为了账号安全,请及时绑定邮箱和手机立即绑定

如何在 Django REST Framework 中使用默认日期时间序列化?

如何在 Django REST Framework 中使用默认日期时间序列化?

鸿蒙传说 2021-11-09 15:42:50
我有一个包含以下内容的 Django REST Framework 序列化程序:from rest_framework import serializersclass ThingSerializer(serializers.ModelSerializer):    last_changed = serializers.SerializerMethodField(read_only=True)    def get_last_changed(self, instance: Thing) -> str:        log_entry = LogEntry.objects.get_for_object(instance).latest()        representation: str = serializers.DateTimeField('%Y-%m-%dT%H:%M:%SZ').to_representation(log_entry.timestamp)        return representation这是有问题的,因为如果日期时间格式发生变化,它将与所有其他datetimes 不同。我想重用 DRF 用于序列化其他datetime字段的代码路径。到目前为止我尝试过的:唯一看起来相关的答案实际上并没有产生与 DRF 相同的结果(它包括毫秒,而 DRF 没有),大概是因为它使用的是 Django 而不是 DRF 序列化器。rest_framework.serializers.DateTimeField().to_representation(log_entry.timestamp),rest_framework.fields.DateTimeField().to_representation(log_entry.timestamp)并rest_framework.fields.DateTimeField(format=api_settings.DATETIME_FORMAT).to_representation(log_entry.timestamp)没有任何工作; 它们以微秒精度生成字符串。我已经用调试器验证了 DRF 在序列化其他字段时调用后者,所以我不明白为什么它会在我的情况下产生不同的结果。LogEntry.timestamp被声明为 a django.db.DateTimeField,但如果我尝试类似的事情,LogEntry.timestamp.to_representation(log_entry.timestamp)它会失败:AttributeError: 'DeferredAttribute' 对象没有属性 'to_representation'
查看完整描述

1 回答

?
狐的传说

TA贡献1804条经验 获得超3个赞

查看 DRF 的来源,有趣的事情发生在rest_framework/fields.py.


特别是,所有格式化的东西都直接在DateTimeField.to_representation方法中发生。


您有几种复制 DRF 行为的方法。


首先,您根本无法传递格式。如果您未明确提供格式,DRF 应使用其默认值。


representation: str = serializers.DateTimeField().to_representation(log_entry.timestamp)

或者,继续做你正在做的事情,但从 DRF 的api_settings.DATETIME_FORMAT. 这可能感觉不那么神奇,但老实说,未来的 API 更改可能会更加脆弱。


这可能看起来像:


from rest_framework.settings import api_settings

...

representation: str = serializers.DateTimeField(api_settings.DATETIME_FORMAT).to_representation(log_entry.timestamp)

但是,鉴于您尝试了第一个并且失败了,我们需要更深入地研究!


DRF 的默认 DateFormat 是ISO_8601,其中包含以下代码:


value = value.isoformat()

if value.endswith('+00:00'):

    value = value[:-6] + 'Z'

    return value

也就是说,它实际上只是依赖于 pythonisoformat函数。


isoformat如果该值有微秒,则格式会有所不同。


从Python 文档中,isoformat将:


以 ISO 8601 格式返回表示日期和时间的字符串,YYYY-MM-DDTHH:MM:SS.ffffff 或者,如果微秒为 0,则 YYYY-MM-DDTHH:MM:SS


在这种情况下,解决方案是将时间戳中的微秒显式设置为零。有几种方法可以做到这一点,但我们可以切换到 Unix 时间戳,剪辑到秒,然后再回来


ts = int(log_entry.timestamp)

representation: str = serializers.DateTimeField().to_representation(ts)

或者继续直接使用 DateTime 对象,这将有更好的时区处理:


representation: str = serializers.DateTimeField().to_representation(

        logentry.replace(microsecond=0)

    )


查看完整回答
反对 回复 2021-11-09
  • 1 回答
  • 0 关注
  • 321 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号