Skip to content

Instantly share code, notes, and snippets.

@coddingtonbear
Created June 5, 2014 20:02
Show Gist options
  • Select an option

  • Save coddingtonbear/464fbdda2f0600ce4a77 to your computer and use it in GitHub Desktop.

Select an option

Save coddingtonbear/464fbdda2f0600ce4a77 to your computer and use it in GitHub Desktop.
Adam's Lovely-but-now-about-to-be-abandoned Serializer
import json
from django.core import serializers
from django.core.serializers.json import DjangoJSONEncoder
from django.db.models import Model
from django.db.models.query import QuerySet
from django.template import (
Context, Library, Node, TemplateSyntaxError, Variable
)
from django.utils.safestring import mark_safe
from medley.util.caching import QuerySetList
register = Library()
class JSONSerializer(DjangoJSONEncoder):
""" Special JSON allowing (naive) model serialization by __unicode__"""
def default(self, obj):
if isinstance(obj, Model):
return unicode(obj)
return super(JSONSerializer, self).default(obj)
class SerializerNode(Node):
INSTANCE_NAME = 'obj'
def __init__(self, qs, fields=None):
self._qs = qs
self._fields = fields
self._field_name_map = {}
def get_synthetic_context(self, obj):
return Context({
self.INSTANCE_NAME: obj,
})
def get_synthetic_field_lookups(self, raw_fields):
fields = []
for raw_field in raw_fields:
if '=' in raw_field:
field_parts = raw_field.split('=')
assigned_name = field_parts[0]
field = field_parts[1]
else:
# Return the same name in JSON that we're using for lookup
assigned_name, field = raw_field, raw_field
if field == '__unicode__':
lookup_name = self.INSTANCE_NAME
else:
lookup_name = 'obj.%s' % field
fields.append(lookup_name)
self._field_name_map[lookup_name] = assigned_name
return fields
def get_actual_field_name(self, field):
if field in self._field_name_map:
return self._field_name_map[field]
return field
def model_serializer(self, queryset):
return serializers.serialize(
'json',
queryset,
)
def dictionary_serializer(self, queryset):
return json.dumps(queryset, cls=JSONSerializer)
def get_queryset_and_serializer(self, context):
queryset = Variable(self._qs).resolve(context)
if not isinstance(queryset, (QuerySet, QuerySetList)):
# We'll let people pass-in a single instance, but we'll
# need to hand an iterable to Django's serializer:
return [queryset], self.model_serializer
elif self._fields is None:
return queryset, self.model_serializer
# If we've made it this far, we're using self._fields, and
# will be creating a new dictionary that we will serialize
dict_queryset = []
for instance in queryset:
context = self.get_synthetic_context(instance)
fields = self.get_synthetic_field_lookups(self._fields)
obj = dict(
(
self.get_actual_field_name(field),
Variable(field).resolve(context)
)
for field in fields
)
dict_queryset.append(obj)
return dict_queryset, self.dictionary_serializer
def render(self, context):
queryset, serializer = self.get_queryset_and_serializer(context)
return mark_safe(serializer(queryset))
@register.tag
def serialize(parser, token):
try:
parts = token.split_contents()
qs = parts[1]
fields = parts[2:]
except ValueError:
raise TemplateSyntaxError("Provide a single parameter only")
return SerializerNode(qs, fields)
@coddingtonbear

Copy link
Copy Markdown
Author
{% serialize some_queryset_or_instance %}

or

{% serialize some_queryset_or_instance somealias=somefieldnamewewanttoalias somefieldwithoutalias %}

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