7
7
from django.conf import settings
8
8
from django.core.serializers import base
9
from django.db import models
9
from django.db import models, DEFAULT_DB_ALIAS
10
10
from django.utils.encoding import smart_unicode, is_protected_type
12
12
class Serializer(base.Serializer):
47
47
def handle_fk_field(self, obj, field):
48
48
related = getattr(obj, field.name)
49
49
if related is not None:
50
if field.rel.field_name == related._meta.pk.name:
51
# Related to remote object via primary key
52
related = related._get_pk_val()
50
if self.use_natural_keys and hasattr(related, 'natural_key'):
51
related = related.natural_key()
54
# Related to remote object via other field
55
related = getattr(related, field.rel.field_name)
56
self._current[field.name] = smart_unicode(related, strings_only=True)
53
if field.rel.field_name == related._meta.pk.name:
54
# Related to remote object via primary key
55
related = related._get_pk_val()
57
# Related to remote object via other field
58
related = smart_unicode(getattr(related, field.rel.field_name), strings_only=True)
59
self._current[field.name] = related
58
61
def handle_m2m_field(self, obj, field):
59
if field.creates_table:
60
self._current[field.name] = [smart_unicode(related._get_pk_val(), strings_only=True)
62
if field.rel.through._meta.auto_created:
63
if self.use_natural_keys and hasattr(field.rel.to, 'natural_key'):
64
m2m_value = lambda value: value.natural_key()
66
m2m_value = lambda value: smart_unicode(value._get_pk_val(), strings_only=True)
67
self._current[field.name] = [m2m_value(related)
61
68
for related in getattr(obj, field.name).iterator()]
63
70
def getvalue(self):
70
77
It's expected that you pass the Python objects themselves (instead of a
71
78
stream or a string) to the constructor
80
db = options.pop('using', DEFAULT_DB_ALIAS)
74
82
for d in object_list:
75
83
# Look up the model and starting build a dict of data for it.
87
95
# Handle M2M relations
88
96
if field.rel and isinstance(field.rel, models.ManyToManyRel):
89
m2m_convert = field.rel.to._meta.pk.to_python
90
m2m_data[field.name] = [m2m_convert(smart_unicode(pk)) for pk in field_value]
97
if hasattr(field.rel.to._default_manager, 'get_by_natural_key'):
98
def m2m_convert(value):
99
if hasattr(value, '__iter__'):
100
return field.rel.to._default_manager.db_manager(db).get_by_natural_key(*value).pk
102
return smart_unicode(field.rel.to._meta.pk.to_python(value))
104
m2m_convert = lambda v: smart_unicode(field.rel.to._meta.pk.to_python(v))
105
m2m_data[field.name] = [m2m_convert(pk) for pk in field_value]
92
107
# Handle FK fields
93
108
elif field.rel and isinstance(field.rel, models.ManyToOneRel):
94
109
if field_value is not None:
95
data[field.attname] = field.rel.to._meta.get_field(field.rel.field_name).to_python(field_value)
110
if hasattr(field.rel.to._default_manager, 'get_by_natural_key'):
111
if hasattr(field_value, '__iter__'):
112
obj = field.rel.to._default_manager.db_manager(db).get_by_natural_key(*field_value)
113
value = getattr(obj, field.rel.field_name)
114
# If this is a natural foreign key to an object that
115
# has a FK/O2O as the foreign key, use the FK value
116
if field.rel.to._meta.pk.rel:
119
value = field.rel.to._meta.get_field(field.rel.field_name).to_python(field_value)
120
data[field.attname] = value
122
data[field.attname] = field.rel.to._meta.get_field(field.rel.field_name).to_python(field_value)
97
124
data[field.attname] = None