PageRenderTime 36ms CodeModel.GetById 2ms app.highlight 29ms RepoModel.GetById 1ms app.codeStats 1ms

/tests/regressiontests/model_inheritance_regress/tests.py

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