2006-06-29 00:00:37 +08:00
|
|
|
"""
|
|
|
|
Module for abstract serializer/unserializer base classes.
|
|
|
|
"""
|
|
|
|
|
2008-07-30 18:40:37 +08:00
|
|
|
from StringIO import StringIO
|
|
|
|
|
2006-06-29 00:00:37 +08:00
|
|
|
from django.db import models
|
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
|
|
|
from django.utils.encoding import smart_str, smart_unicode
|
2008-07-18 11:47:27 +08:00
|
|
|
from django.utils import datetime_safe
|
2006-06-29 00:00:37 +08:00
|
|
|
|
2011-04-27 00:49:32 +08:00
|
|
|
class SerializerDoesNotExist(KeyError):
|
|
|
|
"""The requested serializer was not found."""
|
|
|
|
pass
|
|
|
|
|
2006-06-29 00:00:37 +08:00
|
|
|
class SerializationError(Exception):
|
|
|
|
"""Something bad happened during serialization."""
|
|
|
|
pass
|
2006-08-31 12:11:46 +08:00
|
|
|
|
2006-06-29 00:00:37 +08:00
|
|
|
class DeserializationError(Exception):
|
|
|
|
"""Something bad happened during deserialization."""
|
|
|
|
pass
|
|
|
|
|
|
|
|
class Serializer(object):
|
|
|
|
"""
|
|
|
|
Abstract serializer base class.
|
|
|
|
"""
|
2006-08-31 12:11:46 +08:00
|
|
|
|
2008-03-18 22:35:05 +08:00
|
|
|
# Indicates if the implemented serializer is only available for
|
2007-12-17 14:53:15 +08:00
|
|
|
# internal Django use.
|
|
|
|
internal_use_only = False
|
2008-03-18 22:35:05 +08:00
|
|
|
|
2006-06-29 00:00:37 +08:00
|
|
|
def serialize(self, queryset, **options):
|
|
|
|
"""
|
|
|
|
Serialize a queryset.
|
|
|
|
"""
|
|
|
|
self.options = options
|
2006-08-31 12:11:46 +08:00
|
|
|
|
2011-01-08 23:07:45 +08:00
|
|
|
self.stream = options.pop("stream", StringIO())
|
|
|
|
self.selected_fields = options.pop("fields", None)
|
|
|
|
self.use_natural_keys = options.pop("use_natural_keys", False)
|
2006-08-31 12:11:46 +08:00
|
|
|
|
2006-06-29 00:00:37 +08:00
|
|
|
self.start_serialization()
|
|
|
|
for obj in queryset:
|
|
|
|
self.start_object(obj)
|
2008-06-09 22:03:35 +08:00
|
|
|
for field in obj._meta.local_fields:
|
2007-03-19 19:57:53 +08:00
|
|
|
if field.serialize:
|
|
|
|
if field.rel is None:
|
|
|
|
if self.selected_fields is None or field.attname in self.selected_fields:
|
|
|
|
self.handle_field(obj, field)
|
|
|
|
else:
|
|
|
|
if self.selected_fields is None or field.attname[:-3] in self.selected_fields:
|
|
|
|
self.handle_fk_field(obj, field)
|
2006-06-29 00:00:37 +08:00
|
|
|
for field in obj._meta.many_to_many:
|
2007-03-19 19:57:53 +08:00
|
|
|
if field.serialize:
|
|
|
|
if self.selected_fields is None or field.attname in self.selected_fields:
|
|
|
|
self.handle_m2m_field(obj, field)
|
2006-06-29 00:00:37 +08:00
|
|
|
self.end_object(obj)
|
|
|
|
self.end_serialization()
|
|
|
|
return self.getvalue()
|
2006-08-31 12:11:46 +08:00
|
|
|
|
2006-06-29 00:00:37 +08:00
|
|
|
def get_string_value(self, obj, field):
|
|
|
|
"""
|
|
|
|
Convert a field's value to a string.
|
|
|
|
"""
|
Removed oldforms, validators, and related code:
* Removed `Manipulator`, `AutomaticManipulator`, and related classes.
* Removed oldforms specific bits from model fields:
* Removed `validator_list` and `core` arguments from constructors.
* Removed the methods:
* `get_manipulator_field_names`
* `get_manipulator_field_objs`
* `get_manipulator_fields`
* `get_manipulator_new_data`
* `prepare_field_objs_and_params`
* `get_follow`
* Renamed `flatten_data` method to `value_to_string` for better alignment with its use by the serialization framework, which was the only remaining code using `flatten_data`.
* Removed oldforms methods from `django.db.models.Options` class: `get_followed_related_objects`, `get_data_holders`, `get_follow`, and `has_field_type`.
* Removed oldforms-admin specific options from `django.db.models.fields.related` classes: `num_in_admin`, `min_num_in_admin`, `max_num_in_admin`, `num_extra_on_change`, and `edit_inline`.
* Serialization framework
* `Serializer.get_string_value` now calls the model fields' renamed `value_to_string` methods.
* Removed a special-casing of `models.DateTimeField` in `core.serializers.base.Serializer.get_string_value` that's handled by `django.db.models.fields.DateTimeField.value_to_string`.
* Removed `django.core.validators`:
* Moved `ValidationError` exception to `django.core.exceptions`.
* For the couple places that were using validators, brought over the necessary code to maintain the same functionality.
* Introduced a SlugField form field for validation and to compliment the SlugField model field (refs #8040).
* Removed an oldforms-style model creation hack (refs #2160).
git-svn-id: http://code.djangoproject.com/svn/django/trunk@8616 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-08-27 15:19:44 +08:00
|
|
|
return smart_unicode(field.value_to_string(obj))
|
2006-08-31 12:11:46 +08:00
|
|
|
|
2006-06-29 00:00:37 +08:00
|
|
|
def start_serialization(self):
|
|
|
|
"""
|
|
|
|
Called when serializing of the queryset starts.
|
|
|
|
"""
|
|
|
|
raise NotImplementedError
|
2006-08-31 12:11:46 +08:00
|
|
|
|
2006-06-29 00:00:37 +08:00
|
|
|
def end_serialization(self):
|
|
|
|
"""
|
|
|
|
Called when serializing of the queryset ends.
|
|
|
|
"""
|
|
|
|
pass
|
2006-08-31 12:11:46 +08:00
|
|
|
|
2006-06-29 00:00:37 +08:00
|
|
|
def start_object(self, obj):
|
|
|
|
"""
|
|
|
|
Called when serializing of an object starts.
|
|
|
|
"""
|
|
|
|
raise NotImplementedError
|
2006-08-31 12:11:46 +08:00
|
|
|
|
2006-06-29 00:00:37 +08:00
|
|
|
def end_object(self, obj):
|
|
|
|
"""
|
|
|
|
Called when serializing of an object ends.
|
|
|
|
"""
|
|
|
|
pass
|
2006-08-31 12:11:46 +08:00
|
|
|
|
2006-06-29 00:00:37 +08:00
|
|
|
def handle_field(self, obj, field):
|
|
|
|
"""
|
|
|
|
Called to handle each individual (non-relational) field on an object.
|
|
|
|
"""
|
|
|
|
raise NotImplementedError
|
2006-08-31 12:11:46 +08:00
|
|
|
|
2006-06-29 00:00:37 +08:00
|
|
|
def handle_fk_field(self, obj, field):
|
|
|
|
"""
|
|
|
|
Called to handle a ForeignKey field.
|
|
|
|
"""
|
|
|
|
raise NotImplementedError
|
2006-08-31 12:11:46 +08:00
|
|
|
|
2006-06-29 00:00:37 +08:00
|
|
|
def handle_m2m_field(self, obj, field):
|
|
|
|
"""
|
|
|
|
Called to handle a ManyToManyField.
|
|
|
|
"""
|
|
|
|
raise NotImplementedError
|
2006-08-31 12:11:46 +08:00
|
|
|
|
2006-06-29 00:00:37 +08:00
|
|
|
def getvalue(self):
|
|
|
|
"""
|
2007-04-25 18:12:05 +08:00
|
|
|
Return the fully serialized queryset (or None if the output stream is
|
|
|
|
not seekable).
|
2006-06-29 00:00:37 +08:00
|
|
|
"""
|
2007-04-25 18:12:05 +08:00
|
|
|
if callable(getattr(self.stream, 'getvalue', None)):
|
|
|
|
return self.stream.getvalue()
|
2006-06-29 00:00:37 +08:00
|
|
|
|
|
|
|
class Deserializer(object):
|
|
|
|
"""
|
|
|
|
Abstract base deserializer class.
|
|
|
|
"""
|
2006-08-31 12:11:46 +08:00
|
|
|
|
2006-06-29 00:00:37 +08:00
|
|
|
def __init__(self, stream_or_string, **options):
|
|
|
|
"""
|
|
|
|
Init this serializer given a stream or a string
|
|
|
|
"""
|
|
|
|
self.options = options
|
|
|
|
if isinstance(stream_or_string, basestring):
|
|
|
|
self.stream = StringIO(stream_or_string)
|
|
|
|
else:
|
|
|
|
self.stream = stream_or_string
|
|
|
|
# hack to make sure that the models have all been loaded before
|
|
|
|
# deserialization starts (otherwise subclass calls to get_model()
|
|
|
|
# and friends might fail...)
|
|
|
|
models.get_apps()
|
2006-08-31 12:11:46 +08:00
|
|
|
|
2006-06-29 00:00:37 +08:00
|
|
|
def __iter__(self):
|
|
|
|
return self
|
2006-08-31 12:11:46 +08:00
|
|
|
|
2006-06-29 00:00:37 +08:00
|
|
|
def next(self):
|
|
|
|
"""Iteration iterface -- return the next item in the stream"""
|
|
|
|
raise NotImplementedError
|
2006-08-31 12:11:46 +08:00
|
|
|
|
2006-06-29 00:00:37 +08:00
|
|
|
class DeserializedObject(object):
|
|
|
|
"""
|
2007-03-01 21:11:08 +08:00
|
|
|
A deserialized model.
|
2006-08-31 12:11:46 +08:00
|
|
|
|
2006-06-29 00:00:37 +08:00
|
|
|
Basically a container for holding the pre-saved deserialized data along
|
|
|
|
with the many-to-many data saved with the object.
|
2006-08-31 12:11:46 +08:00
|
|
|
|
2006-06-29 00:00:37 +08:00
|
|
|
Call ``save()`` to save the object (with the many-to-many data) to the
|
|
|
|
database; call ``save(save_m2m=False)`` to save just the object fields
|
|
|
|
(and not touch the many-to-many stuff.)
|
|
|
|
"""
|
2006-08-31 12:11:46 +08:00
|
|
|
|
2006-06-29 00:00:37 +08:00
|
|
|
def __init__(self, obj, m2m_data=None):
|
|
|
|
self.object = obj
|
|
|
|
self.m2m_data = m2m_data
|
2006-08-31 12:11:46 +08:00
|
|
|
|
2006-06-29 00:00:37 +08:00
|
|
|
def __repr__(self):
|
2009-12-22 23:18:51 +08:00
|
|
|
return "<DeserializedObject: %s.%s(pk=%s)>" % (
|
|
|
|
self.object._meta.app_label, self.object._meta.object_name, self.object.pk)
|
2006-08-31 12:11:46 +08:00
|
|
|
|
2009-12-22 23:18:51 +08:00
|
|
|
def save(self, save_m2m=True, using=None):
|
2008-03-18 22:35:05 +08:00
|
|
|
# Call save on the Model baseclass directly. This bypasses any
|
2007-07-12 15:45:35 +08:00
|
|
|
# model-defined save. The save is also forced to be raw.
|
2008-03-18 22:35:05 +08:00
|
|
|
# This ensures that the data that is deserialized is literally
|
2007-07-12 15:45:35 +08:00
|
|
|
# what came from the file, not post-processed by pre_save/save
|
|
|
|
# methods.
|
2009-12-22 23:18:51 +08:00
|
|
|
models.Model.save_base(self.object, using=using, raw=True)
|
2006-06-29 00:00:37 +08:00
|
|
|
if self.m2m_data and save_m2m:
|
|
|
|
for accessor_name, object_list in self.m2m_data.items():
|
|
|
|
setattr(self.object, accessor_name, object_list)
|
2006-08-31 12:11:46 +08:00
|
|
|
|
|
|
|
# prevent a second (possibly accidental) call to save() from saving
|
2006-06-29 00:00:37 +08:00
|
|
|
# the m2m data twice.
|
|
|
|
self.m2m_data = None
|