2006-06-30 00:42:49 +08:00
|
|
|
"""
|
|
|
|
A Python "serializer". Doesn't do much serializing per se -- just converts to
|
|
|
|
and from basic Python data types (lists, dicts, strings, etc.). Useful as a basis for
|
|
|
|
other serializers.
|
|
|
|
"""
|
2012-06-08 00:08:47 +08:00
|
|
|
from __future__ import unicode_literals
|
2006-06-30 00:42:49 +08:00
|
|
|
|
2015-04-02 03:42:09 +08:00
|
|
|
from collections import OrderedDict
|
|
|
|
|
2013-12-24 19:25:17 +08:00
|
|
|
from django.apps import apps
|
2006-06-30 00:42:49 +08:00
|
|
|
from django.conf import settings
|
|
|
|
from django.core.serializers import base
|
2015-01-07 08:16:35 +08:00
|
|
|
from django.db import DEFAULT_DB_ALIAS, models
|
2012-07-21 03:14:27 +08:00
|
|
|
from django.utils import six
|
2015-01-28 20:35:27 +08:00
|
|
|
from django.utils.encoding import force_text, is_protected_type
|
2006-06-30 00:42:49 +08:00
|
|
|
|
2012-09-30 20:34:13 +08:00
|
|
|
|
2006-06-30 00:42:49 +08:00
|
|
|
class Serializer(base.Serializer):
|
|
|
|
"""
|
|
|
|
Serializes a QuerySet to basic Python objects.
|
|
|
|
"""
|
2009-04-13 20:35:49 +08:00
|
|
|
|
2007-12-17 14:53:15 +08:00
|
|
|
internal_use_only = True
|
2009-04-13 20:35:49 +08:00
|
|
|
|
2006-06-30 00:42:49 +08:00
|
|
|
def start_serialization(self):
|
|
|
|
self._current = None
|
|
|
|
self.objects = []
|
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
|
|
|
|
2006-06-30 00:42:49 +08:00
|
|
|
def end_serialization(self):
|
|
|
|
pass
|
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
|
|
|
|
2006-06-30 00:42:49 +08:00
|
|
|
def start_object(self, obj):
|
2015-04-02 03:42:09 +08:00
|
|
|
self._current = OrderedDict()
|
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
|
|
|
|
2006-06-30 00:42:49 +08:00
|
|
|
def end_object(self, obj):
|
2012-05-26 17:43:37 +08:00
|
|
|
self.objects.append(self.get_dump_object(obj))
|
2006-06-30 00:42:49 +08:00
|
|
|
self._current = None
|
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
|
|
|
|
2012-05-26 17:43:37 +08:00
|
|
|
def get_dump_object(self, obj):
|
2015-07-03 01:17:48 +08:00
|
|
|
model = obj._meta.proxy_for_model if obj._deferred else obj.__class__
|
|
|
|
data = OrderedDict([('model', force_text(model._meta))])
|
2012-08-01 09:49:01 +08:00
|
|
|
if not self.use_natural_primary_keys or not hasattr(obj, 'natural_key'):
|
2014-12-21 21:24:15 +08:00
|
|
|
data["pk"] = force_text(obj._get_pk_val(), strings_only=True)
|
2015-04-02 03:42:09 +08:00
|
|
|
data['fields'] = self._current
|
2012-08-01 09:49:01 +08:00
|
|
|
return data
|
2012-05-26 17:43:37 +08:00
|
|
|
|
2006-06-30 00:42:49 +08:00
|
|
|
def handle_field(self, obj, field):
|
2015-04-26 14:30:46 +08:00
|
|
|
value = field.value_from_object(obj)
|
2009-04-13 20:35:49 +08:00
|
|
|
# Protected types (i.e., primitives like None, numbers, dates,
|
|
|
|
# and Decimals) are passed through as is. All other values are
|
|
|
|
# converted to string first.
|
|
|
|
if is_protected_type(value):
|
|
|
|
self._current[field.name] = value
|
|
|
|
else:
|
|
|
|
self._current[field.name] = field.value_to_string(obj)
|
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
|
|
|
|
2006-06-30 00:42:49 +08:00
|
|
|
def handle_fk_field(self, obj, field):
|
2015-02-26 22:19:17 +08:00
|
|
|
if self.use_natural_foreign_keys and hasattr(field.remote_field.model, 'natural_key'):
|
2012-02-05 02:27:07 +08:00
|
|
|
related = getattr(obj, field.name)
|
2012-03-13 03:41:31 +08:00
|
|
|
if related:
|
|
|
|
value = related.natural_key()
|
|
|
|
else:
|
|
|
|
value = None
|
2012-02-05 02:27:07 +08:00
|
|
|
else:
|
|
|
|
value = getattr(obj, field.get_attname())
|
2015-02-13 22:21:33 +08:00
|
|
|
if not is_protected_type(value):
|
|
|
|
value = field.value_to_string(obj)
|
2012-02-05 02:27:07 +08:00
|
|
|
self._current[field.name] = value
|
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
|
|
|
|
2006-06-30 00:42:49 +08:00
|
|
|
def handle_m2m_field(self, obj, field):
|
2015-02-26 22:19:17 +08:00
|
|
|
if field.remote_field.through._meta.auto_created:
|
|
|
|
if self.use_natural_foreign_keys and hasattr(field.remote_field.model, 'natural_key'):
|
2016-01-24 00:47:07 +08:00
|
|
|
def m2m_value(value):
|
|
|
|
return value.natural_key()
|
2009-12-14 20:39:20 +08:00
|
|
|
else:
|
2016-01-24 00:47:07 +08:00
|
|
|
def m2m_value(value):
|
|
|
|
return force_text(value._get_pk_val(), strings_only=True)
|
2009-12-14 20:39:20 +08:00
|
|
|
self._current[field.name] = [m2m_value(related)
|
2008-08-12 20:58:33 +08:00
|
|
|
for related in getattr(obj, field.name).iterator()]
|
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
|
|
|
|
2006-06-30 00:42:49 +08:00
|
|
|
def getvalue(self):
|
|
|
|
return self.objects
|
|
|
|
|
2012-09-30 20:34:13 +08:00
|
|
|
|
2006-06-30 00:42:49 +08:00
|
|
|
def Deserializer(object_list, **options):
|
|
|
|
"""
|
|
|
|
Deserialize simple Python objects back into Django ORM instances.
|
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
|
|
|
|
2006-06-30 00:42:49 +08:00
|
|
|
It's expected that you pass the Python objects themselves (instead of a
|
|
|
|
stream or a string) to the constructor
|
|
|
|
"""
|
2009-12-22 23:18:51 +08:00
|
|
|
db = options.pop('using', DEFAULT_DB_ALIAS)
|
2012-09-30 20:34:13 +08:00
|
|
|
ignore = options.pop('ignorenonexistent', False)
|
2015-10-23 10:29:46 +08:00
|
|
|
field_names_cache = {} # Model: <list of field_names>
|
2012-09-30 20:34:13 +08:00
|
|
|
|
2006-06-30 00:42:49 +08:00
|
|
|
for d in object_list:
|
|
|
|
# Look up the model and starting build a dict of data for it.
|
2014-02-21 14:43:08 +08:00
|
|
|
try:
|
|
|
|
Model = _get_model(d["model"])
|
2014-05-19 05:42:03 +08:00
|
|
|
except base.DeserializationError:
|
2014-02-21 14:43:08 +08:00
|
|
|
if ignore:
|
|
|
|
continue
|
|
|
|
else:
|
2014-05-19 05:42:03 +08:00
|
|
|
raise
|
2012-08-01 09:49:01 +08:00
|
|
|
data = {}
|
|
|
|
if 'pk' in d:
|
2015-03-27 02:31:09 +08:00
|
|
|
try:
|
|
|
|
data[Model._meta.pk.attname] = Model._meta.pk.to_python(d.get('pk'))
|
|
|
|
except Exception as e:
|
|
|
|
raise base.DeserializationError.WithData(e, d['model'], d.get('pk'), None)
|
2006-06-30 00:42:49 +08:00
|
|
|
m2m_data = {}
|
2015-10-23 10:29:46 +08:00
|
|
|
|
|
|
|
if Model not in field_names_cache:
|
|
|
|
field_names_cache[Model] = {f.name for f in Model._meta.get_fields()}
|
|
|
|
field_names = field_names_cache[Model]
|
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
|
|
|
|
2006-06-30 00:42:49 +08:00
|
|
|
# Handle each field
|
2012-07-21 03:14:27 +08:00
|
|
|
for (field_name, field_value) in six.iteritems(d["fields"]):
|
2012-09-30 20:34:13 +08:00
|
|
|
|
2015-01-07 08:16:35 +08:00
|
|
|
if ignore and field_name not in field_names:
|
2012-09-30 20:34:13 +08:00
|
|
|
# skip fields no longer on model
|
|
|
|
continue
|
|
|
|
|
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
|
|
|
if isinstance(field_value, str):
|
2014-12-21 21:24:15 +08:00
|
|
|
field_value = force_text(
|
2014-09-04 20:15:09 +08:00
|
|
|
field_value, options.get("encoding", settings.DEFAULT_CHARSET), strings_only=True
|
|
|
|
)
|
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
|
|
|
|
2006-06-30 00:42:49 +08:00
|
|
|
field = Model._meta.get_field(field_name)
|
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
|
|
|
|
2007-02-27 01:33:27 +08:00
|
|
|
# Handle M2M relations
|
2015-02-26 22:19:17 +08:00
|
|
|
if field.remote_field and isinstance(field.remote_field, models.ManyToManyRel):
|
2015-09-12 07:33:12 +08:00
|
|
|
model = field.remote_field.model
|
|
|
|
if hasattr(model._default_manager, 'get_by_natural_key'):
|
2009-12-14 20:39:20 +08:00
|
|
|
def m2m_convert(value):
|
2012-08-08 23:59:31 +08:00
|
|
|
if hasattr(value, '__iter__') and not isinstance(value, six.text_type):
|
2015-09-12 07:33:12 +08:00
|
|
|
return model._default_manager.db_manager(db).get_by_natural_key(*value).pk
|
2009-12-14 20:39:20 +08:00
|
|
|
else:
|
2015-09-12 07:33:12 +08:00
|
|
|
return force_text(model._meta.pk.to_python(value), strings_only=True)
|
2009-12-14 20:39:20 +08:00
|
|
|
else:
|
2016-01-24 00:47:07 +08:00
|
|
|
def m2m_convert(v):
|
|
|
|
return force_text(model._meta.pk.to_python(v), strings_only=True)
|
2015-03-27 02:31:09 +08:00
|
|
|
|
|
|
|
try:
|
|
|
|
m2m_data[field.name] = []
|
|
|
|
for pk in field_value:
|
|
|
|
m2m_data[field.name].append(m2m_convert(pk))
|
|
|
|
except Exception as e:
|
|
|
|
raise base.DeserializationError.WithData(e, d['model'], d.get('pk'), pk)
|
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
|
|
|
|
2006-06-30 00:42:49 +08:00
|
|
|
# Handle FK fields
|
2015-02-26 22:19:17 +08:00
|
|
|
elif field.remote_field and isinstance(field.remote_field, models.ManyToOneRel):
|
2015-09-12 07:33:12 +08:00
|
|
|
model = field.remote_field.model
|
2008-08-29 03:38:56 +08:00
|
|
|
if field_value is not None:
|
2015-03-27 02:31:09 +08:00
|
|
|
try:
|
2015-09-12 07:33:12 +08:00
|
|
|
default_manager = model._default_manager
|
|
|
|
field_name = field.remote_field.field_name
|
|
|
|
if hasattr(default_manager, 'get_by_natural_key'):
|
2015-03-27 02:31:09 +08:00
|
|
|
if hasattr(field_value, '__iter__') and not isinstance(field_value, six.text_type):
|
2015-09-12 07:33:12 +08:00
|
|
|
obj = default_manager.db_manager(db).get_by_natural_key(*field_value)
|
2015-03-27 02:31:09 +08:00
|
|
|
value = getattr(obj, field.remote_field.field_name)
|
|
|
|
# If this is a natural foreign key to an object that
|
|
|
|
# has a FK/O2O as the foreign key, use the FK value
|
2015-09-12 07:33:12 +08:00
|
|
|
if model._meta.pk.remote_field:
|
2015-03-27 02:31:09 +08:00
|
|
|
value = value.pk
|
|
|
|
else:
|
2015-09-12 07:33:12 +08:00
|
|
|
value = model._meta.get_field(field_name).to_python(field_value)
|
2015-03-27 02:31:09 +08:00
|
|
|
data[field.attname] = value
|
2009-12-14 20:39:20 +08:00
|
|
|
else:
|
2015-09-12 07:33:12 +08:00
|
|
|
data[field.attname] = model._meta.get_field(field_name).to_python(field_value)
|
2015-03-27 02:31:09 +08:00
|
|
|
except Exception as e:
|
|
|
|
raise base.DeserializationError.WithData(e, d['model'], d.get('pk'), field_value)
|
2007-05-14 22:14:49 +08:00
|
|
|
else:
|
|
|
|
data[field.attname] = None
|
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
|
|
|
|
2006-06-30 00:42:49 +08:00
|
|
|
# Handle all other fields
|
|
|
|
else:
|
2015-03-27 02:31:09 +08:00
|
|
|
try:
|
|
|
|
data[field.name] = field.to_python(field_value)
|
|
|
|
except Exception as e:
|
|
|
|
raise base.DeserializationError.WithData(e, d['model'], d.get('pk'), field_value)
|
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
|
|
|
|
2012-08-01 09:49:01 +08:00
|
|
|
obj = base.build_instance(Model, data, db)
|
|
|
|
yield base.DeserializedObject(obj, m2m_data)
|
2006-06-30 00:42:49 +08:00
|
|
|
|
2013-11-03 04:12:09 +08:00
|
|
|
|
2006-06-30 00:42:49 +08:00
|
|
|
def _get_model(model_identifier):
|
|
|
|
"""
|
2013-02-05 17:16:07 +08:00
|
|
|
Helper to look up a model from an "app_label.model_name" string.
|
2006-06-30 00:42:49 +08:00
|
|
|
"""
|
|
|
|
try:
|
2014-01-26 19:57:08 +08:00
|
|
|
return apps.get_model(model_identifier)
|
2013-12-28 21:55:54 +08:00
|
|
|
except (LookupError, TypeError):
|
2012-06-08 00:08:47 +08:00
|
|
|
raise base.DeserializationError("Invalid model identifier: '%s'" % model_identifier)
|