Code

Ticket #10808: 10808.diff

File 10808.diff, 2.5 KB (added by SmileyChris, 5 years ago)

Single patch with tests & changes

Line 
1Index: django/db/models/base.py
2===================================================================
3--- django/db/models/base.py    (revision 10857)
4+++ django/db/models/base.py    (working copy)
5@@ -273,7 +273,15 @@
6         # Now we're left with the unprocessed fields that *must* come from
7         # keywords, or default.
8 
9+        # In the case of diamond inheritance, where B and C inherit from A, and
10+        # D inherits from B and C, D will have "redundant" copies of each of
11+        # A's fields. As we iterate through all the fields, the second time we
12+        # see a field we run the risk of reassigning it the default value, so
13+        # if a field has already been seen in assigned_fields, we ignore it.
14+        assigned_fields = set()
15         for field in fields_iter:
16+            if field.attname in assigned_fields:
17+                continue
18             is_related_object = False
19             # This slightly odd construct is so that we can access any
20             # data-descriptor object (DeferredAttribute) without triggering its
21@@ -311,6 +319,7 @@
22                 setattr(self, field.name, rel_obj)
23             else:
24                 setattr(self, field.attname, val)
25+            assigned_fields.add(field.attname)
26 
27         if kwargs:
28             for prop in kwargs.keys():
29Index: tests/modeltests/model_inheritance/models.py
30===================================================================
31--- tests/modeltests/model_inheritance/models.py        (revision 10857)
32+++ tests/modeltests/model_inheritance/models.py        (working copy)
33@@ -116,6 +116,21 @@
34     def __unicode__(self):
35         return u"%s the parking lot" % self.name
36 
37+#
38+# Diamond inheritance test
39+#
40+class FoodPlace(models.Model):
41+    name = models.CharField(max_length=255)
42+
43+class Bar(FoodPlace):
44+    pass
45+
46+class Pizzeria(FoodPlace):
47+    pass
48+
49+class PizzeriaBar(Bar, Pizzeria):
50+    pizza_bar_specific_field = models.CharField(max_length=255)
51+
52 __test__ = {'API_TESTS':"""
53 # The Student and Worker models both have 'name' and 'age' fields on them and
54 # inherit the __unicode__() method, just as with normal Python subclassing.
55@@ -310,4 +325,11 @@
56 3
57 >>> settings.DEBUG = False
58 
59+# Test of diamond inheritance __init__. If B and C inherit from A, and D inherits from B and C, we should be able to use __init__ for D to properly set all the fields, regardless of the redundant copies of A's fields that D inherits from B and C.
60+
61+>>> p = PizzeriaBar(name="Mike's", pizza_bar_specific_field="Doodle")
62+>>> p.name == "Mike's"
63+True
64+>>> p.pizza_bar_specific_field == "Doodle"
65+True
66 """}