Skip to content

Instantly share code, notes, and snippets.

@jmaicher
Created May 9, 2015 10:17
Show Gist options
  • Save jmaicher/5a5230e2a7699d4fd30b to your computer and use it in GitHub Desktop.
Save jmaicher/5a5230e2a7699d4fd30b to your computer and use it in GitHub Desktop.
(De-)serialize Plain Old Python Objects (POPOs) with Django Rest Framework
# encoding: utf-8
from __future__ import absolute_import, unicode_literals
import logging
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
log = logging.getLogger(__name__)
class POPOListSerializer(serializers.ListSerializer):
""" List serializer for Plain Old Python Objects (POPO) """
def build(self):
if not hasattr(self, "_errors"):
self.is_valid(raise_exception=True)
return self.save()
class POPOSerializer(serializers.Serializer):
""" Serializer for Plain Old Python Objects (POPO) """
ORIGINAL_DATA_ATTR = "__popo_serializer__original_data"
class Meta:
list_serializer_class = POPOListSerializer
def create(self, validated_data):
"""
:type validated_data: dict | collections.OrderedDict
"""
assert hasattr(self, "Meta") and getattr(self.Meta, "model", None), "No `Meta.model` defined"
ModelClass = self.Meta.model
for original_name, field in self.fields.iteritems():
name = field.source
if name in validated_data:
if isinstance(field, POPOSerializer) and name in validated_data:
# Note: We call create directly since the data has already been validated
validated_data[name] = field.create(validated_data[name])
elif isinstance(field, serializers.ListSerializer) and isinstance(field.child, POPOSerializer):
validated_data[name] = [field.child.create(validated_item) for validated_item in validated_data[name]]
try:
instance = ModelClass(**validated_data)
except TypeError as e:
msg = 'Got TypeError (%s) when trying to create %s with data: %s' % (e, ModelClass, validated_data)
log.warn(msg)
raise ValidationError(msg)
# Preserve original data for debugging and later processing
setattr(instance, self.ORIGINAL_DATA_ATTR, self.root.initial_data)
return instance
def build(self):
if not hasattr(self, "_errors"):
self.is_valid(raise_exception=True)
return self.save()
def update(self, instance, validated_data):
raise NotImplemented("`update()` not implemented.")
@classmethod
def extract_original_data(cls, instance):
data = getattr(instance, cls.ORIGINAL_DATA_ATTR, None)
if data is None:
log.warn("Could not extract original data from {}".format(instance))
return None
return data
@bartoszhernas
Copy link

bartoszhernas commented Aug 27, 2016

Thanks! Usefull snippet <3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment