mirror of
https://github.com/django/django.git
synced 2025-10-31 09:41:08 +00:00
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
This commit is contained in:
@@ -6,7 +6,7 @@ Usage::
|
||||
>>> from django.core import serializers
|
||||
>>> json = serializers.serialize("json", some_query_set)
|
||||
>>> objects = list(serializers.deserialize("json", json))
|
||||
|
||||
|
||||
To add your own serializers, use the SERIALIZATION_MODULES setting::
|
||||
|
||||
SERIALIZATION_MODULES = {
|
||||
@@ -30,19 +30,19 @@ try:
|
||||
import yaml
|
||||
BUILTIN_SERIALIZERS["yaml"] = "django.core.serializers.pyyaml"
|
||||
except ImportError:
|
||||
pass
|
||||
pass
|
||||
|
||||
_serializers = {}
|
||||
|
||||
|
||||
def register_serializer(format, serializer_module):
|
||||
"""Register a new serializer by passing in a module name."""
|
||||
module = __import__(serializer_module, {}, {}, [''])
|
||||
_serializers[format] = module
|
||||
|
||||
|
||||
def unregister_serializer(format):
|
||||
"""Unregister a given serializer"""
|
||||
del _serializers[format]
|
||||
|
||||
|
||||
def get_serializer(format):
|
||||
if not _serializers:
|
||||
_load_serializers()
|
||||
@@ -52,12 +52,12 @@ def get_serializer_formats():
|
||||
if not _serializers:
|
||||
_load_serializers()
|
||||
return _serializers.keys()
|
||||
|
||||
|
||||
def get_deserializer(format):
|
||||
if not _serializers:
|
||||
_load_serializers()
|
||||
return _serializers[format].Deserializer
|
||||
|
||||
|
||||
def serialize(format, queryset, **options):
|
||||
"""
|
||||
Serialize a queryset (or any iterator that returns database objects) using
|
||||
@@ -87,4 +87,4 @@ def _load_serializers():
|
||||
register_serializer(format, BUILTIN_SERIALIZERS[format])
|
||||
if hasattr(settings, "SERIALIZATION_MODULES"):
|
||||
for format in settings.SERIALIZATION_MODULES:
|
||||
register_serializer(format, settings.SERIALIZATION_MODULES[format])
|
||||
register_serializer(format, settings.SERIALIZATION_MODULES[format])
|
||||
|
||||
@@ -7,6 +7,7 @@ try:
|
||||
except ImportError:
|
||||
from StringIO import StringIO
|
||||
from django.db import models
|
||||
from django.utils.encoding import smart_str, smart_unicode
|
||||
|
||||
class SerializationError(Exception):
|
||||
"""Something bad happened during serialization."""
|
||||
@@ -59,7 +60,7 @@ class Serializer(object):
|
||||
value = getattr(obj, "get_%s_url" % field.name, lambda: None)()
|
||||
else:
|
||||
value = field.flatten_data(follow=None, obj=obj).get(field.name, "")
|
||||
return str(value)
|
||||
return smart_unicode(value)
|
||||
|
||||
def start_serialization(self):
|
||||
"""
|
||||
@@ -154,7 +155,7 @@ class DeserializedObject(object):
|
||||
self.m2m_data = m2m_data
|
||||
|
||||
def __repr__(self):
|
||||
return "<DeserializedObject: %s>" % str(self.object)
|
||||
return "<DeserializedObject: %s>" % smart_str(self.object)
|
||||
|
||||
def save(self, save_m2m=True):
|
||||
self.object.save()
|
||||
|
||||
@@ -7,33 +7,34 @@ other serializers.
|
||||
from django.conf import settings
|
||||
from django.core.serializers import base
|
||||
from django.db import models
|
||||
from django.utils.encoding import smart_unicode
|
||||
|
||||
class Serializer(base.Serializer):
|
||||
"""
|
||||
Serializes a QuerySet to basic Python objects.
|
||||
"""
|
||||
|
||||
|
||||
def start_serialization(self):
|
||||
self._current = None
|
||||
self.objects = []
|
||||
|
||||
|
||||
def end_serialization(self):
|
||||
pass
|
||||
|
||||
|
||||
def start_object(self, obj):
|
||||
self._current = {}
|
||||
|
||||
|
||||
def end_object(self, obj):
|
||||
self.objects.append({
|
||||
"model" : str(obj._meta),
|
||||
"pk" : str(obj._get_pk_val()),
|
||||
"model" : smart_unicode(obj._meta),
|
||||
"pk" : smart_unicode(obj._get_pk_val()),
|
||||
"fields" : self._current
|
||||
})
|
||||
self._current = None
|
||||
|
||||
|
||||
def handle_field(self, obj, field):
|
||||
self._current[field.name] = getattr(obj, field.name)
|
||||
|
||||
|
||||
def handle_fk_field(self, obj, field):
|
||||
related = getattr(obj, field.name)
|
||||
if related is not None:
|
||||
@@ -44,17 +45,17 @@ class Serializer(base.Serializer):
|
||||
# Related to remote object via other field
|
||||
related = getattr(related, field.rel.field_name)
|
||||
self._current[field.name] = related
|
||||
|
||||
|
||||
def handle_m2m_field(self, obj, field):
|
||||
self._current[field.name] = [related._get_pk_val() for related in getattr(obj, field.name).iterator()]
|
||||
|
||||
|
||||
def getvalue(self):
|
||||
return self.objects
|
||||
|
||||
def Deserializer(object_list, **options):
|
||||
"""
|
||||
Deserialize simple Python objects back into Django ORM instances.
|
||||
|
||||
|
||||
It's expected that you pass the Python objects themselves (instead of a
|
||||
stream or a string) to the constructor
|
||||
"""
|
||||
@@ -64,36 +65,30 @@ def Deserializer(object_list, **options):
|
||||
Model = _get_model(d["model"])
|
||||
data = {Model._meta.pk.attname : Model._meta.pk.to_python(d["pk"])}
|
||||
m2m_data = {}
|
||||
|
||||
|
||||
# Handle each field
|
||||
for (field_name, field_value) in d["fields"].iteritems():
|
||||
if isinstance(field_value, unicode):
|
||||
field_value = field_value.encode(options.get("encoding", settings.DEFAULT_CHARSET))
|
||||
|
||||
if isinstance(field_value, str):
|
||||
field_value = smart_unicode(field_value, options.get("encoding", settings.DEFAULT_CHARSET), strings_only=True)
|
||||
|
||||
field = Model._meta.get_field(field_name)
|
||||
|
||||
|
||||
# Handle M2M relations
|
||||
if field.rel and isinstance(field.rel, models.ManyToManyRel):
|
||||
pks = []
|
||||
m2m_convert = field.rel.to._meta.pk.to_python
|
||||
for pk in field_value:
|
||||
if isinstance(pk, unicode):
|
||||
pks.append(m2m_convert(pk.encode(options.get("encoding", settings.DEFAULT_CHARSET))))
|
||||
else:
|
||||
pks.append(m2m_convert(pk))
|
||||
m2m_data[field.name] = pks
|
||||
|
||||
m2m_data[field.name] = [m2m_convert(smart_unicode(pk)) for pk in field_value]
|
||||
|
||||
# Handle FK fields
|
||||
elif field.rel and isinstance(field.rel, models.ManyToOneRel):
|
||||
if field_value:
|
||||
data[field.attname] = field.rel.to._meta.get_field(field.rel.field_name).to_python(field_value)
|
||||
else:
|
||||
data[field.attname] = None
|
||||
|
||||
|
||||
# Handle all other fields
|
||||
else:
|
||||
data[field.name] = field.to_python(field_value)
|
||||
|
||||
|
||||
yield base.DeserializedObject(Model(**data), m2m_data)
|
||||
|
||||
def _get_model(model_identifier):
|
||||
@@ -105,5 +100,5 @@ def _get_model(model_identifier):
|
||||
except TypeError:
|
||||
Model = None
|
||||
if Model is None:
|
||||
raise base.DeserializationError("Invalid model identifier: '%s'" % model_identifier)
|
||||
raise base.DeserializationError(u"Invalid model identifier: '%s'" % model_identifier)
|
||||
return Model
|
||||
|
||||
@@ -21,7 +21,7 @@ class Serializer(PythonSerializer):
|
||||
self.options.pop('stream', None)
|
||||
self.options.pop('fields', None)
|
||||
yaml.dump(self.objects, self.stream, **self.options)
|
||||
|
||||
|
||||
def getvalue(self):
|
||||
return self.stream.getvalue()
|
||||
|
||||
@@ -35,4 +35,4 @@ def Deserializer(stream_or_string, **options):
|
||||
stream = stream_or_string
|
||||
for obj in PythonDeserializer(yaml.load(stream)):
|
||||
yield obj
|
||||
|
||||
|
||||
|
||||
@@ -6,13 +6,14 @@ from django.conf import settings
|
||||
from django.core.serializers import base
|
||||
from django.db import models
|
||||
from django.utils.xmlutils import SimplerXMLGenerator
|
||||
from django.utils.encoding import smart_unicode
|
||||
from xml.dom import pulldom
|
||||
|
||||
class Serializer(base.Serializer):
|
||||
"""
|
||||
Serializes a QuerySet to XML.
|
||||
"""
|
||||
|
||||
|
||||
def indent(self, level):
|
||||
if self.options.get('indent', None) is not None:
|
||||
self.xml.ignorableWhitespace('\n' + ' ' * self.options.get('indent', None) * level)
|
||||
@@ -24,7 +25,7 @@ class Serializer(base.Serializer):
|
||||
self.xml = SimplerXMLGenerator(self.stream, self.options.get("encoding", settings.DEFAULT_CHARSET))
|
||||
self.xml.startDocument()
|
||||
self.xml.startElement("django-objects", {"version" : "1.0"})
|
||||
|
||||
|
||||
def end_serialization(self):
|
||||
"""
|
||||
End serialization -- end the document.
|
||||
@@ -32,27 +33,27 @@ class Serializer(base.Serializer):
|
||||
self.indent(0)
|
||||
self.xml.endElement("django-objects")
|
||||
self.xml.endDocument()
|
||||
|
||||
|
||||
def start_object(self, obj):
|
||||
"""
|
||||
Called as each object is handled.
|
||||
"""
|
||||
if not hasattr(obj, "_meta"):
|
||||
raise base.SerializationError("Non-model object (%s) encountered during serialization" % type(obj))
|
||||
|
||||
|
||||
self.indent(1)
|
||||
self.xml.startElement("object", {
|
||||
"pk" : str(obj._get_pk_val()),
|
||||
"model" : str(obj._meta),
|
||||
"pk" : smart_unicode(obj._get_pk_val()),
|
||||
"model" : smart_unicode(obj._meta),
|
||||
})
|
||||
|
||||
|
||||
def end_object(self, obj):
|
||||
"""
|
||||
Called after handling all fields for an object.
|
||||
"""
|
||||
self.indent(1)
|
||||
self.xml.endElement("object")
|
||||
|
||||
|
||||
def handle_field(self, obj, field):
|
||||
"""
|
||||
Called to handle each field on an object (except for ForeignKeys and
|
||||
@@ -63,17 +64,17 @@ class Serializer(base.Serializer):
|
||||
"name" : field.name,
|
||||
"type" : field.get_internal_type()
|
||||
})
|
||||
|
||||
|
||||
# Get a "string version" of the object's data (this is handled by the
|
||||
# serializer base class).
|
||||
# serializer base class).
|
||||
if getattr(obj, field.name) is not None:
|
||||
value = self.get_string_value(obj, field)
|
||||
self.xml.characters(str(value))
|
||||
self.xml.characters(smart_unicode(value))
|
||||
else:
|
||||
self.xml.addQuickElement("None")
|
||||
|
||||
self.xml.endElement("field")
|
||||
|
||||
|
||||
def handle_fk_field(self, obj, field):
|
||||
"""
|
||||
Called to handle a ForeignKey (we need to treat them slightly
|
||||
@@ -88,11 +89,11 @@ class Serializer(base.Serializer):
|
||||
else:
|
||||
# Related to remote object via other field
|
||||
related = getattr(related, field.rel.field_name)
|
||||
self.xml.characters(str(related))
|
||||
self.xml.characters(smart_unicode(related))
|
||||
else:
|
||||
self.xml.addQuickElement("None")
|
||||
self.xml.endElement("field")
|
||||
|
||||
|
||||
def handle_m2m_field(self, obj, field):
|
||||
"""
|
||||
Called to handle a ManyToManyField. Related objects are only
|
||||
@@ -101,9 +102,9 @@ class Serializer(base.Serializer):
|
||||
"""
|
||||
self._start_relational_field(field)
|
||||
for relobj in getattr(obj, field.name).iterator():
|
||||
self.xml.addQuickElement("object", attrs={"pk" : str(relobj._get_pk_val())})
|
||||
self.xml.addQuickElement("object", attrs={"pk" : smart_unicode(relobj._get_pk_val())})
|
||||
self.xml.endElement("field")
|
||||
|
||||
|
||||
def _start_relational_field(self, field):
|
||||
"""
|
||||
Helper to output the <field> element for relational fields
|
||||
@@ -112,33 +113,33 @@ class Serializer(base.Serializer):
|
||||
self.xml.startElement("field", {
|
||||
"name" : field.name,
|
||||
"rel" : field.rel.__class__.__name__,
|
||||
"to" : str(field.rel.to._meta),
|
||||
"to" : smart_unicode(field.rel.to._meta),
|
||||
})
|
||||
|
||||
|
||||
class Deserializer(base.Deserializer):
|
||||
"""
|
||||
Deserialize XML.
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self, stream_or_string, **options):
|
||||
super(Deserializer, self).__init__(stream_or_string, **options)
|
||||
self.encoding = self.options.get("encoding", settings.DEFAULT_CHARSET)
|
||||
self.event_stream = pulldom.parse(self.stream)
|
||||
|
||||
self.event_stream = pulldom.parse(self.stream)
|
||||
|
||||
def next(self):
|
||||
for event, node in self.event_stream:
|
||||
if event == "START_ELEMENT" and node.nodeName == "object":
|
||||
self.event_stream.expandNode(node)
|
||||
return self._handle_object(node)
|
||||
raise StopIteration
|
||||
|
||||
|
||||
def _handle_object(self, node):
|
||||
"""
|
||||
Convert an <object> node to a DeserializedObject.
|
||||
"""
|
||||
# Look up the model using the model loading mechanism. If this fails, bail.
|
||||
# Look up the model using the model loading mechanism. If this fails,
|
||||
# bail.
|
||||
Model = self._get_model_from_node(node, "model")
|
||||
|
||||
|
||||
# Start building a data dictionary from the object. If the node is
|
||||
# missing the pk attribute, bail.
|
||||
pk = node.getAttribute("pk")
|
||||
@@ -146,11 +147,11 @@ class Deserializer(base.Deserializer):
|
||||
raise base.DeserializationError("<object> node is missing the 'pk' attribute")
|
||||
|
||||
data = {Model._meta.pk.attname : Model._meta.pk.to_python(pk)}
|
||||
|
||||
|
||||
# Also start building a dict of m2m data (this is saved as
|
||||
# {m2m_accessor_attribute : [list_of_related_objects]})
|
||||
m2m_data = {}
|
||||
|
||||
|
||||
# Deseralize each field.
|
||||
for field_node in node.getElementsByTagName("field"):
|
||||
# If the field is missing the name attribute, bail (are you
|
||||
@@ -158,12 +159,12 @@ class Deserializer(base.Deserializer):
|
||||
field_name = field_node.getAttribute("name")
|
||||
if not field_name:
|
||||
raise base.DeserializationError("<field> node is missing the 'name' attribute")
|
||||
|
||||
|
||||
# Get the field from the Model. This will raise a
|
||||
# FieldDoesNotExist if, well, the field doesn't exist, which will
|
||||
# be propagated correctly.
|
||||
field = Model._meta.get_field(field_name)
|
||||
|
||||
|
||||
# As is usually the case, relation fields get the special treatment.
|
||||
if field.rel and isinstance(field.rel, models.ManyToManyRel):
|
||||
m2m_data[field.name] = self._handle_m2m_field_node(field_node, field)
|
||||
@@ -173,12 +174,12 @@ class Deserializer(base.Deserializer):
|
||||
if len(field_node.childNodes) == 1 and field_node.childNodes[0].nodeName == 'None':
|
||||
value = None
|
||||
else:
|
||||
value = field.to_python(getInnerText(field_node).strip().encode(self.encoding))
|
||||
value = field.to_python(getInnerText(field_node).strip())
|
||||
data[field.name] = value
|
||||
|
||||
|
||||
# Return a DeserializedObject so that the m2m data has a place to live.
|
||||
return base.DeserializedObject(Model(**data), m2m_data)
|
||||
|
||||
|
||||
def _handle_fk_field_node(self, node, field):
|
||||
"""
|
||||
Handle a <field> node for a ForeignKey
|
||||
@@ -188,16 +189,16 @@ class Deserializer(base.Deserializer):
|
||||
return None
|
||||
else:
|
||||
return field.rel.to._meta.get_field(field.rel.field_name).to_python(
|
||||
getInnerText(node).strip().encode(self.encoding))
|
||||
|
||||
getInnerText(node).strip())
|
||||
|
||||
def _handle_m2m_field_node(self, node, field):
|
||||
"""
|
||||
Handle a <field> node for a ManyToManyField
|
||||
Handle a <field> node for a ManyToManyField.
|
||||
"""
|
||||
return [field.rel.to._meta.pk.to_python(
|
||||
c.getAttribute("pk").encode(self.encoding))
|
||||
c.getAttribute("pk"))
|
||||
for c in node.getElementsByTagName("object")]
|
||||
|
||||
|
||||
def _get_model_from_node(self, node, attr):
|
||||
"""
|
||||
Helper to look up a model from a <object model=...> or a <field
|
||||
@@ -217,8 +218,8 @@ class Deserializer(base.Deserializer):
|
||||
"<%s> node has invalid model identifier: '%s'" % \
|
||||
(node.nodeName, model_identifier))
|
||||
return Model
|
||||
|
||||
|
||||
|
||||
|
||||
def getInnerText(node):
|
||||
"""
|
||||
Get all the inner text of a DOM node (recursively).
|
||||
@@ -232,4 +233,5 @@ def getInnerText(node):
|
||||
inner_text.extend(getInnerText(child))
|
||||
else:
|
||||
pass
|
||||
return "".join(inner_text)
|
||||
return u"".join(inner_text)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user