Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #13030 -- Corrected natural key deserialization to subclasses. …

…Thanks to yishaibeeri for the report and test case.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@12804 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 10de2a837f580d76a480a9e0b974cecd2d1d26cb 1 parent be8a1f6
Russell Keith-Magee authored March 18, 2010
4  django/core/serializers/python.py
@@ -111,6 +111,10 @@ def m2m_convert(value):
111 111
                         if hasattr(field_value, '__iter__'):
112 112
                             obj = field.rel.to._default_manager.db_manager(db).get_by_natural_key(*field_value)
113 113
                             value = getattr(obj, field.rel.field_name)
  114
+                            # If this is a natural foreign key to an object that
  115
+                            # has a FK/O2O as the foreign key, use the FK value
  116
+                            if field.rel.to._meta.pk.rel:
  117
+                                value = value.pk
114 118
                         else:
115 119
                             value = field.rel.to._meta.get_field(field.rel.field_name).to_python(field_value)
116 120
                         data[field.attname] = value
4  django/core/serializers/xml_serializer.py
@@ -221,6 +221,10 @@ def _handle_fk_field_node(self, node, field):
221 221
                     field_value = [getInnerText(k).strip() for k in keys]
222 222
                     obj = field.rel.to._default_manager.db_manager(self.db).get_by_natural_key(*field_value)
223 223
                     obj_pk = getattr(obj, field.rel.field_name)
  224
+                    # If this is a natural foreign key to an object that
  225
+                    # has a FK/O2O as the foreign key, use the FK value
  226
+                    if field.rel.to._meta.pk.rel:
  227
+                        obj_pk = obj_pk.pk
224 228
                 else:
225 229
                     # Otherwise, treat like a normal PK
226 230
                     field_value = getInnerText(node).strip()
18  tests/regressiontests/fixtures_regress/fixtures/nk-inheritance.json
... ...
@@ -0,0 +1,18 @@
  1
+[
  2
+    {
  3
+        "pk": 1,
  4
+        "model": "fixtures_regress.nkchild",
  5
+        "fields": {
  6
+            "data": "apple"
  7
+        }
  8
+    },
  9
+    {
  10
+        "pk": 1,
  11
+        "model": "fixtures_regress.reftonkchild",
  12
+        "fields": {
  13
+            "text": "my text",
  14
+            "nk_fk" : ["apple"],
  15
+            "nk_m2m": [["apple"]]
  16
+        }
  17
+    }
  18
+]
23  tests/regressiontests/fixtures_regress/fixtures/nk-inheritance2.xml
... ...
@@ -0,0 +1,23 @@
  1
+<?xml version="1.0" encoding="utf-8"?>
  2
+<django-objects version="1.0">
  3
+    <object pk="2" model="fixtures_regress.parent">
  4
+        <field type="CharField" name="name">james</field>
  5
+    </object>
  6
+    <object pk="2" model="fixtures_regress.nkchild">
  7
+        <field type="CharField" name="data">banana</field>
  8
+    </object>
  9
+    <object pk="2" model="fixtures_regress.reftonkchild">
  10
+        <field type="CharField" name="text">other text</field>
  11
+        <field to="fixtures_regress.nkchild" name="nk_fk" rel="ManyToOneRel">
  12
+            <natural>apple</natural>
  13
+        </field>
  14
+        <field to="fixtures_regress.nkchild" name="nk_m2m" rel="ManyToManyRel">
  15
+            <object>
  16
+                <natural>banana</natural>
  17
+            </object>
  18
+            <object>
  19
+                <natural>apple</natural>
  20
+            </object>
  21
+        </field>
  22
+    </object>
  23
+</django-objects>
52  tests/regressiontests/fixtures_regress/models.py
@@ -52,6 +52,9 @@ def __init__(self, *args, **kwargs):
52 52
 class Parent(models.Model):
53 53
     name = models.CharField(max_length=10)
54 54
 
  55
+    class Meta:
  56
+        ordering = ('id',)
  57
+
55 58
 class Child(Parent):
56 59
     data = models.CharField(max_length=10)
57 60
 
@@ -130,6 +133,32 @@ def __unicode__(self):
130 133
             ', '.join(s.name for s in self.stores.all())
131 134
         )
132 135
 
  136
+class NKManager(models.Manager):
  137
+    def get_by_natural_key(self, data):
  138
+        return self.get(data=data)
  139
+
  140
+class NKChild(Parent):
  141
+    data = models.CharField(max_length=10, unique=True)
  142
+    objects = NKManager()
  143
+
  144
+    def natural_key(self):
  145
+        return self.data
  146
+
  147
+    def __unicode__(self):
  148
+        return u'NKChild %s:%s' % (self.name, self.data)
  149
+
  150
+class RefToNKChild(models.Model):
  151
+    text = models.CharField(max_length=10)
  152
+    nk_fk = models.ForeignKey(NKChild, related_name='ref_fks')
  153
+    nk_m2m = models.ManyToManyField(NKChild, related_name='ref_m2ms')
  154
+
  155
+    def __unicode__(self):
  156
+        return u'%s: Reference to %s [%s]' % (
  157
+            self.text,
  158
+            self.nk_fk,
  159
+            ', '.join(str(o) for o in self.nk_m2m.all())
  160
+        )
  161
+
133 162
 # ome models with pathological circular dependencies
134 163
 class Circle1(models.Model):
135 164
     name = models.CharField(max_length=255)
@@ -245,6 +274,27 @@ def natural_key(self):
245 274
 >>> management.call_command('loaddata', 'model-inheritance.json', verbosity=0)
246 275
 
247 276
 ###############################################
  277
+# Test for ticket #13030 -- natural keys deserialize with fk to inheriting model
  278
+
  279
+# load data with natural keys
  280
+>>> management.call_command('loaddata', 'nk-inheritance.json', verbosity=0)
  281
+
  282
+>>> NKChild.objects.get(pk=1)
  283
+<NKChild: NKChild fred:apple>
  284
+
  285
+>>> RefToNKChild.objects.get(pk=1)
  286
+<RefToNKChild: my text: Reference to NKChild fred:apple [NKChild fred:apple]>
  287
+
  288
+# ... and again in XML
  289
+>>> management.call_command('loaddata', 'nk-inheritance2.xml', verbosity=0)
  290
+
  291
+>>> NKChild.objects.get(pk=2)
  292
+<NKChild: NKChild james:banana>
  293
+
  294
+>>> RefToNKChild.objects.get(pk=2)
  295
+<RefToNKChild: other text: Reference to NKChild fred:apple [NKChild fred:apple, NKChild james:banana]>
  296
+
  297
+###############################################
248 298
 # Test for ticket #7572 -- MySQL has a problem if the same connection is
249 299
 # used to create tables, load data, and then query over that data.
250 300
 # To compensate, we close the connection after running loaddata.
@@ -279,7 +329,7 @@ def natural_key(self):
279 329
 [{"pk": 1, "model": "fixtures_regress.animal", "fields": {"count": 3, "weight": 1.2, "name": "Lion", "latin_name": "Panthera leo"}}, {"pk": 2, "model": "fixtures_regress.animal", "fields": {"count": 2, "weight": 2.2, "name": "Platypus", "latin_name": "Ornithorhynchus anatinus"}}, {"pk": 10, "model": "fixtures_regress.animal", "fields": {"count": 42, "weight": 1.2, "name": "Emu", "latin_name": "Dromaius novaehollandiae"}}]
280 330
 
281 331
 ###############################################
282  
-# Regression for #11428 - Proxy models aren't included when you dumpdata 
  332
+# Regression for #11428 - Proxy models aren't included when you dumpdata
283 333
 
284 334
 # Flush out the database first
285 335
 >>> management.call_command('reset', 'fixtures_regress', interactive=False, verbosity=0)

0 notes on commit 10de2a8

Please sign in to comment.
Something went wrong with that request. Please try again.