问题
I would like for django rest to not convert my DateTime model field into a string date represtation when serializing it.
response_date = serializers.DateTimeField(source="updated_at")
I would like this to come out as
1411880508
and not
"2014-09-28T05:01:48.123"
回答1:
You'll want to write a custom serializer field, like so:
class TimestampField(serializers.Field):
def to_native(self, value):
epoch = datetime.datetime(1970,1,1)
return int((value - epoch).total_seconds())
To support write operations you'd want to inherit from WritableField
and also implement from_native()
.
EDIT for DRF 3.x & Python 3.8:
class TimestampField(serializers.Field):
def to_representation(self, value):
return value.timestamp()
If you want a JavaScript style timestamp:
class JsTimestampField(serializers.Field):
def to_representation(self, value):
return round(value.timestamp()*1000)
回答2:
REST_FRAMEWORK = {
# if you want with milliseconds or
'DATETIME_FORMAT': '%s.%f',
# only with seconds
'DATETIME_FORMAT': '%s',
}
Result in REST will be string
"1517863184.666435"
"1517863249"
If you want float(or integer) value in API, than you can use monkey patching.
Put the file monkey_patching.py
in any of your apps
and import it in app's __init__.py
file. ie:
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
Tested with Django version 2.0.10 and Python 3.5.9
回答3:
I was not able to get Tom's example to work and it seemed the values were not being modified. However it gave me a starting point and after some reading I found a way to produce the desired result:
[METHOD 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 output:
[{
"id": 1,
"ts": 1475894303
},
{
"id": 2,
"ts": 1475833070
}]
[METHOD 2]
Tom's explanation and the previous mentioned method are definitely more on track with maintaining standards (as the results are actually of type integer).
However a quick and dirty solution is to specify the format parameter for the DateTimeField and set it to show the value in seconds.
Note this probably won't work correctly on Windows machines! And may result in a ValueError: Invalid format string
To try it out just include the "format" keyword parameter in your serializer field like so:
serializers.py
class MySerializer(serializers.ModelSerializer):
timestamp = serializers.DateTimeField(format="%s")
class Meta:
model = myModel
fields = ('id', 'ts')
JSON output:
[{
"id": 1,
"ts": "1475890361"
},
{
"id": 2,
"ts": "1475833070"
}]
Additionally you may include microseconds:
timestamp = serializers.DateTimeField(format="%s.%f")
If you want to test the functionality in your own interpreter (to verify your OS supports the %s parameter) just copy over these lines:
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
I feel this method is a little inconsistent with the OPs question because the result is not actually of type integer, instead it is a string representation of an integer/float - and REST will surly add quotes around the value.
回答4:
Although I prefer the answer given by Tom Christie as it is more robust. I decided to post my solution for the benefit of the potential readers
response_date = serializers.SerializerMethodField('get_timestamp')
def get_timestamp(self, obj):
#times 1000 for javascript.
return time.mktime(obj.updated_at.timetuple()) * 1000
回答5:
Global Configuration:
REST_FRAMEWORK = {
'DATETIME_FORMAT': '%s.%f',
}
回答6:
In python, the timestamp is 10 digit. However, in Javascript, it is 13 digit.
Therefore, if you want to return Javascript format timestamp in global configure, just add '000' after '%s':
JS_TIMESTAMP = '%s000'
REST_FRAMEWORK = {
'DATETIME_FORMAT': JS_TIMESTAMP,
'DATE_FORMAT': JS_TIMESTAMP
}
The result will looks like this: 1567413479000
回答7:
As mentioned before you can set timestamp format for all datetimes globally by:
REST_FRAMEWORK = {
'DATETIME_FORMAT': '%s',
}
But this doesnt work for regular dates, to make it work for dates you also have to set:
REST_FRAMEWORK = {
'DATE_FORMAT': '%s',
}
来源:https://stackoverflow.com/questions/26083583/serialize-a-datetime-as-an-integer-timestamp