Last active
March 16, 2016 14:39
-
-
Save fidiego/cd007fdb5f335dfc48e8 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from collections import OrderedDict | |
from rest_framework import serializers | |
class SkipField(Exception): | |
pass | |
class ExtensibleModelSerializer(serializers.ModelSerializer): | |
''' | |
Allows for specifying ``non_native_fields`` in the Meta, which allow for | |
custom handling of some fields, while letting the ``ModelSerializer`` do | |
its magic with the rest of the fields. | |
''' | |
def save(self, **kwargs): | |
return super(ExtensibleModelSerializer, self).save(**kwargs) | |
def to_representation(self, instance): | |
'''create a representation of the model but skip ``non_native_fields`` | |
1. set aside fields in ``non_native_fields`` | |
2. call `ModelSerializer`'s `to_representation` with `super` | |
3. get internal representation of ``non_native_fields`` | |
4. update data w/ non_native_fields representation and return data | |
''' | |
# 1. set aside non native fields | |
model_serializer_declared_fields = self._declared_fields | |
self._declared_fields = OrderedDict({ | |
_f:self._declared_fields[_f] for _f in self._declared_fields if _f not in self.Meta.non_native_fields | |
}) | |
# 2. call super | |
ret_data = super(ExtensibleModelSerializer, self).to_representation(instance) | |
# 3. get internal representation of non_native_fields | |
self._declared_fields = model_serializer_declared_fields | |
non_native_fields = OrderedDict({ | |
_f: self._declared_fields for _f in self._declared_fields if _f in self.Meta.non_native_fields | |
}) | |
non_native_field_data = self.to_representation_non_native_fields(instance, non_native_fields) | |
# 4. update data w/ non_native_fields and return it | |
ret_data.update(non_native_field_data) | |
return ret_data | |
def to_internal_value(self, data): | |
model_serializer_writeable_fields = self._declared_fields | |
self._declared_fields = OrderedDict({ | |
_f: self._declared_fields[_f] for _f in self._declared_fields if _f not in self.Meta.non_native_fields | |
}) | |
ret_data = super(ExtensibleModelSerializer, self).to_internal_value(data) | |
self._declared_fields = model_serializer_writeable_fields | |
non_native_fields = OrderedDict({ | |
_f: self._declared_fields[_f] for _f in self._declared_fields if _f in self.Meta.non_native_fields | |
}) | |
non_native_field_data = self.to_internal_value_non_native_fields(data, non_native_fields) | |
ret_data.update(non_native_field_data) | |
return ret_data | |
def to_internal_value_non_native_fields(self, data, non_native_fields): | |
ret_data = {} | |
for field in non_native_fields: | |
non_native_fields[field].field_name = field | |
try: | |
ret_data[field] = self.get_field_internal_value(non_native_fields[field], data) | |
except SkipField: | |
continue | |
return ret_data | |
def to_representation_non_native_fields(self, instance, non_native_fields): | |
ret_data = {} | |
for field in non_native_fields: | |
try: | |
ret_data[field] = self.get_field_representation(field, instance) | |
except SkipField: | |
continue | |
return ret_data | |
def get_field_representation(self, field, instance): | |
default_method_name = 'get_{field_name}'.format(field_name=field) | |
method = getattr(self, default_method_name, None) | |
if not method: | |
raise SkipField | |
return method(instance) | |
def get_field_internal_value(self, field, data): | |
default_method_name = 'to_internal_value' | |
method = getattr(field, default_method_name, None) | |
if not method: | |
raise SkipField | |
return method(data[field.field_name]) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment