代码之家  ›  专栏  ›  技术社区  ›  l0b0

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

  •  1
  • l0b0  · 技术社区  · 5 年前

    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格式发生更改,它将与所有其他格式不同 datetime 美国。我想 重用DRF用于序列化其他文件的代码路径 领域。

    到目前为止,我所尝试的:

    • 唯一的 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”对象没有属性“to\u表示”

    0 回复  |  直到 5 年前
        1
  •  6
  •   kibibu laffuste    5 年前

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

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


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

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

    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)
    

    然而,考虑到您尝试了第一次,但失败了,我们需要更深入地了解!

    ISO_8601 following code 其中:

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

    也就是说,它实际上只是依靠python isoformat

    等格式 如果该值是否有微秒

    Python docs 等格式

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

    在这种情况下,解决方案是显式地将微秒设置为

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

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

    representation: str = serializers.DateTimeField().to_representation(
            logentry.replace(microsecond=0)
        )