Fixed #3741 -- Fixed serialization of GenericRelations. Thanks for the report, Alexander Solovyov.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@4752 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
cb624b1377
commit
83bed03a59
|
@ -34,17 +34,17 @@ class Serializer(object):
|
||||||
for obj in queryset:
|
for obj in queryset:
|
||||||
self.start_object(obj)
|
self.start_object(obj)
|
||||||
for field in obj._meta.fields:
|
for field in obj._meta.fields:
|
||||||
if field is obj._meta.pk:
|
if field.serialize:
|
||||||
continue
|
if field.rel is None:
|
||||||
elif field.rel is None:
|
if self.selected_fields is None or field.attname in self.selected_fields:
|
||||||
if self.selected_fields is None or field.attname in self.selected_fields:
|
self.handle_field(obj, field)
|
||||||
self.handle_field(obj, field)
|
else:
|
||||||
else:
|
if self.selected_fields is None or field.attname[:-3] in self.selected_fields:
|
||||||
if self.selected_fields is None or field.attname[:-3] in self.selected_fields:
|
self.handle_fk_field(obj, field)
|
||||||
self.handle_fk_field(obj, field)
|
|
||||||
for field in obj._meta.many_to_many:
|
for field in obj._meta.many_to_many:
|
||||||
if self.selected_fields is None or field.attname in self.selected_fields:
|
if field.serialize:
|
||||||
self.handle_m2m_field(obj, field)
|
if self.selected_fields is None or field.attname in self.selected_fields:
|
||||||
|
self.handle_m2m_field(obj, field)
|
||||||
self.end_object(obj)
|
self.end_object(obj)
|
||||||
self.end_serialization()
|
self.end_serialization()
|
||||||
return self.getvalue()
|
return self.getvalue()
|
||||||
|
|
|
@ -67,7 +67,7 @@ class Field(object):
|
||||||
|
|
||||||
def __init__(self, verbose_name=None, name=None, primary_key=False,
|
def __init__(self, verbose_name=None, name=None, primary_key=False,
|
||||||
maxlength=None, unique=False, blank=False, null=False, db_index=False,
|
maxlength=None, unique=False, blank=False, null=False, db_index=False,
|
||||||
core=False, rel=None, default=NOT_PROVIDED, editable=True,
|
core=False, rel=None, default=NOT_PROVIDED, editable=True, serialize=True,
|
||||||
prepopulate_from=None, unique_for_date=None, unique_for_month=None,
|
prepopulate_from=None, unique_for_date=None, unique_for_month=None,
|
||||||
unique_for_year=None, validator_list=None, choices=None, radio_admin=None,
|
unique_for_year=None, validator_list=None, choices=None, radio_admin=None,
|
||||||
help_text='', db_column=None):
|
help_text='', db_column=None):
|
||||||
|
@ -78,6 +78,7 @@ class Field(object):
|
||||||
self.blank, self.null = blank, null
|
self.blank, self.null = blank, null
|
||||||
self.core, self.rel, self.default = core, rel, default
|
self.core, self.rel, self.default = core, rel, default
|
||||||
self.editable = editable
|
self.editable = editable
|
||||||
|
self.serialize = serialize
|
||||||
self.validator_list = validator_list or []
|
self.validator_list = validator_list or []
|
||||||
self.prepopulate_from = prepopulate_from
|
self.prepopulate_from = prepopulate_from
|
||||||
self.unique_for_date, self.unique_for_month = unique_for_date, unique_for_month
|
self.unique_for_date, self.unique_for_month = unique_for_date, unique_for_month
|
||||||
|
|
|
@ -94,6 +94,7 @@ class GenericRelation(RelatedField, Field):
|
||||||
|
|
||||||
kwargs['blank'] = True
|
kwargs['blank'] = True
|
||||||
kwargs['editable'] = False
|
kwargs['editable'] = False
|
||||||
|
kwargs['serialize'] = False
|
||||||
Field.__init__(self, **kwargs)
|
Field.__init__(self, **kwargs)
|
||||||
|
|
||||||
def get_manipulator_field_objs(self):
|
def get_manipulator_field_objs(self):
|
||||||
|
|
|
@ -84,6 +84,7 @@ class Options(object):
|
||||||
self.fields.insert(bisect(self.fields, field), field)
|
self.fields.insert(bisect(self.fields, field), field)
|
||||||
if not self.pk and field.primary_key:
|
if not self.pk and field.primary_key:
|
||||||
self.pk = field
|
self.pk = field
|
||||||
|
field.serialize = False
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '<Options for %s>' % self.object_name
|
return '<Options for %s>' % self.object_name
|
||||||
|
|
|
@ -6,7 +6,8 @@ This class sets up a model for each model field type
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.contrib.contenttypes.models import ContentType
|
||||||
|
|
||||||
# The following classes are for testing basic data
|
# The following classes are for testing basic data
|
||||||
# marshalling, including NULL values.
|
# marshalling, including NULL values.
|
||||||
|
|
||||||
|
@ -73,6 +74,22 @@ class USStateData(models.Model):
|
||||||
class XMLData(models.Model):
|
class XMLData(models.Model):
|
||||||
data = models.XMLField(null=True)
|
data = models.XMLField(null=True)
|
||||||
|
|
||||||
|
class Tag(models.Model):
|
||||||
|
"""A tag on an item."""
|
||||||
|
data = models.SlugField()
|
||||||
|
content_type = models.ForeignKey(ContentType)
|
||||||
|
object_id = models.PositiveIntegerField()
|
||||||
|
|
||||||
|
content_object = models.GenericForeignKey()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
ordering = ["data"]
|
||||||
|
|
||||||
|
class GenericData(models.Model):
|
||||||
|
data = models.CharField(maxlength=30)
|
||||||
|
|
||||||
|
tags = models.GenericRelation(Tag)
|
||||||
|
|
||||||
# The following test classes are all for validation
|
# The following test classes are all for validation
|
||||||
# of related objects; in particular, forward, backward,
|
# of related objects; in particular, forward, backward,
|
||||||
# and self references.
|
# and self references.
|
||||||
|
|
|
@ -24,6 +24,14 @@ def data_create(pk, klass, data):
|
||||||
instance.data = data
|
instance.data = data
|
||||||
instance.save()
|
instance.save()
|
||||||
return instance
|
return instance
|
||||||
|
|
||||||
|
def generic_create(pk, klass, data):
|
||||||
|
instance = klass(id=pk)
|
||||||
|
instance.data = data[0]
|
||||||
|
instance.save()
|
||||||
|
for tag in data[1:]:
|
||||||
|
instance.tags.create(data=tag)
|
||||||
|
return instance
|
||||||
|
|
||||||
def fk_create(pk, klass, data):
|
def fk_create(pk, klass, data):
|
||||||
instance = klass(id=pk)
|
instance = klass(id=pk)
|
||||||
|
@ -56,6 +64,11 @@ def data_compare(testcase, pk, klass, data):
|
||||||
testcase.assertEqual(data, instance.data,
|
testcase.assertEqual(data, instance.data,
|
||||||
"Objects with PK=%d not equal; expected '%s' (%s), got '%s' (%s)" % (pk,data, type(data), instance.data, type(instance.data)))
|
"Objects with PK=%d not equal; expected '%s' (%s), got '%s' (%s)" % (pk,data, type(data), instance.data, type(instance.data)))
|
||||||
|
|
||||||
|
def generic_compare(testcase, pk, klass, data):
|
||||||
|
instance = klass.objects.get(id=pk)
|
||||||
|
testcase.assertEqual(data[0], instance.data)
|
||||||
|
testcase.assertEqual(data[1:], [t.data for t in instance.tags.all()])
|
||||||
|
|
||||||
def fk_compare(testcase, pk, klass, data):
|
def fk_compare(testcase, pk, klass, data):
|
||||||
instance = klass.objects.get(id=pk)
|
instance = klass.objects.get(id=pk)
|
||||||
testcase.assertEqual(data, instance.data_id)
|
testcase.assertEqual(data, instance.data_id)
|
||||||
|
@ -76,6 +89,7 @@ def pk_compare(testcase, pk, klass, data):
|
||||||
# actually a pair of functions; one to create
|
# actually a pair of functions; one to create
|
||||||
# and one to compare objects of that type
|
# and one to compare objects of that type
|
||||||
data_obj = (data_create, data_compare)
|
data_obj = (data_create, data_compare)
|
||||||
|
generic_obj = (generic_create, generic_compare)
|
||||||
fk_obj = (fk_create, fk_compare)
|
fk_obj = (fk_create, fk_compare)
|
||||||
m2m_obj = (m2m_create, m2m_compare)
|
m2m_obj = (m2m_create, m2m_compare)
|
||||||
o2o_obj = (o2o_create, o2o_compare)
|
o2o_obj = (o2o_create, o2o_compare)
|
||||||
|
@ -140,6 +154,9 @@ The end."""),
|
||||||
(data_obj, 190, XMLData, "<foo></foo>"),
|
(data_obj, 190, XMLData, "<foo></foo>"),
|
||||||
(data_obj, 191, XMLData, None),
|
(data_obj, 191, XMLData, None),
|
||||||
|
|
||||||
|
(generic_obj, 200, GenericData, ['Generic Object 1', 'tag1', 'tag2']),
|
||||||
|
(generic_obj, 201, GenericData, ['Generic Object 2', 'tag2', 'tag3']),
|
||||||
|
|
||||||
(data_obj, 300, Anchor, "Anchor 1"),
|
(data_obj, 300, Anchor, "Anchor 1"),
|
||||||
(data_obj, 301, Anchor, "Anchor 2"),
|
(data_obj, 301, Anchor, "Anchor 2"),
|
||||||
|
|
||||||
|
@ -222,6 +239,9 @@ def serializerTest(format, self):
|
||||||
transaction.commit()
|
transaction.commit()
|
||||||
transaction.leave_transaction_management()
|
transaction.leave_transaction_management()
|
||||||
|
|
||||||
|
# Add the generic tagged objects to the object list
|
||||||
|
objects.extend(Tag.objects.all())
|
||||||
|
|
||||||
# Serialize the test database
|
# Serialize the test database
|
||||||
serialized_data = serializers.serialize(format, objects, indent=2)
|
serialized_data = serializers.serialize(format, objects, indent=2)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue