summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell Keith-Magee <russell@keith-magee.com>2008-08-12 12:58:33 +0000
committerRussell Keith-Magee <russell@keith-magee.com>2008-08-12 12:58:33 +0000
commit63ea57642dd980ff07627964efd445986bc9fe58 (patch)
treef385b7587e4b207fd4351be6447843d24f41b552
parentdd970bfbfd3bd9a4954ae3bc0879842198903742 (diff)
Fixed #8134 -- Corrected serialization of m2m fields with intermediate models. Thanks to Rock Howard for the report, and kire for the test case.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@8321 bcc190cf-cafb-0310-a4f2-bffc1f526a37
-rw-r--r--django/core/serializers/python.py5
-rw-r--r--django/core/serializers/xml_serializer.py9
-rw-r--r--tests/regressiontests/m2m_through_regress/models.py144
-rw-r--r--tests/regressiontests/serializers_regress/models.py9
-rw-r--r--tests/regressiontests/serializers_regress/tests.py43
5 files changed, 201 insertions, 9 deletions
diff --git a/django/core/serializers/python.py b/django/core/serializers/python.py
index cedab06be9..c129c068df 100644
--- a/django/core/serializers/python.py
+++ b/django/core/serializers/python.py
@@ -49,8 +49,9 @@ class Serializer(base.Serializer):
self._current[field.name] = smart_unicode(related, strings_only=True)
def handle_m2m_field(self, obj, field):
- self._current[field.name] = [smart_unicode(related._get_pk_val(), strings_only=True)
- for related in getattr(obj, field.name).iterator()]
+ if field.creates_table:
+ self._current[field.name] = [smart_unicode(related._get_pk_val(), strings_only=True)
+ for related in getattr(obj, field.name).iterator()]
def getvalue(self):
return self.objects
diff --git a/django/core/serializers/xml_serializer.py b/django/core/serializers/xml_serializer.py
index 667faf7c5e..04498db00c 100644
--- a/django/core/serializers/xml_serializer.py
+++ b/django/core/serializers/xml_serializer.py
@@ -100,10 +100,11 @@ class Serializer(base.Serializer):
serialized as references to the object's PK (i.e. the related *data*
is not dumped, just the relation).
"""
- self._start_relational_field(field)
- for relobj in getattr(obj, field.name).iterator():
- self.xml.addQuickElement("object", attrs={"pk" : smart_unicode(relobj._get_pk_val())})
- self.xml.endElement("field")
+ if field.creates_table:
+ self._start_relational_field(field)
+ for relobj in getattr(obj, field.name).iterator():
+ self.xml.addQuickElement("object", attrs={"pk" : smart_unicode(relobj._get_pk_val())})
+ self.xml.endElement("field")
def _start_relational_field(self, field):
"""
diff --git a/tests/regressiontests/m2m_through_regress/models.py b/tests/regressiontests/m2m_through_regress/models.py
index bb9073a172..eed0cc1b5f 100644
--- a/tests/regressiontests/m2m_through_regress/models.py
+++ b/tests/regressiontests/m2m_through_regress/models.py
@@ -1,12 +1,13 @@
-from django.db import models
from datetime import datetime
from django.contrib.auth.models import User
+from django.core import management
+from django.db import models
# Forward declared intermediate model
class Membership(models.Model):
person = models.ForeignKey('Person')
group = models.ForeignKey('Group')
- date_joined = models.DateTimeField(default=datetime.now)
+ price = models.IntegerField(default=100)
def __unicode__(self):
return "%s is a member of %s" % (self.person.name, self.group.name)
@@ -14,7 +15,7 @@ class Membership(models.Model):
class UserMembership(models.Model):
user = models.ForeignKey(User)
group = models.ForeignKey('Group')
- date_joined = models.DateTimeField(default=datetime.now)
+ price = models.IntegerField(default=100)
def __unicode__(self):
return "%s is a user and member of %s" % (self.user.username, self.group.name)
@@ -99,4 +100,141 @@ AttributeError: Cannot use create() on a ManyToManyField which specifies an inte
>>> roll.user_members.all()
[<User: frank>]
+# Regression test for #8134 --
+# m2m-through models shouldn't be serialized as m2m fields on the model.
+# Dump the current contents of the database as a JSON fixture
+>>> management.call_command('dumpdata', 'm2m_through_regress', format='json', indent=2)
+[
+ {
+ "pk": 1,
+ "model": "m2m_through_regress.membership",
+ "fields": {
+ "person": 1,
+ "price": 100,
+ "group": 1
+ }
+ },
+ {
+ "pk": 2,
+ "model": "m2m_through_regress.membership",
+ "fields": {
+ "person": 1,
+ "price": 100,
+ "group": 2
+ }
+ },
+ {
+ "pk": 3,
+ "model": "m2m_through_regress.membership",
+ "fields": {
+ "person": 2,
+ "price": 100,
+ "group": 1
+ }
+ },
+ {
+ "pk": 1,
+ "model": "m2m_through_regress.usermembership",
+ "fields": {
+ "price": 100,
+ "group": 1,
+ "user": 1
+ }
+ },
+ {
+ "pk": 2,
+ "model": "m2m_through_regress.usermembership",
+ "fields": {
+ "price": 100,
+ "group": 2,
+ "user": 1
+ }
+ },
+ {
+ "pk": 3,
+ "model": "m2m_through_regress.usermembership",
+ "fields": {
+ "price": 100,
+ "group": 1,
+ "user": 2
+ }
+ },
+ {
+ "pk": 1,
+ "model": "m2m_through_regress.person",
+ "fields": {
+ "name": "Bob"
+ }
+ },
+ {
+ "pk": 2,
+ "model": "m2m_through_regress.person",
+ "fields": {
+ "name": "Jim"
+ }
+ },
+ {
+ "pk": 1,
+ "model": "m2m_through_regress.group",
+ "fields": {
+ "name": "Rock"
+ }
+ },
+ {
+ "pk": 2,
+ "model": "m2m_through_regress.group",
+ "fields": {
+ "name": "Roll"
+ }
+ }
+]
+
+# Check the XML serializer too, since it doesn't use the common implementation
+>>> management.call_command('dumpdata', 'm2m_through_regress', format='xml', indent=2)
+<?xml version="1.0" encoding="utf-8"?>
+<django-objects version="1.0">
+ <object pk="1" model="m2m_through_regress.membership">
+ <field to="m2m_through_regress.person" name="person" rel="ManyToOneRel">1</field>
+ <field to="m2m_through_regress.group" name="group" rel="ManyToOneRel">1</field>
+ <field type="IntegerField" name="price">100</field>
+ </object>
+ <object pk="2" model="m2m_through_regress.membership">
+ <field to="m2m_through_regress.person" name="person" rel="ManyToOneRel">1</field>
+ <field to="m2m_through_regress.group" name="group" rel="ManyToOneRel">2</field>
+ <field type="IntegerField" name="price">100</field>
+ </object>
+ <object pk="3" model="m2m_through_regress.membership">
+ <field to="m2m_through_regress.person" name="person" rel="ManyToOneRel">2</field>
+ <field to="m2m_through_regress.group" name="group" rel="ManyToOneRel">1</field>
+ <field type="IntegerField" name="price">100</field>
+ </object>
+ <object pk="1" model="m2m_through_regress.usermembership">
+ <field to="auth.user" name="user" rel="ManyToOneRel">1</field>
+ <field to="m2m_through_regress.group" name="group" rel="ManyToOneRel">1</field>
+ <field type="IntegerField" name="price">100</field>
+ </object>
+ <object pk="2" model="m2m_through_regress.usermembership">
+ <field to="auth.user" name="user" rel="ManyToOneRel">1</field>
+ <field to="m2m_through_regress.group" name="group" rel="ManyToOneRel">2</field>
+ <field type="IntegerField" name="price">100</field>
+ </object>
+ <object pk="3" model="m2m_through_regress.usermembership">
+ <field to="auth.user" name="user" rel="ManyToOneRel">2</field>
+ <field to="m2m_through_regress.group" name="group" rel="ManyToOneRel">1</field>
+ <field type="IntegerField" name="price">100</field>
+ </object>
+ <object pk="1" model="m2m_through_regress.person">
+ <field type="CharField" name="name">Bob</field>
+ </object>
+ <object pk="2" model="m2m_through_regress.person">
+ <field type="CharField" name="name">Jim</field>
+ </object>
+ <object pk="1" model="m2m_through_regress.group">
+ <field type="CharField" name="name">Rock</field>
+ </object>
+ <object pk="2" model="m2m_through_regress.group">
+ <field type="CharField" name="name">Roll</field>
+ </object>
+</django-objects>
+
"""} \ No newline at end of file
diff --git a/tests/regressiontests/serializers_regress/models.py b/tests/regressiontests/serializers_regress/models.py
index 4e2fbb1ee2..d2c06234fb 100644
--- a/tests/regressiontests/serializers_regress/models.py
+++ b/tests/regressiontests/serializers_regress/models.py
@@ -132,6 +132,14 @@ class FKDataToField(models.Model):
class FKDataToO2O(models.Model):
data = models.ForeignKey(O2OData, null=True)
+class M2MIntermediateData(models.Model):
+ data = models.ManyToManyField(Anchor, null=True, through='Intermediate')
+
+class Intermediate(models.Model):
+ left = models.ForeignKey(M2MIntermediateData)
+ right = models.ForeignKey(Anchor)
+ extra = models.CharField(max_length=30, blank=True, default="doesn't matter")
+
# The following test classes are for validating the
# deserialization of objects that use a user-defined
# field as the primary key.
@@ -243,3 +251,4 @@ class InheritBaseModel(BaseModel):
class ExplicitInheritBaseModel(BaseModel):
parent = models.OneToOneField(BaseModel)
child_data = models.IntegerField()
+ \ No newline at end of file
diff --git a/tests/regressiontests/serializers_regress/tests.py b/tests/regressiontests/serializers_regress/tests.py
index 7a38af4cf9..e49ab9de5c 100644
--- a/tests/regressiontests/serializers_regress/tests.py
+++ b/tests/regressiontests/serializers_regress/tests.py
@@ -54,6 +54,20 @@ def m2m_create(pk, klass, data):
instance.data = data
return [instance]
+def im2m_create(pk, klass, data):
+ instance = klass(id=pk)
+ models.Model.save_base(instance, raw=True)
+ return [instance]
+
+def im_create(pk, klass, data):
+ instance = klass(id=pk)
+ setattr(instance, 'right_id', data['right'])
+ setattr(instance, 'left_id', data['left'])
+ if 'extra' in data:
+ setattr(instance, 'extra', data['extra'])
+ models.Model.save_base(instance, raw=True)
+ return [instance]
+
def o2o_create(pk, klass, data):
instance = klass()
instance.data_id = data
@@ -99,6 +113,19 @@ def m2m_compare(testcase, pk, klass, data):
instance = klass.objects.get(id=pk)
testcase.assertEqual(data, [obj.id for obj in instance.data.all()])
+def im2m_compare(testcase, pk, klass, data):
+ instance = klass.objects.get(id=pk)
+ #actually nothing else to check, the instance just should exist
+
+def im_compare(testcase, pk, klass, data):
+ instance = klass.objects.get(id=pk)
+ testcase.assertEqual(data['left'], instance.left_id)
+ testcase.assertEqual(data['right'], instance.right_id)
+ if 'extra' in data:
+ testcase.assertEqual(data['extra'], instance.extra)
+ else:
+ testcase.assertEqual("doesn't matter", instance.extra)
+
def o2o_compare(testcase, pk, klass, data):
instance = klass.objects.get(data=data)
testcase.assertEqual(data, instance.data_id)
@@ -119,6 +146,8 @@ data_obj = (data_create, data_compare)
generic_obj = (generic_create, generic_compare)
fk_obj = (fk_create, fk_compare)
m2m_obj = (m2m_create, m2m_compare)
+im2m_obj = (im2m_create, im2m_compare)
+im_obj = (im_create, im_compare)
o2o_obj = (o2o_create, o2o_compare)
pk_obj = (pk_create, pk_compare)
inherited_obj = (inherited_create, inherited_compare)
@@ -231,6 +260,20 @@ The end."""),
(fk_obj, 452, FKDataToField, None),
(fk_obj, 460, FKDataToO2O, 300),
+
+ (im2m_obj, 470, M2MIntermediateData, None),
+
+ #testing post- and prereferences and extra fields
+ (im_obj, 480, Intermediate, {'right': 300, 'left': 470}),
+ (im_obj, 481, Intermediate, {'right': 300, 'left': 490}),
+ (im_obj, 482, Intermediate, {'right': 500, 'left': 470}),
+ (im_obj, 483, Intermediate, {'right': 500, 'left': 490}),
+ (im_obj, 484, Intermediate, {'right': 300, 'left': 470, 'extra': "extra"}),
+ (im_obj, 485, Intermediate, {'right': 300, 'left': 490, 'extra': "extra"}),
+ (im_obj, 486, Intermediate, {'right': 500, 'left': 470, 'extra': "extra"}),
+ (im_obj, 487, Intermediate, {'right': 500, 'left': 490, 'extra': "extra"}),
+
+ (im2m_obj, 490, M2MIntermediateData, []),
(data_obj, 500, Anchor, "Anchor 3"),
(data_obj, 501, Anchor, "Anchor 4"),