Project

General

Profile

Statistics
| Branch: | Revision:

root / env / lib / python2.7 / site-packages / django / core / serializers / python.py @ 1a305335

History | View | Annotate | Download (5.51 KB)

1 1a305335 officers
"""
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, DEFAULT_DB_ALIAS
10
from django.utils.encoding import smart_unicode, is_protected_type
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
        value = field._get_val_from_obj(obj)
39
        # Protected types (i.e., primitives like None, numbers, dates,
40
        # and Decimals) are passed through as is. All other values are
41
        # converted to string first.
42
        if is_protected_type(value):
43
            self._current[field.name] = value
44
        else:
45
            self._current[field.name] = field.value_to_string(obj)
46
47
    def handle_fk_field(self, obj, field):
48
        if self.use_natural_keys and hasattr(field.rel.to, 'natural_key'):
49
            related = getattr(obj, field.name)
50
            if related:
51
                value = related.natural_key()
52
            else:
53
                value = None
54
        else:
55
            value = getattr(obj, field.get_attname())
56
        self._current[field.name] = value
57
58
    def handle_m2m_field(self, obj, field):
59
        if field.rel.through._meta.auto_created:
60
            if self.use_natural_keys and hasattr(field.rel.to, 'natural_key'):
61
                m2m_value = lambda value: value.natural_key()
62
            else:
63
                m2m_value = lambda value: smart_unicode(value._get_pk_val(), strings_only=True)
64
            self._current[field.name] = [m2m_value(related)
65
                               for related in getattr(obj, field.name).iterator()]
66
67
    def getvalue(self):
68
        return self.objects
69
70
def Deserializer(object_list, **options):
71
    """
72
    Deserialize simple Python objects back into Django ORM instances.
73

74
    It's expected that you pass the Python objects themselves (instead of a
75
    stream or a string) to the constructor
76
    """
77
    db = options.pop('using', DEFAULT_DB_ALIAS)
78
    models.get_apps()
79
    for d in object_list:
80
        # Look up the model and starting build a dict of data for it.
81
        Model = _get_model(d["model"])
82
        data = {Model._meta.pk.attname : Model._meta.pk.to_python(d["pk"])}
83
        m2m_data = {}
84
85
        # Handle each field
86
        for (field_name, field_value) in d["fields"].iteritems():
87
            if isinstance(field_value, str):
88
                field_value = smart_unicode(field_value, options.get("encoding", settings.DEFAULT_CHARSET), strings_only=True)
89
90
            field = Model._meta.get_field(field_name)
91
92
            # Handle M2M relations
93
            if field.rel and isinstance(field.rel, models.ManyToManyRel):
94
                if hasattr(field.rel.to._default_manager, 'get_by_natural_key'):
95
                    def m2m_convert(value):
96
                        if hasattr(value, '__iter__'):
97
                            return field.rel.to._default_manager.db_manager(db).get_by_natural_key(*value).pk
98
                        else:
99
                            return smart_unicode(field.rel.to._meta.pk.to_python(value))
100
                else:
101
                    m2m_convert = lambda v: smart_unicode(field.rel.to._meta.pk.to_python(v))
102
                m2m_data[field.name] = [m2m_convert(pk) for pk in field_value]
103
104
            # Handle FK fields
105
            elif field.rel and isinstance(field.rel, models.ManyToOneRel):
106
                if field_value is not None:
107
                    if hasattr(field.rel.to._default_manager, 'get_by_natural_key'):
108
                        if hasattr(field_value, '__iter__'):
109
                            obj = field.rel.to._default_manager.db_manager(db).get_by_natural_key(*field_value)
110
                            value = getattr(obj, field.rel.field_name)
111
                            # If this is a natural foreign key to an object that
112
                            # has a FK/O2O as the foreign key, use the FK value
113
                            if field.rel.to._meta.pk.rel:
114
                                value = value.pk
115
                        else:
116
                            value = field.rel.to._meta.get_field(field.rel.field_name).to_python(field_value)
117
                        data[field.attname] = value
118
                    else:
119
                        data[field.attname] = field.rel.to._meta.get_field(field.rel.field_name).to_python(field_value)
120
                else:
121
                    data[field.attname] = None
122
123
            # Handle all other fields
124
            else:
125
                data[field.name] = field.to_python(field_value)
126
127
        yield base.DeserializedObject(Model(**data), m2m_data)
128
129
def _get_model(model_identifier):
130
    """
131
    Helper to look up a model from an "app_label.module_name" string.
132
    """
133
    try:
134
        Model = models.get_model(*model_identifier.split("."))
135
    except TypeError:
136
        Model = None
137
    if Model is None:
138
        raise base.DeserializationError(u"Invalid model identifier: '%s'" % model_identifier)
139
    return Model