3

我正在使用 Flask 在 python 中制作 REST API。我使用 SQLalchemy 和 Marshmallow 来处理和存储进出 API 的数据。

我有一条用于创建事件的路线。它需要一个日期时间作为 POST 有效负载的信息之一。在模型中,该字段使用 TIMESTAMP 类型。SQLalchemy 的 TIMESTAMP 类型是支持时区的日期时间。

当我在 Linux 上运行 API 时,一切正常,但是当我在 Windows 上运行它时,数据进来了,因为它应该从棉花糖的模式中传递到 load() 方法中,
post_campaign, errors = campaign_schema.load(request.get_json()) 一旦它被加载到模式中,日期时间就丢失了时区数据,这对我来说是个大问题。

我没有在我的模式中做任何特殊操作,它是一种“经典”的模式。

基本上,在我的机器和其他一些机器上,我有

test_campaign (tests.test_setup.Testing) ...
<------------------>
现在 2017-05-05 09:52:39.014386+00:00 使用日期时间生成。 utcnow().replace(tzinfo=pytz.utc)
在模式中加载之前 2018-05-05 08:35:17.361864+00:00
模式中的数据 2018-05-05 08:35:17.361864+00:00
<- ----------------->

在我有的其他机器上

test_campaign (tests.test_setup.Testing) ...
<------------------>
现在 2017-05-05 09:52:39.014386+00:00
在模式加载之前2018-05-05 08:35:17.361864+00:00
架构中的数据 2018-05-05 08:35:17
<----------------->

我的模式(ma 是棉花糖):

class CampaignSchema(ma.ModelSchema):
   class Meta:
   model = Campaign
admingroup_id = field_for(Campaign, 'admingroup_id', dump_only=False)
smtp_id = field_for(Campaign, 'smtp_id', dump_only=False)
mail_template_id = field_for(Campaign, 'mail_template_id', dump_only=False)
landing_page_id = field_for(Campaign, 'landing_page_id', dump_only=False)

campaign_schema = CampaignSchema()
campaigns_schema = CampaignSchema(many=True)

你们中有人知道这种行为吗?

4

1 回答 1

-1

TL;DR
您需要dateutil在您使用的任何机器上安装模块:

pip install python-dateutil

我对棉花糖也有类似的问题Schema

class TestSchema(Schema):
    dt_field = fields.DateTime(required=True)

按原样使用它,我得到了一个不知道时区的datetime对象:

>>> ts = TestSchema()
>>> ts.load({'dt_field': '2018-03-22T16:30:00+02:00'}).data.get('dt_field')
datetime.datetime(2018, 3, 22, 16, 30)

marshmallow有一个utils.py包含各种方法的。
其中一些方法用于将日期时间字符串转换为datetime对象,例如from_iso_datetime()

def from_iso_datetime(datestring, use_dateutil=True):
       """
       Parse an ISO8601-formatted datetime string and return a datetime object.
       Use dateutil's parser if possible and return a timezone-aware datetime.
       """
    if not _iso8601_re.match(datestring):
        raise ValueError('Not a valid ISO8601-formatted datetime string')
    # Use dateutil's parser if possible
    if dateutil_available and use_dateutil:
        return parser.parse(datestring)
    else:
        # Strip off timezone info.
        return datetime.datetime.strptime(datestring[:19], '%Y-%m-%dT%H:%M:%S')

从这段代码片段中,我们可以看到该方法检查是否dateutils可用,如果不可用,它会删除时区信息。

当我安装dateutils(从而使其“可用” marshmallow)时,上面的示例按预期工作:

>>> ts.load({'dt_field': '2018-03-22T16:30:00+02:00'}).data.get('dt_field')
datetime.datetime(2018, 3, 22, 16, 30, tzinfo=tzoffset(None, 7200))
于 2018-03-22T14:40:40.890 回答