Обеспечить строгие поля. Формат даты с десериализацией Зефир - PullRequest
0 голосов
/ 08 октября 2018

Я использую Marshmallow 2.15.3 для проекта Flask и хочу использовать строгие форматы Date и DateTime.Под строгим подразумевается, что я хочу принимать только строки, идентичные форматам ниже.То, что я испытываю, это некоторая разница в обработке Date и DateTime.Форматы:

DATE_FORMAT = '%Y-%m-%d'
DATETIME_FORMAT = '%Y-%m-%dT%H:%M:%S'

Например, с DateTime я могу сделать следующее:

dt = fields.DateTime(format=DATETIME_FORMAT)
dt.deserialize('2018-01-01')  # fails, as desired
dt.deserialize('2018-01-01T05:06:08.012312+02:00')  # fails, as desired
dt.deserialize('2018-01-01T05:06:08')  # works, as desired and according to format

С датой я могу сделать следующее:

d = fields.Date() # does not accept format argument
d.deserialize('2018-01')  # fails, as desired
d.deserialize('2018-01-01T05:06:08.012312+02:00')  # works, NOT as desired
d.deserialize('2018-01-01')  # works, as desired and according to format

ПокаDateTime не разрешает дополнительную информацию, Date разрешает это.Из моего понимания нет аргумента format для поля Дата.Можно ли как-то обойти это для аналогичной функциональности и применения моего строгого формата как для слишком коротких, так и для слишком длинных входных значений?

1 Ответ

0 голосов
/ 11 октября 2018

Для будущего кода я обнаружил, что класс Date в Marshmallow 3.0.0b17 теперь является подклассом DateTime вместо Field, что делает его наследующим format kwarg ( релевантный коммит ).

Для версий 2.15.3 и (в целом 2.XX) я не могу найти встроенную функцию для этого.Обходной путь - обезьянить патч класса fields.Date.С модификациями это выглядит так:

class Date(Field):
    """ISO8601-formatted date string.

    :param kwargs: The same keyword arguments that :class:`Field` receives.
    """
    default_error_messages = {
        'invalid': 'Not a valid date.',
        'format': '"{input}" cannot be formatted as a date.',
    }

    def __init__(self, format=None, **kwargs):
        super(Date, self).__init__(**kwargs)
        self.dateformat = format

    def _serialize(self, value, attr, obj):
        if value is None:
            return None
        try:
            return value.isoformat()
        except AttributeError:
            self.fail('format', input=value)
        return value

    def _deserialize(self, value, attr, data):
        """Deserialize an ISO8601-formatted date string to a
        :class:`datetime.date` object.
        """
        if not value:  # falsy values are invalid
            self.fail('invalid')
        elif self.dateformat:
            try:
                return dt.datetime.strptime(value, self.dateformat).date()
            except (TypeError, AttributeError, ValueError):
                raise self.fail('invalid')
        try:
            return utils.from_iso_date(value)
        except (AttributeError, TypeError, ValueError):
            self.fail('invalid')

Модификации здесь - это добавление определения __init__, и под _deserialize добавлена ​​вся elif self.dateformat -пункт.Это позволяет мне десериализовать, используя представленный формат, например:

d = fields.Date('%Y-%m-%d') # now accepts a format
d.deserialize('2018-01-01T05:06:08.012312+02:00')  # fails, as desired
...