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 维护者发言。
我正在尝试做一些非常简单的事情:获取当前时间,用棉花糖验证我的对象,将它存储在 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 维护者发言。