Reputation: 862
I need to take a form that has a field "starttime" that is in EPOCH and convert it to
when I have:
class Snippet(models.Model):
created = models.DateTimeField(auto_now_add=True
class Meta:
ordering = ('created',)
import time
class SnippetSerializer(serializers.ModelSerializer):
starttime = serializers.SerializerMethodField('epoch')
def epoch(self, obj):
""" Return epoch time for a datetime object or ``None``"""
try:
return int(time.mktime(obj.created.timetuple()))
except (AttributeError, TypeError):
return None
class Meta:
model = Snippet
fields = ('starttime')
If I:
"GET" /snippets/1/
{"id":1, 'starttime':13232111}
I want to be able to do:
"POST" /snippets/1/ {"id":1, 'starttime':1}
{"id":1, 'starttime':1}
right now, it just ignores the request. I am forced to use unix epoch times to conform to existing API's.
Upvotes: 6
Views: 5820
Reputation: 323
Please see below code it will help you to solve your problem.
class UnixEpochDateField(serializers.DateField):
def to_representation(self, value):
return int(time.mktime(value.timetuple()))
Upvotes: 0
Reputation: 181
Adapting Kevin Stone code for Django Rest Framework 3:
class UnixEpochDateField(serializers.DateTimeField):
def to_representation(self, value):
""" Return epoch time for a datetime object or ``None``"""
import time
try:
return int(time.mktime(value.timetuple()))
except (AttributeError, TypeError):
return None
def to_internal_value(self, value):
import datetime
return datetime.datetime.fromtimestamp(int(value))
Upvotes: 18
Reputation: 381
Based on Kevin Stone's answer, I've created timezone aware serializer fields, including a UnixEpochDateField
. The actual conversion methods are static because I've found them useful elsewhere in my code.
class UnixEpochDateTimeField(DateTimeField):
def to_native(self, value):
"""
to_native method is responsible for turning the
Python object into a simple, serializable value.
Here: return epoch time for a datetime object or `None`
"""
return self.datetime_to_epoch(value)
def from_native(self, value):
return self.epoch_to_datetime(value)
@staticmethod
def datetime_to_epoch(value):
try:
return int(calendar.timegm(value.utctimetuple()))
except (AttributeError, TypeError):
return None
@staticmethod
def epoch_to_datetime(value):
try:
return datetime.datetime.utcfromtimestamp(int(value)).replace(tzinfo=utc)
except (ValueError, TypeError):
raise ValidationError('%s is not a valid value' % value)
class UnixEpochDateField(DateField):
def to_native(self, value):
return self.date_to_epoch(value)
def from_native(self, value):
return self.epoch_to_date(value)
@staticmethod
def date_to_epoch(value):
try:
return int(calendar.timegm(value.timetuple()))
except (AttributeError, TypeError):
return None
@staticmethod
def epoch_to_date(value):
try:
return datetime.date.fromtimestamp(int(value))
except (ValueError, TypeError):
raise ValidationError('%s is not a valid value' % value)
Upvotes: 1
Reputation: 8981
You want to write your own serializer Field sub-class with overridden to_native()
and from_native()
for the actual conversion. Here's my attempt:
class UnixEpochDateField(serializers.DateTimeField):
def to_native(self, value):
""" Return epoch time for a datetime object or ``None``"""
import time
try:
return int(time.mktime(value.timetuple()))
except (AttributeError, TypeError):
return None
def from_native(self, value):
import datetime
return datetime.datetime.fromtimestamp(int(value))
And then use that field in your Serializer
definition:
class SnippetSerializer(serializers.ModelSerializer):
starttime = UnixEpochDateField(source='created')
Upvotes: 20
Reputation: 15559
If I understand it correctly, you need to deserialize the starttime
field and use it's value to update created
field. If that's so, then you need to create your own serializer field and override field_from_native
(it doesn't return anything by default, that's why it doesn't have any effect in your case):
class EpochSerializerField(SerializerMethodField):
def field_from_native(self, data, files, field_name, into):
starttime = data['starttime']
# generate `created` value using `starttime`
into['created'] = created
super(EpochSerializerField, self).field_from_native(data, files, field_name, into)
so the idea is simple, just reverse the calculation to generate created
value and use your new serializer field. You can also move the content from the epoch method into field_to_native
method of the new serializer field.
Upvotes: 0