From 83bed03a5990ba90cd99c6b2ceedcaf3199626e2 Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Mon, 19 Mar 2007 11:57:53 +0000 Subject: [PATCH] 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 --- django/core/serializers/base.py | 20 +++++++++---------- django/db/models/fields/__init__.py | 3 ++- django/db/models/fields/generic.py | 1 + django/db/models/options.py | 1 + .../serializers_regress/models.py | 19 +++++++++++++++++- .../serializers_regress/tests.py | 20 +++++++++++++++++++ 6 files changed, 52 insertions(+), 12 deletions(-) diff --git a/django/core/serializers/base.py b/django/core/serializers/base.py index 7dde2a4faf..8e610ad240 100644 --- a/django/core/serializers/base.py +++ b/django/core/serializers/base.py @@ -34,17 +34,17 @@ class Serializer(object): for obj in queryset: self.start_object(obj) for field in obj._meta.fields: - if field is obj._meta.pk: - continue - elif 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) + 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) for field in obj._meta.many_to_many: - if self.selected_fields is None or field.attname in self.selected_fields: - self.handle_m2m_field(obj, field) + if field.serialize: + 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_serialization() return self.getvalue() diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py index 781e4cb9e9..3972de7d4a 100644 --- a/django/db/models/fields/__init__.py +++ b/django/db/models/fields/__init__.py @@ -67,7 +67,7 @@ class Field(object): def __init__(self, verbose_name=None, name=None, primary_key=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, unique_for_year=None, validator_list=None, choices=None, radio_admin=None, help_text='', db_column=None): @@ -78,6 +78,7 @@ class Field(object): self.blank, self.null = blank, null self.core, self.rel, self.default = core, rel, default self.editable = editable + self.serialize = serialize self.validator_list = validator_list or [] self.prepopulate_from = prepopulate_from self.unique_for_date, self.unique_for_month = unique_for_date, unique_for_month diff --git a/django/db/models/fields/generic.py b/django/db/models/fields/generic.py index 1ad8346e42..480ee689c9 100644 --- a/django/db/models/fields/generic.py +++ b/django/db/models/fields/generic.py @@ -94,6 +94,7 @@ class GenericRelation(RelatedField, Field): kwargs['blank'] = True kwargs['editable'] = False + kwargs['serialize'] = False Field.__init__(self, **kwargs) def get_manipulator_field_objs(self): diff --git a/django/db/models/options.py b/django/db/models/options.py index ff0d112d16..51cf0a019b 100644 --- a/django/db/models/options.py +++ b/django/db/models/options.py @@ -84,6 +84,7 @@ class Options(object): self.fields.insert(bisect(self.fields, field), field) if not self.pk and field.primary_key: self.pk = field + field.serialize = False def __repr__(self): return '' % self.object_name diff --git a/tests/regressiontests/serializers_regress/models.py b/tests/regressiontests/serializers_regress/models.py index b558050022..d3415ac1b9 100644 --- a/tests/regressiontests/serializers_regress/models.py +++ b/tests/regressiontests/serializers_regress/models.py @@ -6,7 +6,8 @@ This class sets up a model for each model field type """ from django.db import models - +from django.contrib.contenttypes.models import ContentType + # The following classes are for testing basic data # marshalling, including NULL values. @@ -73,6 +74,22 @@ class USStateData(models.Model): class XMLData(models.Model): 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 # of related objects; in particular, forward, backward, # and self references. diff --git a/tests/regressiontests/serializers_regress/tests.py b/tests/regressiontests/serializers_regress/tests.py index 008ccecc2c..97b3fbacbe 100644 --- a/tests/regressiontests/serializers_regress/tests.py +++ b/tests/regressiontests/serializers_regress/tests.py @@ -24,6 +24,14 @@ def data_create(pk, klass, data): instance.data = data instance.save() 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): instance = klass(id=pk) @@ -56,6 +64,11 @@ def data_compare(testcase, pk, klass, 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))) +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): instance = klass.objects.get(id=pk) 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 # and one to compare objects of that type data_obj = (data_create, data_compare) +generic_obj = (generic_create, generic_compare) fk_obj = (fk_create, fk_compare) m2m_obj = (m2m_create, m2m_compare) o2o_obj = (o2o_create, o2o_compare) @@ -140,6 +154,9 @@ The end."""), (data_obj, 190, XMLData, ""), (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, 301, Anchor, "Anchor 2"), @@ -222,6 +239,9 @@ def serializerTest(format, self): transaction.commit() transaction.leave_transaction_management() + # Add the generic tagged objects to the object list + objects.extend(Tag.objects.all()) + # Serialize the test database serialized_data = serializers.serialize(format, objects, indent=2)