WTForms DateTimeField, возвращающий True, не имеет значения ввода - PullRequest
0 голосов
/ 08 октября 2019

Я изо всех сил пытаюсь понять, почему WTForms всегда проверяет мой ввод, даже если он не соответствует формату ввода по умолчанию, указанному в документации. В документах говорится, что по умолчанию используется формат

class wtforms.fields.DateTimeField(default field arguments, format='%Y-%m-%d %H:%M:%S')

, но мой код всегда возвращает true

from wtforms import Form, validators
from wtforms.fields import DateTimeField

class InputForm(Form):
        timestamp = DateTimeField('TimeStamp', validators=[validators.DataRequired()])

form = InputForm(timestamp='lmao')
form.validate()
# True

Может кто-нибудь объяснить мне это поведение?

1 Ответ

1 голос
/ 10 октября 2019

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

DateTimeField гарантирует, что значение может быть приведено к дате и времени, но только если значение происходит из формы. Как вы можете видеть ниже, передача значения в конструктор формы через kwargs (timestamp='lmao') не проходит через тот же тест.

Если посмотреть на определение DateTimeField, то единственный метод, который имеет пользовательскую обработку для поля, являющегося полем даты и времени, - это метод process_formdata() (также _value(), нокоторый используется виджетами для визуализации полей):

class DateTimeField(Field):
    """
    A text field which stores a `datetime.datetime` matching a format.
    """

    widget = widgets.TextInput()

    def __init__(
        self, label=None, validators=None, format="%Y-%m-%d %H:%M:%S", **kwargs
    ):
        super(DateTimeField, self).__init__(label, validators, **kwargs)
        self.format = format

    def _value(self):
        if self.raw_data:
            return " ".join(self.raw_data)
        else:
            return self.data and self.data.strftime(self.format) or ""

    def process_formdata(self, valuelist):
        if valuelist:
            date_str = " ".join(valuelist)
            try:
                self.data = datetime.datetime.strptime(date_str, self.format)
            except ValueError:
                self.data = None
                raise ValueError(self.gettext("Not a valid datetime value"))

Когда вы создаете экземпляр объекта Form, вызывается метод формы process(), который вызывает метод process() каждого из полей формы ипередает formdata (в данном случае None) и значение для поля, если оно найдено (в данном случае 'lmao').

Как видите, здесь нетprocess() метод, определенный в определении DateTimeField выше, поэтому он вызывает Field.process():

    def process(self, formdata, data=unset_value):
        """
        Process incoming data, calling process_data, process_formdata as needed,
        and run filters.
        If `data` is not provided, process_data will be called on the field's
        default.
        Field subclasses usually won't override this, instead overriding the
        process_formdata and process_data methods. Only override this for
        special advanced processing, such as when a field encapsulates many
        inputs.
        """
        self.process_errors = []
        if data is unset_value:
            try:
                data = self.default()
            except TypeError:
                data = self.default

        self.object_data = data

        try:
            self.process_data(data)
        except ValueError as e:
            self.process_errors.append(e.args[0])

        if formdata is not None:
            if self.name in formdata:
                self.raw_data = formdata.getlist(self.name)
            else:
                self.raw_data = []

            try:
                self.process_formdata(self.raw_data)
            except ValueError as e:
                self.process_errors.append(e.args[0])

        try:
            for filter in self.filters:
                self.data = filter(self.data)
        except ValueError as e:
            self.process_errors.append(e.args[0])

В этом методе параметр data равен 'lmao', а formdata равен None. Вы можете видеть, что вызов process_formdata() защищен условным условием if formdata is not None:, поэтому настраиваемая обработка поля, определенного в DateTimeField, выполняется только для данных, поступающих из формы.

from werkzeug import MultiDict

form = InputForm(formdata=MultiDict([("timestamp", "lmao")]))

print(form.timestamp.raw_data)  # ['lmao']
print(form.timestamp.process_errors)  # ['Not a valid datetime value']
print(form.validate())  # False

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

...