Python 将日期时间序列化为整数时间戳

Python 将日期时间序列化为整数时间戳,python,django-rest-framework,Python,Django Rest Framework,我希望django rest在序列化时不要将DateTime模型字段转换为字符串日期表示形式 response_date = serializers.DateTimeField(source="updated_at") 我希望这个能作为 1411880508 而不是 “2014-09-28T05:01:48.123” 你会想写一个,像这样: class TimestampField(serializers.Field): def to_native(self, value):

我希望django rest在序列化时不要将DateTime模型字段转换为字符串日期表示形式

response_date = serializers.DateTimeField(source="updated_at")
我希望这个能作为

1411880508

而不是

“2014-09-28T05:01:48.123”

你会想写一个,像这样:

class TimestampField(serializers.Field):
    def to_native(self, value):
        epoch = datetime.datetime(1970,1,1)
        return int((value - epoch).total_seconds())
要支持写操作,您需要从
WritableField
继承,并从\u native()实现

针对DRF 3.x和Python 3.8进行编辑:

class TimestampField(serializers.Field):
    def to_representation(self, value):
        return value.timestamp()
如果需要JavaScript样式的时间戳:

class JsTimestampField(serializers.Field):
    def to_representation(self, value):
        return round(value.timestamp()*1000)

虽然我更喜欢Tom Christie给出的答案,因为它更可靠。 为了潜在读者的利益,我决定发布我的解决方案

response_date = serializers.SerializerMethodField('get_timestamp')
def get_timestamp(self, obj):
    #times 1000 for javascript.
    return time.mktime(obj.updated_at.timetuple()) * 1000

我无法让Tom的例子起作用,而且这些值似乎没有被修改。然而,它给了我一个起点,在阅读之后,我找到了一种产生期望结果的方法:

[方法1]

序列化程序.py

JSON输出:

[{
    "id": 1,
    "ts": 1475894303
},
{
    "id": 2,
    "ts": 1475833070 
}]
[{
    "id": 1,
    "ts": "1475890361"
},
{
    "id": 2,
    "ts": "1475833070"
}]
[方法2]

Tom的解释和前面提到的方法肯定更符合标准(因为结果实际上是integer类型)

但是,一个快速而肮脏的解决方案是指定并将其设置为以秒为单位显示值

注意,这可能无法在Windows计算机上正常工作 并可能导致ValueError:无效的格式字符串

要进行尝试,只需在序列化程序字段中包含“format”关键字参数,如下所示:

序列化程序.py

JSON输出:

[{
    "id": 1,
    "ts": 1475894303
},
{
    "id": 2,
    "ts": 1475833070 
}]
[{
    "id": 1,
    "ts": "1475890361"
},
{
    "id": 2,
    "ts": "1475833070"
}]
此外,还可以包括微秒:

timestamp = serializers.DateTimeField(format="%s.%f")
如果要在您自己的解释器中测试功能(验证您的操作系统是否支持%s参数),只需复制以下行:

import datetime
print datetime.datetime.now().strftime('%s') #datetime formatted as seconds for REST

import time  #This is just for confirmation
print time.mktime(datetime.datetime.now().timetuple()) #time object result as float
我觉得这个方法与OPs问题有点不一致,因为结果实际上不是integer类型,而是integer/float的字符串表示形式,REST肯定会在值周围加引号。

全局配置:

REST_FRAMEWORK = {
    'DATETIME_FORMAT': '%s.%f',
}
REST中的结果将是字符串

  • “1517863184.666435”

  • “1517863249”

  • 如果希望API中的浮点(或整数)值,则可以使用monkey patching

    将文件
    monkey\u patching.py
    放入任何
    应用程序中,并将其导入应用程序的
    \uuuu init\uuuuu.py
    文件中。即:

    app/monkey\u patching.py

    #app/monkey_patching.py
    import six
    from rest_framework import ISO_8601
    from rest_framework.fields import DateTimeField
    from rest_framework.settings import api_settings
    
    
    def to_representation_ext(self, value):
        if not value:
            return None
    
        output_format = getattr(self, 'format', api_settings.DATETIME_FORMAT)
    
        if output_format is None or isinstance(value, six.string_types):
            return value
    
        if output_format.lower() == ISO_8601:
            value = self.enforce_timezone(value)
            value = value.isoformat()
            if value.endswith('+00:00'):
                value = value[:-6] + 'Z'
            return value
        
        # FOR INTEGER RESULT 'DATETIME_FORMAT': '%s',
        # return int(value.strftime(output_format))
    
        # FOR FLOAT RESULT 'DATETIME_FORMAT': '%s.%f',
        return float(value.strftime(output_format))
    
    
    DateTimeField.to_representation = to_representation_ext
    
    #app/__init__.py
    import app.monkey_patching
    
    app/init.py

    #app/monkey_patching.py
    import six
    from rest_framework import ISO_8601
    from rest_framework.fields import DateTimeField
    from rest_framework.settings import api_settings
    
    
    def to_representation_ext(self, value):
        if not value:
            return None
    
        output_format = getattr(self, 'format', api_settings.DATETIME_FORMAT)
    
        if output_format is None or isinstance(value, six.string_types):
            return value
    
        if output_format.lower() == ISO_8601:
            value = self.enforce_timezone(value)
            value = value.isoformat()
            if value.endswith('+00:00'):
                value = value[:-6] + 'Z'
            return value
        
        # FOR INTEGER RESULT 'DATETIME_FORMAT': '%s',
        # return int(value.strftime(output_format))
    
        # FOR FLOAT RESULT 'DATETIME_FORMAT': '%s.%f',
        return float(value.strftime(output_format))
    
    
    DateTimeField.to_representation = to_representation_ext
    
    #app/__init__.py
    import app.monkey_patching
    

    使用Django版本2.0.10和Python 3.5.9测试,如前所述,您可以通过以下方式全局设置所有日期时间的时间戳格式:

    REST_FRAMEWORK = {
        'DATETIME_FORMAT': '%s',
    }
    
    但这不适用于常规日期,要使其适用于日期,还必须设置:

    REST_FRAMEWORK = {
        'DATE_FORMAT': '%s',
    }
    

    在python中,时间戳是10位数字。然而,在Javascript中,它是13位数字

    因此,如果要在全局配置中返回Javascript格式时间戳,只需在“%s”之后添加“000”:

    JS_TIMESTAMP = '%s000'
    
    REST_FRAMEWORK = {
        'DATETIME_FORMAT': JS_TIMESTAMP,
        'DATE_FORMAT': JS_TIMESTAMP
    }
    
    结果如下:1567413479000

    感谢您的帮助。我是在windows上开发的,因此获取的格式字符串无效,因为windows不支持任何“%s”格式()


    因此,我使用了monkey patch-like并稍微调整了解决方案,以返回“%s.%f”的
    value.timestamp()
    ,以及“%s”的
    int(value.timestamp())

    AFAIK日期时间作为一个数字存储在数据库中。我希望得到这个数字,而不是遍历queryset中的所有记录。我担心这和我自己的方法都会对性能产生影响。如果你得到这个答案并使用DRF 3.x,那么
    to_native
    方法现在是
    to_representation
    这个答案很棒!此外,它可以被格式化为浮点吗?我不相信,这也会给我的FilterSet参数带来一些问题,但事实并非如此int@MohammadTorkashvand添加了int和float的信息results@YanQiDong添加了int和float结果的信息这应该是可接受的答案。format=“%s”更干净!