Flask-WTF SelectMultipleField заполняет идентификаторы базы данных вместо имен

Я хотел бы предисловие к этому, сказав, что английский не является моим родным языком, если какое-либо из моих объяснений расплывчато или не имеет смысла, пожалуйста, дайте мне знать, и я попытаюсь сделать их более ясными.

У меня проблема с заселением a SelectMultipleFieldс правильными данными в Flask-WTF. Как видно из приведенного ниже кода, я передаю объект пользователя форме. Это работает безупречно, поскольку оно заполняет все поля, когда страница отображается. Проблема, с которой я сталкиваюсь, заключается в том, что в ней SelectMultipleFieldзаполняются идентификаторы ролей, а не имена ролей.

В разделе форм я создаю список, в choicesкотором хранятся все доступные варианты, которые должны отображаться. Я могу инвертировать это, choices.append((role.id, role.name))и он заполнит поле именами вместо идентификаторов. Однако, если я это сделаю, роли, назначенные объекту пользователя (из базы данных), не будут отображаться как предварительно выбранные.

Как я могу сделать это так, чтобы поле было предварительно заполнено именами, а не идентификаторами, и сохранить выбранные роли предварительно выбранными?

Любое руководство или подталкивание в правильном направлении будет с благодарностью оценено. Если какой-либо информации не хватает, что я не думал добавить, пожалуйста, дайте мне знать, и я добавлю.

# Models
class Role(db.Document, RoleMixin):
    meta = {'collection': 'role'} 
    name = db.StringField(max_length=80, unique=True)
    description = db.StringField(max_length=255)

    def __repr__(self):
        return '<Role {}>'.format(self.name)

    def __str__(self):
        return self.name

class User(db.Document, UserMixin):
    meta = {'collection': 'User'}   
    first_name = db.StringField(max_length=30)
    last_name = db.StringField(max_length=30)
    email = db.StringField(max_length=120)
    password_hash = db.StringField(max_length=255)
    active = db.BooleanField(default=True)
    roles = db.ListField(db.ReferenceField(Role), default=[])

    def __repr__(self):
        return '<User {}>'.format(self.email)

    def __str__(self):
        return self.email

# Forms
class EditUserForm(FlaskForm):
    choices = []
    for role in Role.objects:
        choices.append((role.name, role.id))

    first_name = StringField('First name', validators=[DataRequired()])
    last_name = StringField('Last name', validators=[DataRequired()])
    email = StringField('Email', validators=[DataRequired(), Email()])
    password = PasswordField('Password')
    password2 = PasswordField('Repeat password', validators=[EqualTo('password')])
    roles = SelectMultipleField('User roles', choices=choices)
    submit = SubmitField('Save')

# Routes
@app.route('/users/edit/<id>', methods=['GET', 'POST'])
@roles_required('admin')
def edit_user(id):
    user = User.objects(id=id).first()
    form = EditUserForm(obj=user)

    if form.validate_on_submit() and request.method == 'POST':
        user.first_name=form.first_name.data
        user.last_name=form.last_name.data
        user.email=form.email.data
        user.roles = []

        for role in form.roles.data:
            r = Role.objects(name=role).first()
            user.set_role(r.id)

        if form.password.data:
            user.set_password(form.password.data)

        user.save()
        return redirect(url_for('users'))

    return render_template('edit_user.html', title='Edit user', user=user, form=form)

Шаблон:

{% extends "layout.html" %}
{% set active_page = "edit_user" %}
{% block jumbotron %}

    <h1>{{ title }}</h1>
    <form action="" method="post">
        {{ form.hidden_tag() }}
        <p>
            {{ form.first_name.label }}<br>
            {{ form.first_name(size=32) }}<br>
            {% for error in form.first_name.errors %}
            <span style="color: red;">[{{ error }}]</span>
            {% endfor %}
        </p>
        <p>
            {{ form.last_name.label }}<br>
            {{ form.last_name(size=32) }}<br>
            {% for error in form.last_name.errors %}
            <span style="color: red;">[{{ error }}]</span>
            {% endfor %}
        </p>
        <p>
            {{ form.email.label }}<br>
            {{ form.email(size=32) }}<br>
            {% for error in form.email.errors %}
            <span style="color: red;">[{{ error }}]</span>
            {% endfor %}
        </p>
        <p>
            {{ form.password.label }}<br>
            {{ form.password(size=32) }}<br>
            {% for error in form.password.errors %}
            <span style="color: red;">[{{ error }}]</span>
            {% endfor %}
        </p>
        <p>
            {{ form.password2.label }}<br>
            {{ form.password2(size=32) }}<br>
            {% for error in form.password2.errors %}
            <span style="color: red;">[{{ error }}]</span>
            {% endfor %}
        </p>
        <p>
            {{ form.roles.label }}<br>
            {{ form.roles(size=32) }}<br>
            {% for error in form.roles.errors %}
            <span style="color: red;">[{{ error }}]</span>
            {% endfor %}
        </p>
        <p>{{ form.submit() }}</p>
    </form>

{% endblock %}

Я попытался создать свой собственный объект с кодом ниже, чтобы перейти к форме, однако я не увенчался успехом. При передаче этого объекта в форму поля не заполнялись.

user = User.objects(id=id).first()
temps = []

u = user.to_mongo()
u['_id'] = {'$oid': str(u['_id'])}
temp_roles = []
for role in user.roles:
    r = role.to_mongo()
    r['_id'] = {'$oid': str(r['_id'])}
    temp_roles.append(r)

u['roles'] = temp_roles

python,flask,flask-wtforms,flask-mongoengine,

1

Ответов: 1


2 принят

Я думаю, что PRMoureu прав.

Ты мог choices.append((role.name, role.name))

FYI.

Выбор SelectField - это список пар кортежей (значение, метка) , перейдите по этой ссылке для получения более подробной информации.

В выбранных полях сохраняется свойство выбора, которое представляет собой последовательность пар (значение, метка) . Часть значения может быть любым типом в теории, но поскольку данные формы отправляются браузером в виде строк, вам необходимо предоставить функцию, которая может принудить представление строки обратно к сопоставимому объекту.

По умолчанию coerce является unicode , int, если вы используете (id, name).

питон, колба, колба-wtforms, колба-mongoengine,
Похожие вопросы