【发布时间】:2021-02-27 21:43:12
【问题描述】:
我希望 django rest 在序列化时不要将我的 DateTime 模型字段转换为字符串日期表示。
response_date = serializers.DateTimeField(source="updated_at")
我希望这样出来
1411880508
而不是
“2014-09-28T05:01:48.123”
【问题讨论】:
标签: python django-rest-framework
我希望 django rest 在序列化时不要将我的 DateTime 模型字段转换为字符串日期表示。
response_date = serializers.DateTimeField(source="updated_at")
我希望这样出来
1411880508
而不是
“2014-09-28T05:01:48.123”
【问题讨论】:
标签: python django-rest-framework
你会想写一个custom serializer field,像这样:
class TimestampField(serializers.Field):
def to_native(self, value):
epoch = datetime.datetime(1970,1,1)
return int((value - epoch).total_seconds())
为了支持您希望从 WritableField 继承并实现 from_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)
【讨论】:
to_native 方法现在是to_representation
REST_FRAMEWORK = {
# if you want with milliseconds or
'DATETIME_FORMAT': '%s.%f',
# only with seconds
'DATETIME_FORMAT': '%s',
}
REST 中的结果将是 string
“1517863184.666435”
“1517863249”
如果您想要 API 中的浮点(或整数)值,则可以使用猴子补丁。
将文件monkey_patching.py 放入您的任何apps 并将其导入应用程序的__init__.py 文件中。即:
app/monkey_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
#app/__init__.py
import app.monkey_patching
使用 Django 版本 2.0.10 和 Python 3.5.9 测试
【讨论】:
我无法让 Tom 的示例正常工作,而且这些值似乎没有被修改。然而,它给了我一个起点,经过一番阅读,我找到了一种产生预期结果的方法:
[方法 1]
serializers.py
import time
class TimestampField(serializers.Field):
def to_representation(self, value):
return int(time.mktime(value.timetuple()))
class MySerializer(serializers.ModelSerializer):
ts = TimestampField(source="my_fieldname") #Source must be a models.DateTimeField
class Meta:
model = myModel
fields = ('id', 'ts')
JSON 输出:
[{
"id": 1,
"ts": 1475894303
},
{
"id": 2,
"ts": 1475833070
}]
[方法 2]
Tom 的解释和前面提到的方法肯定更符合维护标准(因为结果实际上是整数类型)。
然而,一个快速而肮脏的解决方案是指定 format parameter for the DateTimeField 并将其设置为以秒为单位显示值。
请注意,这可能无法在 Windows 机器上正常工作! 并可能导致 ValueError: Invalid format string
要试用它,只需在序列化器字段中包含“格式”关键字参数,如下所示:
serializers.py
class MySerializer(serializers.ModelSerializer):
timestamp = serializers.DateTimeField(format="%s")
class Meta:
model = myModel
fields = ('id', 'ts')
JSON 输出:
[{
"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 的问题有点不一致,因为结果实际上不是整数类型,而是整数/浮点数的字符串表示形式 - REST 会在值周围添加引号。
【讨论】:
settings.py中设置全局默认格式,就像REST_FRAMEWORK = { 'DATETIME_FORMAT': '%s.%f'}一样
虽然我更喜欢 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
【讨论】:
全局配置:
REST_FRAMEWORK = {
'DATETIME_FORMAT': '%s.%f',
}
【讨论】:
在 python 中,时间戳是 10 位数字。但是,在 Javascript 中,它是 13 位数字。
因此,如果要在全局配置中返回Javascript格式的时间戳,只需在'%s'后面加上'000'即可:
JS_TIMESTAMP = '%s000'
REST_FRAMEWORK = {
'DATETIME_FORMAT': JS_TIMESTAMP,
'DATE_FORMAT': JS_TIMESTAMP
}
结果将如下所示:1567413479000
【讨论】:
如前所述,您可以通过以下方式为所有日期时间全局设置时间戳格式:
REST_FRAMEWORK = {
'DATETIME_FORMAT': '%s',
}
但这不适用于常规日期,要使其适用于您还必须设置的日期:
REST_FRAMEWORK = {
'DATE_FORMAT': '%s',
}
【讨论】:
感谢@megajoe monkey patch solution。我是在 windows 上开发的,所以得到了无效的格式字符串,因为 windows 不支持任何 "%s" 格式 (http://msdn.microsoft.com/en-us/library/fe06s4ak.aspx)。
所以我使用了像 @megajoe 这样的猴子补丁,并稍微调整了解决方案以返回 value.timestamp() 为 "%s.%f" 和 int(value.timestamp()) 为 "%s"。
【讨论】: