WTForms-JSON с дополнительным вложением с использованием FormField

Я использую WTForms-JSON и обрабатываю вложенные формы. Я хотел бы сделать внутреннюю форму необязательной, но если внутренняя форма присутствует, я бы хотел, чтобы ее поля были обязательными. Проблема, с которой я сталкиваюсь, заключается в том, что FormField не принимает валидаторы.

(Хотя я использую WTForms-JSON, я полагаю, что это относится и к обычным WTForms.)

Этот код работает, но не так, как я хочу:

class InnerForm(Form):
    foo_id = IntegerField("Foo ID", [Required()])

class OuterForm(Form):
    inner = FormField(InnerForm)

Проблема с приведенным выше кодом заключается в том, что inner требуется неявно. Как ни странно, хотя validate() возвращает False, когда inner опущено, errors пусто.

Этот код не работает:

class InnerForm(Form):
    foo_id = IntegerField("Foo ID", [Required()])

class OuterForm(Form):
    inner = FormField(InnerForm, "Inner", [Optional()])

Последний выдает эту ошибку:

TypeError: FormField does not accept any validators. Instead, define them on the enclosed form.

Мой вопрос: как сделать inner необязательным, но требовать foo_id, если присутствует inner?


person Jim Stewart    schedule 09.01.2014    source источник


Ответы (3)


Самый простой способ — обернуть FormField в FieldList. , где max_entries установлено в 1. FieldList также поддерживает валидаторы, но поскольку min_entries по умолчанию равно 0, вам они не нужны. Единственное раздражение будет заключаться в том, что вам придется разворачивать данные внутренней формы, если они доступны.

person Sean Vieira    schedule 10.01.2014
comment
+1 за хорошее предложение, но, к сожалению, это изменит API и потребует изменений на стороне клиента или предварительной обработки на стороне сервера, чтобы изменить структуру данных, и ни один из них не является хорошим вариантом для меня. Я мог бы просто исправить WTForms, чтобы FormField() уважал Required() и Optional(). - person Jim Stewart; 10.01.2014
comment
@JimStewart - достаточно честно. Определенно стоит сделать запрос на включение, так как они сейчас работают над WTForms 2.0 :-) - person Sean Vieira; 10.01.2014
comment
Я принимаю это, потому что нет поддержки того, что я хочу, и это хороший обходной путь. Если я когда-нибудь доберусь до исправления WTForms, я обновлю здесь. - person Jim Stewart; 28.01.2014

Спасибо @aryeh за OptionalFormField. Я просто поместил здесь свой немного улучшенный (на мой взгляд) вариант:

class OptionalFormField(FormField):

    def process(self, formdata, *args, **kwargs):
        self._formdata = formdata
        return super(OptionalFormField, self).process(formdata, *args, **kwargs)

    def validate(self, *args, **kwargs):
        if self._formdata:
            for field_name in self._formdata.keys():
                if field_name.startswith(self.name + self.separator):
                    return super(OptionalFormField, self).validate(*args, **kwargs)
        return True
person grubberr    schedule 22.11.2015

Если кто-то придет сюда в поисках решения этой проблемы, вот простое:

from wtforms.fields import FormField, _unset_value

class OptionalFormField(FormField):

    def process(self, formdata, data=_unset_value):
        self._formdata = formdata
        return super(OptionalFormField, self).process(formdata, data=data)

    def validate(self, form, extra_validators=tuple()):
        if extra_validators:
            raise TypeError('FormField does not accept in-line validators, as it gets errors from the enclosed form.')

        # Run normal validation only if there is data for this form
        for field_name in self._formdata.keys():
            if field_name.find(self.name) == 0:
                return self.form.validate()

        return True

Что это делает, так это запускает проверку формы только в том случае, если находит ключи в данных формы, которые относятся к этой форме.

person aryeh    schedule 23.08.2015