diff --git a/apps/common/serializers/__init__.py b/apps/common/serializers/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/apps/common/serializers/better_yaml.py b/apps/common/serializers/better_yaml.py new file mode 100644 index 0000000000..330053f270 --- /dev/null +++ b/apps/common/serializers/better_yaml.py @@ -0,0 +1,103 @@ +# better_yaml.py + +""" +Customized YAML serializer, with more condensed and readable output. +Rather than producing a flat list of objects with the same three attributes: + + - fields: {...} + model: modelname + pk: 123 + +This serializer nests the data, grouping by model name, then indexing by +primary key. For example, instead of this output, as produced by the default +YAML serializer: + + - fields: {name: blue} + model: app.firstmodel + pk: 3 + - fields: {name: red} + model: app.firstmodel + pk: 1 + - fields: {name: green} + model: app.firstmodel + pk: 2 + - fields: {name: crumbly} + model: app.secondmodel + pk: 2 + - fields: {name: squishy} + model: app.secondmodel + pk: 1 + +You'll get this output: + + app.firstmodel: + 1: {name: red} + 2: {name: green} + 3: {name: blue} + app.secondmodel: + 1: {name: squishy} + 2: {name: crumbly} + +To use this customized serializer and deserializer, save this file +somewhere in your Django project, then add this to your settings.py: + + SERIALIZATION_MODULES = { + 'yaml': 'path.to.better_yaml', + } + +Note that this serializer is NOT compatible with the default Django +YAML serializer; this one uses nested dictionaries, while the default +one uses a flat list of object dicts. + +Requires PyYaml (http://pyyaml.org/), of course. +""" + +from StringIO import StringIO +import yaml + +from django.core.serializers.pyyaml import Serializer as YamlSerializer +from django.core.serializers.python import Deserializer as PythonDeserializer +from django.utils.encoding import smart_unicode + +class Serializer (YamlSerializer): + """ + Serialize database objects as nested dicts, indexed first by + model name, then by primary key. + """ + def start_serialization(self): + self._current = None + self.objects = {} + + def end_object(self, obj): + model = smart_unicode(obj._meta) + pk = obj._get_pk_val() + + if model not in self.objects: + self.objects[model] = {} + + self.objects[model][pk] = self._current + self._current = None + + +def Deserializer(stream_or_string, **options): + """ + Deserialize a stream or string of YAML data, + as written by the Serializer above. + """ + if isinstance(stream_or_string, basestring): + stream = StringIO(stream_or_string) + else: + stream = stream_or_string + + # Reconstruct the flat object list as PythonDeserializer expects + # NOTE: This could choke on large data sets, since it + # constructs the flattened data list in memory + data = [] + for model, objects in yaml.load(stream).iteritems(): + # Add the model name back into each object dict + for pk, fields in objects.iteritems(): + data.append({'model': model, 'pk': pk, 'fields': fields}) + + # Deserialize the flattened data + for obj in PythonDeserializer(data, **options): + yield obj diff --git a/settings.py b/settings.py index 50b02f3091..7e7d037fac 100644 --- a/settings.py +++ b/settings.py @@ -233,6 +233,10 @@ PAGINATION_INVALID_PAGE_RAISES_404 = True #---------- Search ------------------ SEARCH_SHOW_OBJECT_TYPE = False +SERIALIZATION_MODULES = { + 'better_yaml': 'common.serializers.better_yaml', +} + try: from settings_local import * except ImportError: