Code

Ticket #12152: 12152-1.diff

File 12152-1.diff, 6.2 KB (added by mattmcc, 4 years ago)
Line 
1Index: django/db/models/base.py
2===================================================================
3--- django/db/models/base.py    (revision 11718)
4+++ django/db/models/base.py    (working copy)
5@@ -49,10 +49,6 @@
6 
7         new_class.add_to_class('_meta', Options(meta, **kwargs))
8         if not abstract:
9-            new_class.add_to_class('DoesNotExist',
10-                    subclass_exception('DoesNotExist', ObjectDoesNotExist, module))
11-            new_class.add_to_class('MultipleObjectsReturned',
12-                    subclass_exception('MultipleObjectsReturned', MultipleObjectsReturned, module))
13             if base_meta and not base_meta.abstract:
14                 # Non-abstract child classes inherit some attributes from their
15                 # non-abstract parent (unless an ABC comes before it in the
16@@ -118,6 +114,7 @@
17         o2o_map = dict([(f.rel.to, f) for f in new_class._meta.local_fields
18                 if isinstance(f, OneToOneField)])
19 
20+        exception_class_bases = []
21         for base in parents:
22             original_base = base
23             if not hasattr(base, '_meta'):
24@@ -136,6 +133,7 @@
25                                      'base class %r' %
26                                         (field.name, name, base.__name__))
27             if not base._meta.abstract:
28+                exception_class_bases.append(base)
29                 # Concrete classes...
30                 while base._meta.proxy:
31                     # Skip over a proxy class to the "real" base it proxies.
32@@ -176,6 +174,23 @@
33                                         (field.name, name, base.__name__))
34                 new_class.add_to_class(field.name, copy.deepcopy(field))
35 
36+        # If a model has non-abstract parent models, the model's inner
37+        # exception classes should inherit from theirs.
38+        if exception_class_bases:
39+            does_not_exist_parents = tuple(getattr(x, 'DoesNotExist')
40+                            for x in exception_class_bases)
41+            multiple_objects_returned_parents = tuple(getattr(x, 'MultipleObjectsReturned')
42+                            for x in exception_class_bases)
43+        else:
44+            does_not_exist_parents = ObjectDoesNotExist
45+            multiple_objects_returned_parents = MultipleObjectsReturned
46+        new_class.add_to_class('DoesNotExist',
47+                subclass_exception('DoesNotExist',
48+                        does_not_exist_parents, module))
49+        new_class.add_to_class('MultipleObjectsReturned',
50+                subclass_exception('MultipleObjectsReturned',
51+                        multiple_objects_returned_parents, module))
52+
53         if abstract:
54             # Abstract base models can't be instantiated and don't appear in
55             # the list of models for an app. We do the final setup for them a
56@@ -669,7 +684,9 @@
57 if sys.version_info < (2, 5):
58     # Prior to Python 2.5, Exception was an old-style class
59     def subclass_exception(name, parent, unused):
60-        return types.ClassType(name, (parent,), {})
61+        return types.ClassType(name,
62+                    (parent,) if type(parent) == type else parent, {})
63 else:
64     def subclass_exception(name, parent, module):
65-        return type(name, (parent,), {'__module__': module})
66+        return type(name, (parent,) if type(parent) == type else parent,
67+                    {'__module__': module})
68Index: tests/modeltests/proxy_models/models.py
69===================================================================
70--- tests/modeltests/proxy_models/models.py     (revision 11718)
71+++ tests/modeltests/proxy_models/models.py     (working copy)
72@@ -205,6 +205,26 @@
73 >>> MyPersonProxy.objects.all()
74 [<MyPersonProxy: Bazza del Frob>, <MyPersonProxy: Foo McBar>, <MyPersonProxy: homer>]
75 
76+# Proxy models are included in the ancestors for a model's DoesNotExist and MultipleObjectsReturned
77+>>> try:
78+...     MyPersonProxy.objects.get(name='Zathras')
79+... except Person.DoesNotExist:
80+...     pass
81+>>> try:
82+...     MyPersonProxy.objects.get(id__lt=10)
83+... except Person.MultipleObjectsReturned:
84+...     pass
85+>>> try:
86+...     StatusPerson.objects.get(name='Zathras')
87+... except Person.DoesNotExist:
88+...     pass
89+>>> sp1 = StatusPerson.objects.create(name='Bazza Jr.')
90+>>> sp2 = StatusPerson.objects.create(name='Foo Jr.')
91+>>> try:
92+...     StatusPerson.objects.get(id__lt=10)
93+... except Person.MultipleObjectsReturned:
94+...     pass
95+
96 # And now for some things that shouldn't work...
97 #
98 # All base classes must be non-abstract
99Index: tests/modeltests/model_inheritance/models.py
100===================================================================
101--- tests/modeltests/model_inheritance/models.py        (revision 11718)
102+++ tests/modeltests/model_inheritance/models.py        (working copy)
103@@ -38,6 +38,9 @@
104     class Meta:
105         pass
106 
107+class StudentWorker(Student, Worker):
108+    pass
109+
110 #
111 # Abstract base classes with related models
112 #
113@@ -151,6 +154,32 @@
114     ...
115 AttributeError: type object 'CommonInfo' has no attribute 'objects'
116 
117+# A StudentWorker which does not exist is both a Student and Worker which does not exist.
118+>>> try:
119+...     StudentWorker.objects.get(id=1)
120+... except Student.DoesNotExist:
121+...     pass
122+>>> try:
123+...     StudentWorker.objects.get(id=1)
124+... except Worker.DoesNotExist:
125+...     pass
126+
127+# MultipleObjectsReturned is also inherited.
128+>>> sw1 = StudentWorker()
129+>>> sw1.name = 'Wilma'
130+>>> sw1.age = 35
131+>>> sw1.save()
132+>>> sw2 = StudentWorker()
133+>>> sw2.name = 'Betty'
134+>>> sw2.age = 34
135+>>> sw2.save()
136+>>> try:
137+...     StudentWorker.objects.get(id__lt=10)
138+... except Student.MultipleObjectsReturned:
139+...     pass
140+... except Worker.MultipleObjectsReturned:
141+...     pass
142+
143 # Create a Post
144 >>> post = Post(title='Lorem Ipsum')
145 >>> post.save()
146@@ -242,6 +271,18 @@
147     ...
148 DoesNotExist: ItalianRestaurant matching query does not exist.
149 
150+# An ItalianRestaurant which does not exist is also a Place which does not exist.
151+>>> try:
152+...     ItalianRestaurant.objects.get(name='The Noodle Void')
153+... except Place.DoesNotExist:
154+...     pass
155+
156+# MultipleObjectsReturned is also inherited.
157+>>> try:
158+...     Restaurant.objects.get(id__lt=10)
159+... except Place.MultipleObjectsReturned:
160+...     pass
161+
162 # Related objects work just as they normally do.
163 
164 >>> s1 = Supplier(name="Joe's Chickens", address='123 Sesame St')