| 1 |
""" |
|---|
| 2 |
A Python "serializer". Doesn't do much serializing per se -- just converts to |
|---|
| 3 |
and from basic Python data types (lists, dicts, strings, etc.). Useful as a basis for |
|---|
| 4 |
other serializers. |
|---|
| 5 |
""" |
|---|
| 6 |
|
|---|
| 7 |
from django.conf import settings |
|---|
| 8 |
from django.core.serializers import base |
|---|
| 9 |
from django.db import models |
|---|
| 10 |
from django.utils.encoding import smart_unicode |
|---|
| 11 |
|
|---|
| 12 |
class Serializer(base.Serializer): |
|---|
| 13 |
""" |
|---|
| 14 |
Serializes a QuerySet to basic Python objects. |
|---|
| 15 |
""" |
|---|
| 16 |
|
|---|
| 17 |
internal_use_only = True |
|---|
| 18 |
|
|---|
| 19 |
def start_serialization(self): |
|---|
| 20 |
self._current = None |
|---|
| 21 |
self.objects = [] |
|---|
| 22 |
|
|---|
| 23 |
def end_serialization(self): |
|---|
| 24 |
pass |
|---|
| 25 |
|
|---|
| 26 |
def start_object(self, obj): |
|---|
| 27 |
self._current = {} |
|---|
| 28 |
|
|---|
| 29 |
def end_object(self, obj): |
|---|
| 30 |
self.objects.append({ |
|---|
| 31 |
"model" : smart_unicode(obj._meta), |
|---|
| 32 |
"pk" : smart_unicode(obj._get_pk_val(), strings_only=True), |
|---|
| 33 |
"fields" : self._current |
|---|
| 34 |
}) |
|---|
| 35 |
self._current = None |
|---|
| 36 |
|
|---|
| 37 |
def handle_field(self, obj, field): |
|---|
| 38 |
self._current[field.name] = smart_unicode(getattr(obj, field.name), strings_only=True) |
|---|
| 39 |
|
|---|
| 40 |
def handle_fk_field(self, obj, field): |
|---|
| 41 |
related = getattr(obj, field.name) |
|---|
| 42 |
if related is not None: |
|---|
| 43 |
if field.rel.field_name == related._meta.pk.name: |
|---|
| 44 |
# Related to remote object via primary key |
|---|
| 45 |
related = related._get_pk_val() |
|---|
| 46 |
else: |
|---|
| 47 |
# Related to remote object via other field |
|---|
| 48 |
related = getattr(related, field.rel.field_name) |
|---|
| 49 |
self._current[field.name] = smart_unicode(related, strings_only=True) |
|---|
| 50 |
|
|---|
| 51 |
def handle_m2m_field(self, obj, field): |
|---|
| 52 |
if field.creates_table: |
|---|
| 53 |
self._current[field.name] = [smart_unicode(related._get_pk_val(), strings_only=True) |
|---|
| 54 |
for related in getattr(obj, field.name).iterator()] |
|---|
| 55 |
|
|---|
| 56 |
def getvalue(self): |
|---|
| 57 |
return self.objects |
|---|
| 58 |
|
|---|
| 59 |
def Deserializer(object_list, **options): |
|---|
| 60 |
""" |
|---|
| 61 |
Deserialize simple Python objects back into Django ORM instances. |
|---|
| 62 |
|
|---|
| 63 |
It's expected that you pass the Python objects themselves (instead of a |
|---|
| 64 |
stream or a string) to the constructor |
|---|
| 65 |
""" |
|---|
| 66 |
models.get_apps() |
|---|
| 67 |
for d in object_list: |
|---|
| 68 |
# Look up the model and starting build a dict of data for it. |
|---|
| 69 |
Model = _get_model(d["model"]) |
|---|
| 70 |
data = {Model._meta.pk.attname : Model._meta.pk.to_python(d["pk"])} |
|---|
| 71 |
m2m_data = {} |
|---|
| 72 |
|
|---|
| 73 |
# Handle each field |
|---|
| 74 |
for (field_name, field_value) in d["fields"].iteritems(): |
|---|
| 75 |
if isinstance(field_value, str): |
|---|
| 76 |
field_value = smart_unicode(field_value, options.get("encoding", settings.DEFAULT_CHARSET), strings_only=True) |
|---|
| 77 |
|
|---|
| 78 |
field = Model._meta.get_field(field_name) |
|---|
| 79 |
|
|---|
| 80 |
# Handle M2M relations |
|---|
| 81 |
if field.rel and isinstance(field.rel, models.ManyToManyRel): |
|---|
| 82 |
m2m_convert = field.rel.to._meta.pk.to_python |
|---|
| 83 |
m2m_data[field.name] = [m2m_convert(smart_unicode(pk)) for pk in field_value] |
|---|
| 84 |
|
|---|
| 85 |
# Handle FK fields |
|---|
| 86 |
elif field.rel and isinstance(field.rel, models.ManyToOneRel): |
|---|
| 87 |
if field_value is not None: |
|---|
| 88 |
data[field.attname] = field.rel.to._meta.get_field(field.rel.field_name).to_python(field_value) |
|---|
| 89 |
else: |
|---|
| 90 |
data[field.attname] = None |
|---|
| 91 |
|
|---|
| 92 |
# Handle all other fields |
|---|
| 93 |
else: |
|---|
| 94 |
data[field.name] = field.to_python(field_value) |
|---|
| 95 |
|
|---|
| 96 |
yield base.DeserializedObject(Model(**data), m2m_data) |
|---|
| 97 |
|
|---|
| 98 |
def _get_model(model_identifier): |
|---|
| 99 |
""" |
|---|
| 100 |
Helper to look up a model from an "app_label.module_name" string. |
|---|
| 101 |
""" |
|---|
| 102 |
try: |
|---|
| 103 |
Model = models.get_model(*model_identifier.split(".")) |
|---|
| 104 |
except TypeError: |
|---|
| 105 |
Model = None |
|---|
| 106 |
if Model is None: |
|---|
| 107 |
raise base.DeserializationError(u"Invalid model identifier: '%s'" % model_identifier) |
|---|
| 108 |
return Model |
|---|