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

标签 python django django-rest-framework

我有一个包含以下内容的 Django REST Framework 序列化程序:

from rest_framework import serializers


class 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

这是有问题的,因为如果日期时间格式发生变化,它将与所有其他 datetime 不同。我想重用 DRF 用来序列化其他 datetime 字段的代码路径。

到目前为止我尝试了什么:

  • 唯一answer看起来相关的结果实际上并没有产生与 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 被声明为 django.db.DateTimeField,但是如果我尝试像 LogEntry.timestamp.to_representation(log_entry. timestamp) 它严重失败:

    AttributeError: 'DeferredAttribute' object has no attribute 'to_representation'

最佳答案

查看 DRF 的源代码,rest_framework/fields.py 中发生了一些有趣的事情。

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

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


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

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

或者,继续做您正在做的事情,但显式传递来自 DRF 的 api_settings.DATETIME_FORMAT 的格式字符串。这可能感觉不那么神奇,但老实说,它可能更容易受到 future 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,它有 following code其中:

value = value.isoformat()
if value.endswith('+00:00'):
    value = value[:-6] + 'Z'
    return value

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

isoformat 如果值是否有微秒,格式会有所不同

来自Python docs , isoformat 将:

Return a string representing the date and time in ISO 8601 format, YYYY-MM-DDTHH:MM:SS.ffffff or, if microsecond is 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)
    )

关于python - 如何在 Django REST Framework 中使用默认的日期时间序列化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54699507/

相关文章:

python - 如何在 View 中更改 Django 数据库架构?

python - 序列化 MD5 计算状态并稍后恢复?

Python 错误 : AttributeError: __enter__

python - 类型错误 : 'Question' object is not iterable in test case assertion

python - 有什么办法可以对本地 Appengine 开发服务器实现 30 秒限制?

python - Django 休息框架 : How do I order/sort a search/filter query?

python - html 输出中的整数(jupyter notebook)

python - 避免全局变量但也避免太多函数参数(Python)

python - Django:select_related 与多表继承

python-3.x - Django Rest 框架如何创建家庭并为该家庭分配成员,同时为每个成员分配角色