Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

[1.2.X] Migrated model_inheritance_regress doctests. Thanks to Gregor…

… Müllegger for the patch.

Backport of r14576 from trunk.

git-svn-id: http://code.djangoproject.com/svn/django/branches/releases/1.2.X@14577 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 10fafed666b1bde858589787433af5bb15ceaded 1 parent 587c66f
Russell Keith-Magee authored November 16, 2010
256  tests/regressiontests/model_inheritance_regress/models.py
... ...
@@ -1,7 +1,3 @@
1  
-"""
2  
-Regression tests for Model inheritance behaviour.
3  
-"""
4  
-
5 1
 import datetime
6 2
 
7 3
 from django.db import models
@@ -136,255 +132,3 @@ class BachelorParty(AbstractEvent):
136 132
 
137 133
 class MessyBachelorParty(BachelorParty):
138 134
     pass
139  
-
140  
-__test__ = {'API_TESTS':"""
141  
-# Regression for #7350, #7202
142  
-# Check that when you create a Parent object with a specific reference to an
143  
-# existent child instance, saving the Parent doesn't duplicate the child. This
144  
-# behaviour is only activated during a raw save - it is mostly relevant to
145  
-# deserialization, but any sort of CORBA style 'narrow()' API would require a
146  
-# similar approach.
147  
-
148  
-# Create a child-parent-grandparent chain
149  
->>> place1 = Place(name="Guido's House of Pasta", address='944 W. Fullerton')
150  
->>> place1.save_base(raw=True)
151  
->>> restaurant = Restaurant(place_ptr=place1, serves_hot_dogs=True, serves_pizza=False)
152  
->>> restaurant.save_base(raw=True)
153  
->>> italian_restaurant = ItalianRestaurant(restaurant_ptr=restaurant, serves_gnocchi=True)
154  
->>> italian_restaurant.save_base(raw=True)
155  
-
156  
-# Create a child-parent chain with an explicit parent link
157  
->>> place2 = Place(name='Main St', address='111 Main St')
158  
->>> place2.save_base(raw=True)
159  
->>> park = ParkingLot(parent=place2, capacity=100)
160  
->>> park.save_base(raw=True)
161  
-
162  
-# Check that no extra parent objects have been created.
163  
->>> Place.objects.all()
164  
-[<Place: Guido's House of Pasta the place>, <Place: Main St the place>]
165  
-
166  
->>> dicts = Restaurant.objects.values('name','serves_hot_dogs')
167  
->>> [sorted(d.items()) for d in dicts] == [[('name', u"Guido's House of Pasta"), ('serves_hot_dogs', True)]]
168  
-True
169  
-
170  
->>> dicts = ItalianRestaurant.objects.values('name','serves_hot_dogs','serves_gnocchi')
171  
->>> [sorted(d.items()) for d in dicts] == [[('name', u"Guido's House of Pasta"), ('serves_gnocchi', True), ('serves_hot_dogs', True)]]
172  
-True
173  
-
174  
->>> dicts = ParkingLot.objects.values('name','capacity')
175  
->>> [sorted(d.items()) for d in dicts]
176  
-[[('capacity', 100), ('name', u'Main St')]]
177  
-
178  
-# You can also update objects when using a raw save.
179  
->>> place1.name = "Guido's All New House of Pasta"
180  
->>> place1.save_base(raw=True)
181  
-
182  
->>> restaurant.serves_hot_dogs = False
183  
->>> restaurant.save_base(raw=True)
184  
-
185  
->>> italian_restaurant.serves_gnocchi = False
186  
->>> italian_restaurant.save_base(raw=True)
187  
-
188  
->>> place2.name='Derelict lot'
189  
->>> place2.save_base(raw=True)
190  
-
191  
->>> park.capacity = 50
192  
->>> park.save_base(raw=True)
193  
-
194  
-# No extra parent objects after an update, either.
195  
->>> Place.objects.all()
196  
-[<Place: Derelict lot the place>, <Place: Guido's All New House of Pasta the place>]
197  
-
198  
->>> dicts = Restaurant.objects.values('name','serves_hot_dogs')
199  
->>> [sorted(d.items()) for d in dicts] == [[('name', u"Guido's All New House of Pasta"), ('serves_hot_dogs', False)]]
200  
-True
201  
-
202  
->>> dicts = ItalianRestaurant.objects.values('name','serves_hot_dogs','serves_gnocchi')
203  
->>> [sorted(d.items()) for d in dicts] == [[('name', u"Guido's All New House of Pasta"), ('serves_gnocchi', False), ('serves_hot_dogs', False)]]
204  
-True
205  
-
206  
->>> dicts = ParkingLot.objects.values('name','capacity')
207  
->>> [sorted(d.items()) for d in dicts]
208  
-[[('capacity', 50), ('name', u'Derelict lot')]]
209  
-
210  
-# If you try to raw_save a parent attribute onto a child object,
211  
-# the attribute will be ignored.
212  
-
213  
->>> italian_restaurant.name = "Lorenzo's Pasta Hut"
214  
->>> italian_restaurant.save_base(raw=True)
215  
-
216  
-# Note that the name has not changed
217  
-# - name is an attribute of Place, not ItalianRestaurant
218  
->>> dicts = ItalianRestaurant.objects.values('name','serves_hot_dogs','serves_gnocchi')
219  
->>> [sorted(d.items()) for d in dicts] == [[('name', u"Guido's All New House of Pasta"), ('serves_gnocchi', False), ('serves_hot_dogs', False)]]
220  
-True
221  
-
222  
-# Regressions tests for #7105: dates() queries should be able to use fields
223  
-# from the parent model as easily as the child.
224  
->>> obj = Child.objects.create(name='child', created=datetime.datetime(2008, 6, 26, 17, 0, 0))
225  
->>> Child.objects.dates('created', 'month')
226  
-[datetime.datetime(2008, 6, 1, 0, 0)]
227  
-
228  
-# Regression test for #7276: calling delete() on a model with multi-table
229  
-# inheritance should delete the associated rows from any ancestor tables, as
230  
-# well as any descendent objects.
231  
-
232  
->>> ident = ItalianRestaurant.objects.all()[0].id
233  
->>> Place.objects.get(pk=ident)
234  
-<Place: Guido's All New House of Pasta the place>
235  
->>> xx = Restaurant.objects.create(name='a', address='xx', serves_hot_dogs=True, serves_pizza=False)
236  
-
237  
-# This should delete both Restuarants, plus the related places, plus the ItalianRestaurant.
238  
->>> Restaurant.objects.all().delete()
239  
-
240  
->>> Place.objects.get(pk=ident)
241  
-Traceback (most recent call last):
242  
-...
243  
-DoesNotExist: Place matching query does not exist.
244  
-
245  
->>> ItalianRestaurant.objects.get(pk=ident)
246  
-Traceback (most recent call last):
247  
-...
248  
-DoesNotExist: ItalianRestaurant matching query does not exist.
249  
-
250  
-# Regression test for #6755
251  
->>> r = Restaurant(serves_pizza=False)
252  
->>> r.save()
253  
->>> r.id == r.place_ptr_id
254  
-True
255  
->>> orig_id = r.id
256  
->>> r = Restaurant(place_ptr_id=orig_id, serves_pizza=True)
257  
->>> r.save()
258  
->>> r.id == orig_id
259  
-True
260  
->>> r.id == r.place_ptr_id
261  
-True
262  
-
263  
-# Regression test for #7488. This looks a little crazy, but it's the equivalent
264  
-# of what the admin interface has to do for the edit-inline case.
265  
->>> Supplier.objects.filter(restaurant=Restaurant(name='xx', address='yy'))
266  
-[]
267  
-
268  
-# Regression test for #11764.
269  
->>> for w in Wholesaler.objects.all().select_related():
270  
-...     print w
271  
-
272  
-# Regression test for #7853
273  
-# If the parent class has a self-referential link, make sure that any updates
274  
-# to that link via the child update the right table.
275  
-
276  
->>> obj = SelfRefChild.objects.create(child_data=37, parent_data=42)
277  
->>> obj.delete()
278  
-
279  
-# Regression tests for #8076 - get_(next/previous)_by_date should work.
280  
->>> c1 = ArticleWithAuthor(headline='ArticleWithAuthor 1', author="Person 1", pub_date=datetime.datetime(2005, 8, 1, 3, 0))
281  
->>> c1.save()
282  
->>> c2 = ArticleWithAuthor(headline='ArticleWithAuthor 2', author="Person 2", pub_date=datetime.datetime(2005, 8, 1, 10, 0))
283  
->>> c2.save()
284  
->>> c3 = ArticleWithAuthor(headline='ArticleWithAuthor 3', author="Person 3", pub_date=datetime.datetime(2005, 8, 2))
285  
->>> c3.save()
286  
-
287  
->>> c1.get_next_by_pub_date()
288  
-<ArticleWithAuthor: ArticleWithAuthor 2>
289  
->>> c2.get_next_by_pub_date()
290  
-<ArticleWithAuthor: ArticleWithAuthor 3>
291  
->>> c3.get_next_by_pub_date()
292  
-Traceback (most recent call last):
293  
-    ...
294  
-DoesNotExist: ArticleWithAuthor matching query does not exist.
295  
->>> c3.get_previous_by_pub_date()
296  
-<ArticleWithAuthor: ArticleWithAuthor 2>
297  
->>> c2.get_previous_by_pub_date()
298  
-<ArticleWithAuthor: ArticleWithAuthor 1>
299  
->>> c1.get_previous_by_pub_date()
300  
-Traceback (most recent call last):
301  
-    ...
302  
-DoesNotExist: ArticleWithAuthor matching query does not exist.
303  
-
304  
-# Regression test for #8825: Make sure all inherited fields (esp. m2m fields, in
305  
-# this case) appear on the child class.
306  
->>> M2MChild.objects.filter(articles__isnull=False)
307  
-[]
308  
-
309  
-# All fields from an ABC, including those inherited non-abstractly should be
310  
-# available on child classes (#7588). Creating this instance should work
311  
-# without error.
312  
->>> _ = QualityControl.objects.create(headline="Problems in Django", pub_date=datetime.datetime.now(), quality=10, assignee="adrian")
313  
-
314  
-# Ordering should not include any database column more than once (this is most
315  
-# likely to ocurr naturally with model inheritance, so we check it here).
316  
-# Regression test for #9390. This necessarily pokes at the SQL string for the
317  
-# query, since the duplicate problems are only apparent at that late stage.
318  
->>> qs = ArticleWithAuthor.objects.order_by('pub_date', 'pk')
319  
->>> sql = qs.query.get_compiler(qs.db).as_sql()[0]
320  
->>> fragment = sql[sql.find('ORDER BY'):]
321  
->>> pos = fragment.find('pub_date')
322  
->>> fragment.find('pub_date', pos + 1) == -1
323  
-True
324  
-
325  
-# It is possible to call update() and only change a field in an ancestor model
326  
-# (regression test for #10362).
327  
->>> article = ArticleWithAuthor.objects.create(author="fred", headline="Hey there!", pub_date = datetime.datetime(2009, 3, 1, 8, 0, 0))
328  
->>> ArticleWithAuthor.objects.filter(author="fred").update(headline="Oh, no!")
329  
-1
330  
->>> ArticleWithAuthor.objects.filter(pk=article.pk).update(headline="Oh, no!")
331  
-1
332  
-
333  
->>> DerivedM.objects.create(customPK=44, base_name="b1", derived_name="d1")
334  
-<DerivedM: PK = 44, base_name = b1, derived_name = d1>
335  
->>> DerivedM.objects.all()
336  
-[<DerivedM: PK = 44, base_name = b1, derived_name = d1>]
337  
-
338  
-# Regression tests for #10406
339  
-
340  
-# If there's a one-to-one link between a child model and the parent and no
341  
-# explicit pk declared, we can use the one-to-one link as the pk on the child.
342  
-# The ParkingLot2 model shows this behaviour.
343  
->>> ParkingLot2._meta.pk.name
344  
-"parent"
345  
-
346  
-# However, the connector from child to parent need not be the pk on the child
347  
-# at all.
348  
->>> ParkingLot3._meta.pk.name
349  
-"primary_key"
350  
->>> ParkingLot3._meta.get_ancestor_link(Place).name  # the child->parent link
351  
-"parent"
352  
-
353  
-# Check that many-to-many relations defined on an abstract base class
354  
-# are correctly inherited (and created) on the child class.
355  
->>> p1 = Person.objects.create(name='Alice')
356  
->>> p2 = Person.objects.create(name='Bob')
357  
->>> p3 = Person.objects.create(name='Carol')
358  
->>> p4 = Person.objects.create(name='Dave')
359  
-
360  
->>> birthday = BirthdayParty.objects.create(name='Birthday party for Alice')
361  
->>> birthday.attendees = [p1, p3]
362  
-
363  
->>> bachelor = BachelorParty.objects.create(name='Bachelor party for Bob')
364  
->>> bachelor.attendees = [p2, p4]
365  
-
366  
->>> print p1.birthdayparty_set.all()
367  
-[<BirthdayParty: Birthday party for Alice>]
368  
-
369  
->>> print p1.bachelorparty_set.all()
370  
-[]
371  
-
372  
->>> print p2.bachelorparty_set.all()
373  
-[<BachelorParty: Bachelor party for Bob>]
374  
-
375  
-# Check that a subclass of a subclass of an abstract model
376  
-# doesn't get it's own accessor.
377  
->>> p2.messybachelorparty_set.all()
378  
-Traceback (most recent call last):
379  
-...
380  
-AttributeError: 'Person' object has no attribute 'messybachelorparty_set'
381  
-
382  
-# ... but it does inherit the m2m from it's parent
383  
->>> messy = MessyBachelorParty.objects.create(name='Bachelor party for Dave')
384  
->>> messy.attendees = [p4]
385  
-
386  
->>> p4.bachelorparty_set.all()
387  
-[<BachelorParty: Bachelor party for Bob>, <BachelorParty: Bachelor party for Dave>]
388  
-
389  
-"""}
390  
-
355  tests/regressiontests/model_inheritance_regress/tests.py
... ...
@@ -0,0 +1,355 @@
  1
+"""
  2
+Regression tests for Model inheritance behaviour.
  3
+"""
  4
+
  5
+import datetime
  6
+from django.test import TestCase
  7
+from regressiontests.model_inheritance_regress.models import (
  8
+    Place, Restaurant, ItalianRestaurant, ParkingLot, ParkingLot2,
  9
+    ParkingLot3, Supplier, Wholesaler, Child, SelfRefChild, ArticleWithAuthor,
  10
+    M2MChild, QualityControl, DerivedM, Person, BirthdayParty, BachelorParty,
  11
+    MessyBachelorParty)
  12
+
  13
+class ModelInheritanceTest(TestCase):
  14
+    def test_model_inheritance(self):
  15
+        # Regression for #7350, #7202
  16
+        # Check that when you create a Parent object with a specific reference
  17
+        # to an existent child instance, saving the Parent doesn't duplicate
  18
+        # the child. This behaviour is only activated during a raw save - it
  19
+        # is mostly relevant to deserialization, but any sort of CORBA style
  20
+        # 'narrow()' API would require a similar approach.
  21
+
  22
+        # Create a child-parent-grandparent chain
  23
+        place1 = Place(
  24
+            name="Guido's House of Pasta",
  25
+            address='944 W. Fullerton')
  26
+        place1.save_base(raw=True)
  27
+        restaurant = Restaurant(
  28
+            place_ptr=place1,
  29
+            serves_hot_dogs=True,
  30
+            serves_pizza=False)
  31
+        restaurant.save_base(raw=True)
  32
+        italian_restaurant = ItalianRestaurant(
  33
+            restaurant_ptr=restaurant,
  34
+            serves_gnocchi=True)
  35
+        italian_restaurant.save_base(raw=True)
  36
+
  37
+        # Create a child-parent chain with an explicit parent link
  38
+        place2 = Place(name='Main St', address='111 Main St')
  39
+        place2.save_base(raw=True)
  40
+        park = ParkingLot(parent=place2, capacity=100)
  41
+        park.save_base(raw=True)
  42
+
  43
+        # Check that no extra parent objects have been created.
  44
+        places = list(Place.objects.all())
  45
+        self.assertEqual(places, [place1, place2])
  46
+
  47
+        dicts = list(Restaurant.objects.values('name','serves_hot_dogs'))
  48
+        self.assertEqual(dicts, [{
  49
+            'name': u"Guido's House of Pasta",
  50
+            'serves_hot_dogs': True
  51
+        }])
  52
+
  53
+        dicts = list(ItalianRestaurant.objects.values(
  54
+            'name','serves_hot_dogs','serves_gnocchi'))
  55
+        self.assertEqual(dicts, [{
  56
+            'name': u"Guido's House of Pasta",
  57
+            'serves_gnocchi': True,
  58
+            'serves_hot_dogs': True,
  59
+        }])
  60
+
  61
+        dicts = list(ParkingLot.objects.values('name','capacity'))
  62
+        self.assertEqual(dicts, [{
  63
+            'capacity': 100,
  64
+            'name': u'Main St',
  65
+        }])
  66
+
  67
+        # You can also update objects when using a raw save.
  68
+        place1.name = "Guido's All New House of Pasta"
  69
+        place1.save_base(raw=True)
  70
+
  71
+        restaurant.serves_hot_dogs = False
  72
+        restaurant.save_base(raw=True)
  73
+
  74
+        italian_restaurant.serves_gnocchi = False
  75
+        italian_restaurant.save_base(raw=True)
  76
+
  77
+        place2.name='Derelict lot'
  78
+        place2.save_base(raw=True)
  79
+
  80
+        park.capacity = 50
  81
+        park.save_base(raw=True)
  82
+
  83
+        # No extra parent objects after an update, either.
  84
+        places = list(Place.objects.all())
  85
+        self.assertEqual(places, [place2, place1])
  86
+        self.assertEqual(places[0].name, 'Derelict lot')
  87
+        self.assertEqual(places[1].name, "Guido's All New House of Pasta")
  88
+
  89
+        dicts = list(Restaurant.objects.values('name','serves_hot_dogs'))
  90
+        self.assertEqual(dicts, [{
  91
+            'name': u"Guido's All New House of Pasta",
  92
+            'serves_hot_dogs': False,
  93
+        }])
  94
+
  95
+        dicts = list(ItalianRestaurant.objects.values(
  96
+            'name', 'serves_hot_dogs', 'serves_gnocchi'))
  97
+        self.assertEqual(dicts, [{
  98
+            'name': u"Guido's All New House of Pasta",
  99
+            'serves_gnocchi': False,
  100
+            'serves_hot_dogs': False,
  101
+        }])
  102
+
  103
+        dicts = list(ParkingLot.objects.values('name','capacity'))
  104
+        self.assertEqual(dicts, [{
  105
+            'capacity': 50,
  106
+            'name': u'Derelict lot',
  107
+        }])
  108
+
  109
+        # If you try to raw_save a parent attribute onto a child object,
  110
+        # the attribute will be ignored.
  111
+
  112
+        italian_restaurant.name = "Lorenzo's Pasta Hut"
  113
+        italian_restaurant.save_base(raw=True)
  114
+
  115
+        # Note that the name has not changed
  116
+        # - name is an attribute of Place, not ItalianRestaurant
  117
+        dicts = list(ItalianRestaurant.objects.values(
  118
+            'name','serves_hot_dogs','serves_gnocchi'))
  119
+        self.assertEqual(dicts, [{
  120
+            'name': u"Guido's All New House of Pasta",
  121
+            'serves_gnocchi': False,
  122
+            'serves_hot_dogs': False,
  123
+        }])
  124
+
  125
+    def test_issue_7105(self):
  126
+        # Regressions tests for #7105: dates() queries should be able to use
  127
+        # fields from the parent model as easily as the child.
  128
+        obj = Child.objects.create(
  129
+            name='child',
  130
+            created=datetime.datetime(2008, 6, 26, 17, 0, 0))
  131
+        dates = list(Child.objects.dates('created', 'month'))
  132
+        self.assertEqual(dates, [datetime.datetime(2008, 6, 1, 0, 0)])
  133
+
  134
+    def test_issue_7276(self):
  135
+        # Regression test for #7276: calling delete() on a model with
  136
+        # multi-table inheritance should delete the associated rows from any
  137
+        # ancestor tables, as well as any descendent objects.
  138
+        place1 = Place(
  139
+            name="Guido's House of Pasta",
  140
+            address='944 W. Fullerton')
  141
+        place1.save_base(raw=True)
  142
+        restaurant = Restaurant(
  143
+            place_ptr=place1,
  144
+            serves_hot_dogs=True,
  145
+            serves_pizza=False)
  146
+        restaurant.save_base(raw=True)
  147
+        italian_restaurant = ItalianRestaurant(
  148
+            restaurant_ptr=restaurant,
  149
+            serves_gnocchi=True)
  150
+        italian_restaurant.save_base(raw=True)
  151
+
  152
+        ident = ItalianRestaurant.objects.all()[0].id
  153
+        self.assertEqual(Place.objects.get(pk=ident), place1)
  154
+        xx = Restaurant.objects.create(
  155
+            name='a',
  156
+            address='xx',
  157
+            serves_hot_dogs=True,
  158
+            serves_pizza=False)
  159
+
  160
+        # This should delete both Restuarants, plus the related places, plus
  161
+        # the ItalianRestaurant.
  162
+        Restaurant.objects.all().delete()
  163
+
  164
+        self.assertRaises(
  165
+            Place.DoesNotExist,
  166
+            Place.objects.get,
  167
+            pk=ident)
  168
+        self.assertRaises(
  169
+            ItalianRestaurant.DoesNotExist,
  170
+            ItalianRestaurant.objects.get,
  171
+            pk=ident)
  172
+
  173
+    def test_issue_6755(self):
  174
+        """
  175
+        Regression test for #6755
  176
+        """
  177
+        r = Restaurant(serves_pizza=False)
  178
+        r.save()
  179
+        self.assertEqual(r.id, r.place_ptr_id)
  180
+        orig_id = r.id
  181
+        r = Restaurant(place_ptr_id=orig_id, serves_pizza=True)
  182
+        r.save()
  183
+        self.assertEqual(r.id, orig_id)
  184
+        self.assertEqual(r.id, r.place_ptr_id)
  185
+
  186
+    def test_issue_7488(self):
  187
+        # Regression test for #7488. This looks a little crazy, but it's the
  188
+        # equivalent of what the admin interface has to do for the edit-inline
  189
+        # case.
  190
+        suppliers = Supplier.objects.filter(
  191
+            restaurant=Restaurant(name='xx', address='yy'))
  192
+        suppliers = list(suppliers)
  193
+        self.assertEqual(suppliers, [])
  194
+
  195
+    def test_issue_11764(self):
  196
+        """
  197
+        Regression test for #11764
  198
+        """
  199
+        wholesalers = list(Wholesaler.objects.all().select_related())
  200
+        self.assertEqual(wholesalers, [])
  201
+
  202
+    def test_issue_7853(self):
  203
+        """
  204
+        Regression test for #7853
  205
+        If the parent class has a self-referential link, make sure that any
  206
+        updates to that link via the child update the right table.
  207
+        """
  208
+        obj = SelfRefChild.objects.create(child_data=37, parent_data=42)
  209
+        obj.delete()
  210
+
  211
+    def test_get_next_previous_by_date(self):
  212
+        """
  213
+        Regression tests for #8076
  214
+        get_(next/previous)_by_date should work
  215
+        """
  216
+        c1 = ArticleWithAuthor(
  217
+            headline='ArticleWithAuthor 1',
  218
+            author="Person 1",
  219
+            pub_date=datetime.datetime(2005, 8, 1, 3, 0))
  220
+        c1.save()
  221
+        c2 = ArticleWithAuthor(
  222
+            headline='ArticleWithAuthor 2',
  223
+            author="Person 2",
  224
+            pub_date=datetime.datetime(2005, 8, 1, 10, 0))
  225
+        c2.save()
  226
+        c3 = ArticleWithAuthor(
  227
+            headline='ArticleWithAuthor 3',
  228
+            author="Person 3",
  229
+            pub_date=datetime.datetime(2005, 8, 2))
  230
+        c3.save()
  231
+
  232
+        self.assertEqual(c1.get_next_by_pub_date(), c2)
  233
+        self.assertEqual(c2.get_next_by_pub_date(), c3)
  234
+        self.assertRaises(
  235
+            ArticleWithAuthor.DoesNotExist,
  236
+            c3.get_next_by_pub_date)
  237
+        self.assertEqual(c3.get_previous_by_pub_date(), c2)
  238
+        self.assertEqual(c2.get_previous_by_pub_date(), c1)
  239
+        self.assertRaises(
  240
+            ArticleWithAuthor.DoesNotExist,
  241
+            c1.get_previous_by_pub_date)
  242
+
  243
+    def test_inherited_fields(self):
  244
+        """
  245
+        Regression test for #8825 and #9390
  246
+        Make sure all inherited fields (esp. m2m fields, in this case) appear
  247
+        on the child class.
  248
+        """
  249
+        m2mchildren = list(M2MChild.objects.filter(articles__isnull=False))
  250
+        self.assertEqual(m2mchildren, [])
  251
+
  252
+        # Ordering should not include any database column more than once (this
  253
+        # is most likely to ocurr naturally with model inheritance, so we
  254
+        # check it here). Regression test for #9390. This necessarily pokes at
  255
+        # the SQL string for the query, since the duplicate problems are only
  256
+        # apparent at that late stage.
  257
+        qs = ArticleWithAuthor.objects.order_by('pub_date', 'pk')
  258
+        sql = qs.query.get_compiler(qs.db).as_sql()[0]
  259
+        fragment = sql[sql.find('ORDER BY'):]
  260
+        pos = fragment.find('pub_date')
  261
+        self.assertEqual(fragment.find('pub_date', pos + 1), -1)
  262
+
  263
+    def test_queryset_update_on_parent_model(self):
  264
+        """
  265
+        Regression test for #10362
  266
+        It is possible to call update() and only change a field in
  267
+        an ancestor model.
  268
+        """
  269
+        article = ArticleWithAuthor.objects.create(
  270
+            author="fred",
  271
+            headline="Hey there!",
  272
+            pub_date=datetime.datetime(2009, 3, 1, 8, 0, 0))
  273
+        update = ArticleWithAuthor.objects.filter(
  274
+            author="fred").update(headline="Oh, no!")
  275
+        self.assertEqual(update, 1)
  276
+        update = ArticleWithAuthor.objects.filter(
  277
+            pk=article.pk).update(headline="Oh, no!")
  278
+        self.assertEqual(update, 1)
  279
+
  280
+        derivedm1 = DerivedM.objects.create(
  281
+            customPK=44,
  282
+            base_name="b1",
  283
+            derived_name="d1")
  284
+        self.assertEqual(derivedm1.customPK, 44)
  285
+        self.assertEqual(derivedm1.base_name, 'b1')
  286
+        self.assertEqual(derivedm1.derived_name, 'd1')
  287
+        derivedms = list(DerivedM.objects.all())
  288
+        self.assertEqual(derivedms, [derivedm1])
  289
+
  290
+    def test_use_explicit_o2o_to_parent_as_pk(self):
  291
+        """
  292
+        Regression tests for #10406
  293
+        If there's a one-to-one link between a child model and the parent and
  294
+        no explicit pk declared, we can use the one-to-one link as the pk on
  295
+        the child.
  296
+        """
  297
+        self.assertEqual(ParkingLot2._meta.pk.name, "parent")
  298
+
  299
+        # However, the connector from child to parent need not be the pk on
  300
+        # the child at all.
  301
+        self.assertEqual(ParkingLot3._meta.pk.name, "primary_key")
  302
+        # the child->parent link
  303
+        self.assertEqual(
  304
+            ParkingLot3._meta.get_ancestor_link(Place).name,
  305
+            "parent")
  306
+
  307
+    def test_all_fields_from_abstract_base_class(self):
  308
+        """
  309
+        Regression tests for #7588
  310
+        """
  311
+        # All fields from an ABC, including those inherited non-abstractly
  312
+        # should be available on child classes (#7588). Creating this instance
  313
+        # should work without error.
  314
+        QualityControl.objects.create(
  315
+            headline="Problems in Django",
  316
+            pub_date=datetime.datetime.now(),
  317
+            quality=10,
  318
+            assignee="adrian")
  319
+
  320
+    def test_abstract_base_class_m2m_relation_inheritance(self):
  321
+        # Check that many-to-many relations defined on an abstract base class
  322
+        # are correctly inherited (and created) on the child class.
  323
+        p1 = Person.objects.create(name='Alice')
  324
+        p2 = Person.objects.create(name='Bob')
  325
+        p3 = Person.objects.create(name='Carol')
  326
+        p4 = Person.objects.create(name='Dave')
  327
+
  328
+        birthday = BirthdayParty.objects.create(
  329
+            name='Birthday party for Alice')
  330
+        birthday.attendees = [p1, p3]
  331
+
  332
+        bachelor = BachelorParty.objects.create(name='Bachelor party for Bob')
  333
+        bachelor.attendees = [p2, p4]
  334
+
  335
+        parties = list(p1.birthdayparty_set.all())
  336
+        self.assertEqual(parties, [birthday])
  337
+
  338
+        parties = list(p1.bachelorparty_set.all())
  339
+        self.assertEqual(parties, [])
  340
+
  341
+        parties = list(p2.bachelorparty_set.all())
  342
+        self.assertEqual(parties, [bachelor])
  343
+
  344
+        # Check that a subclass of a subclass of an abstract model doesn't get
  345
+        # it's own accessor.
  346
+        self.assertFalse(hasattr(p2, 'messybachelorparty_set'))
  347
+
  348
+        # ... but it does inherit the m2m from it's parent
  349
+        messy = MessyBachelorParty.objects.create(
  350
+            name='Bachelor party for Dave')
  351
+        messy.attendees = [p4]
  352
+        messy_parent = messy.bachelorparty_ptr
  353
+
  354
+        parties = list(p4.bachelorparty_set.all())
  355
+        self.assertEqual(parties, [bachelor, messy_parent])

0 notes on commit 10fafed

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