Flask WTForms dynamici c выберите значение проверки поля пусто на POST - PullRequest
0 голосов
/ 03 апреля 2020

У меня проблемы с проверкой динамически генерируемого WTForms SelectField. Каким-то образом мой self.choices пуст во время POST, пока они заполняются при первом запросе GET. Я что-то упустил?

app.py:

    @app.route('/users/edit/<email>/', methods=['GET', 'POST'])
    def users_edit(email):

        match = False
        for user in session['users']['message']:
            if user['email']['S'] == email:
                match = True

        if match:
            form = EditUserForm()
            if request.method == 'GET':
                form_data = session.get('edit_user_form_data', None)
                if form_data:
                    form = EditUserForm(MultiDict(form_data))
                    form.shops_allowed.choices = [(str(shop['shop_id']['S']), str(shop['general']['M']['shop_name']['S'])) for i, shop in enumerate(session['shops']['message'])]

                    print(f"SHOPS_ALLOWED CHOICES WITH FORM DATA: {form.shops_allowed.choices}")

                    form.validate()

                    session.pop('edit_user_form_data', None)
                else:
                    form.email.data = email
                    form.shops_allowed.choices = [(str(shop['shop_id']['S']), str(shop['general']['M']['shop_name']['S'])) for i, shop in enumerate(session['shops']['message'])]

                    print(f"SHOPS_ALLOWED CHOICES WITHOUT FORM DATA: {form.shops_allowed.choices}")
                    matched_shop = []
                    for user in session['users']['message']:
                        if user['email']['S'] == email and 'shops_allowed' in user.keys():
                            matched_shop = [allow['S'] for allow, shop in zip(user['shops_allowed']['L'], session['shops']['message'])]

                    form.shops_allowed.data = matched_shop
                    form.validate()

            if request.method == 'POST' and form.validate_on_submit():
                app.logger.info(f"PRE POST EDIT USER FORM DATA: {form.data}")

                url = ...

                <REDACTED POST REQUESTS ENDPOINT>

                app.logger.info(f"POST EDIT USER RESPONSE: ({post_response.status_code}) {response_data}")

                if post_response.status_code == 200:
                    session.pop('edit_user_form_data', None)
                    return redirect(url_for('users'))
                else:
                    app.logger.info(f"EDIT USER FORM DATA: {form.data}")
                    session['edit_user_form_data'] = form.data
                    return redirect(url_for('users_edit', email=email))
            elif request.method == 'POST' and form.validate_on_submit() == False:
                app.logger.info(f"EDIT USER FORM DATA VALIDATION FAILED: {form.data}")
                session['edit_user_form_data'] = form.data
                return redirect(url_for('users_edit', email=email))

forms.py

class NonValidatingSelectMultipleField(SelectMultipleField):
    def __len__(self):
        return 1

    def pre_validate(self, form):
        pass
        # HACK TO VALID A CHOICE FOR SELECT MULTIPLE
        if self.data:
            print(f"SELF DATA: {self.data}")
            print(f"VALUES: {self.choices}")
            values = list(self.coerce(c[0]) for c in self.choices)
            print(f"PROCESSED VALUES: {values}")
            for d in self.data:
                if d not in values:
                    raise ValueError(self.gettext("'%(value)s' is not a valid choice for this multiple select field") % dict(value=d))


class EditUserForm(FlaskForm):
    email = StringField('Email', [
        validators.DataRequired(),
        validators.Length(min=6),
        validators.Email(message='Not a valid email address.')]
    )
    shops_allowed = NonValidatingSelectMultipleField(
        'Shops',
        widget = widgets.ListWidget(prefix_label=False),
        option_widget = widgets.CheckboxInput(),
        coerce=str
    )

Это делает следующую запись в лог:

SHOPS_ALLOWED CHOICES WITHOUT FORM DATA: [('decb5a00-fe45-484f-b887-b9bd41c4f0f2', 'My shop'), ('2cea2efa-7ccf-4bca-896d-16119d5fb7a8', 'My other shop')]
SELF DATA: ['decb5a00-fe45-484f-b887-b9bd41c4f0f2', '2cea2efa-7ccf-4bca-896d-16119d5fb7a8']
VALUES: [('decb5a00-fe45-484f-b887-b9bd41c4f0f2', 'My shop'), ('2cea2efa-7ccf-4bca-896d-16119d5fb7a8', 'My other shop')]
PROCESSED VALUES: ['decb5a00-fe45-484f-b887-b9bd41c4f0f2', '2cea2efa-7ccf-4bca-896d-16119d5fb7a8']
127.0.0.1 - - [03/Apr/2020 14:30:11] "GET /users/edit/my@email.com/ HTTP/1.1" 200 -

После POST:

SELF DATA: ['decb5a00-fe45-484f-b887-b9bd41c4f0f2', '2cea2efa-7ccf-4bca-896d-16119d5fb7a8']
VALUES: None

И на экране:

forms.py", line 35, in pre_validate values = list(self.coerce(c[0]) for c in self.choices) TypeError: 'NoneType' object is not iterable

1 Ответ

0 голосов
/ 03 апреля 2020

Мех, после просмотра моего кода я наконец нашел проблему. Я звоню form.validate_on_submit(), в то же время я проверяю if request.method == 'POST', что никогда не дает мне возможности заполнить варианты во время POST.

Изменил мой код на:

            if request.method == 'POST':

                form.shops_allowed.choices = [(str(shop['shop_id']['S']), str(shop['general']['M']['shop_name']['S'])) for i, shop in enumerate(session['shops']['message'])]
                form.validate_on_submit()

И это начало работать. Иногда вам просто нужно записать вещи, чтобы увидеть ответ: -)

...