python、mongo 和棉花糖:约会时间的挣扎

python, mongo and marshmallow: datetime struggles

我正在尝试做一些非常简单的事情:获取当前时间,用棉花糖验证我的对象,将它存储在 mongo

python 3.7

要求:

datetime==4.3
marshmallow==3.5.1
pymongo==3.10.1

schema.py

from marshmallow import Schema, fields
...
class MySchema(Schema):
    user_id = fields.Str(required=True)
    user_name = fields.Str()
    date = fields.DateTime()
    account_type = fields.Str()
    object = fields.Raw()

preapredata.py

from datetime import datetime
from schema.py import Myschema
... 
        dt = datetime.now()
        x = dt.isoformat()
        data = {
            "user_id": '123123123',
            "user_name": 'my cool name',
            "date":  x,
            "account_type": 'another sting',
            "trade": {'some':'dict'}
        }
        # validate the schema for storage
        validator = MySchema().load(data)
        if 'errors' in validator:
            log.info('validator.errors')
            log.info(validator.errors)
...
        res = MyService().create(
            data
        )

myservice.py

    def create(self, data):
        log.info("in creating data service")
        log.info(data)

        self.repo.create(data)
        return MySchema().dump(data)

mongo 的连接器很好,正在保存没有日期时间的其他数据没有问题。 在将日期时间传递给日期键之前,我似乎经历了一百种不同的格式化日期时间变体,以及在内联和元 class 中的模式字段中指定 'format' 选项,示例:

    #class Meta:
    #    datetimeformat = '%Y-%m-%dT%H:%M:%S+03:00'

我尝试的大多数变化导致:

{'date': ['Not a valid datetime.']}

我终于设法通过简单地使用

进入的验证
 x = dt.isoformat()

并将字段架构保留为默认值 ( date = fields.DateTime() )

但是当我通过棉花糖倒回去时我得到

AttributeError: 'str' object has no attribute 'isoformat'

记录是在 mongo 数据库中创建的,但字段类型是字符串,理想情况下我想利用本机 mongo 日期字段

如果我尝试通过

 datetime.now()

到目前为止,它失败了

{'date': ['Not a valid datetime.']}

相同
datetime.utcnow()

非常感谢任何指导。


编辑:绕过棉花糖并使用

datetime.now(pytz.utc)

datetime.utcnow() 

字段数据按预期日期存储在 mongo 中,所以我认为这个问题可以更简洁地表述为:我如何让 marshmallow fields.DateTime() 验证这些格式中的任何一种?


编辑 2: 因此,由于 Jérôme 在下面的富有洞察力的回答,我们已经开始重构。 对于任何想要 'twist' 棉花糖表现得像最初提出的问题的人,我们最终选择了:

    date = fields.DateTime(
        #dump_only=True,
        default=lambda: datetime.utcnow(),
        missing=lambda: datetime.utcnow(),
        allow_none=False
    )

即完全跳过传递日期,让 marshmallow 从丢失中生成它,这满足了我们的用例。

marshmallow 的要点是将数据从序列化(例如,JSON、等格式字符串等)加载到实际的 Python 对象(int、datetime、...)中。反过来将它从对象转储到序列化字符串。

Marshmallow 还提供加载验证,并且仅在加载时进行验证。转储时,数据来自应用程序,不需要验证。

在 API 中,在应用程序中使用数据之前加载和验证来自外部世界的数据很有用。并将其序列化回外界。

如果您的数据是序列化形式,当您在日期时间调用 isoformat() 时就是这种情况,那么 marshmallow 可以加载它,您会得到一个 Python 对象,里面有一个真实的日期时间.这就是你应该喂给 pymongo 的东西。

    # load/validate the schema for storage
    try:
        loaded_data = MySchema().load(data)
    except ValidationError as exc:
        log.info('validator.errors')
        log.info(exc.errors)
    ...
    # Store object in database
    res = MyService().create(loaded_data)

自 marshmallow 3 起,始终加载 returns 反序列化内容,您需要 try/catch 验证错误。

如果您的数据不是以反序列化的形式进入您的应用程序(如果它已经是对象形式),那么 marshmallow 可能不是完成这项工作的正确工具,因为它不会对反序列化的对象执行验证(请参阅https://github.com/marshmallow-code/marshmallow/issues/1415).

也许是。您可以使用对象文档映射器 (ODM) 来管理验证和数据库管理。这是其他 pymongo 的额外层。 umongo 是基于棉花糖的 mongoDB ODM。还有其他 ODM:mongoengine、pymodm。

顺便说一句,这是什么

datetime==4.3

你安装了DateTime吗?你不需要这个。

免责声明:marshmallow 和 umongo 维护者发言。