mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			677 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			677 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| """
 | |
| Regression tests for Model inheritance behavior.
 | |
| """
 | |
| import datetime
 | |
| from operator import attrgetter
 | |
| from unittest import expectedFailure
 | |
| 
 | |
| from django import forms
 | |
| from django.test import TestCase
 | |
| 
 | |
| from .models import (
 | |
|     ArticleWithAuthor,
 | |
|     BachelorParty,
 | |
|     BirthdayParty,
 | |
|     BusStation,
 | |
|     Child,
 | |
|     Congressman,
 | |
|     DerivedM,
 | |
|     InternalCertificationAudit,
 | |
|     ItalianRestaurant,
 | |
|     M2MChild,
 | |
|     MessyBachelorParty,
 | |
|     ParkingLot,
 | |
|     ParkingLot3,
 | |
|     ParkingLot4A,
 | |
|     ParkingLot4B,
 | |
|     Person,
 | |
|     Place,
 | |
|     Politician,
 | |
|     Profile,
 | |
|     QualityControl,
 | |
|     Restaurant,
 | |
|     SelfRefChild,
 | |
|     SelfRefParent,
 | |
|     Senator,
 | |
|     Supplier,
 | |
|     TrainStation,
 | |
|     User,
 | |
|     Wholesaler,
 | |
| )
 | |
| 
 | |
| 
 | |
| class ModelInheritanceTest(TestCase):
 | |
|     def test_model_inheritance(self):
 | |
|         # Regression for #7350, #7202
 | |
|         # When you create a Parent object with a specific reference to an
 | |
|         # existent child instance, saving the Parent doesn't duplicate the
 | |
|         # child. This behavior is only activated during a raw save - it is
 | |
|         # mostly relevant to deserialization, but any sort of CORBA style
 | |
|         # 'narrow()' API would require a similar approach.
 | |
| 
 | |
|         # Create a child-parent-grandparent chain
 | |
|         place1 = Place(name="Guido's House of Pasta", address="944 W. Fullerton")
 | |
|         place1.save_base(raw=True)
 | |
|         restaurant = Restaurant(
 | |
|             place_ptr=place1,
 | |
|             serves_hot_dogs=True,
 | |
|             serves_pizza=False,
 | |
|         )
 | |
|         restaurant.save_base(raw=True)
 | |
|         italian_restaurant = ItalianRestaurant(
 | |
|             restaurant_ptr=restaurant, serves_gnocchi=True
 | |
|         )
 | |
|         italian_restaurant.save_base(raw=True)
 | |
| 
 | |
|         # Create a child-parent chain with an explicit parent link
 | |
|         place2 = Place(name="Main St", address="111 Main St")
 | |
|         place2.save_base(raw=True)
 | |
|         park = ParkingLot(parent=place2, capacity=100)
 | |
|         park.save_base(raw=True)
 | |
| 
 | |
|         # No extra parent objects have been created.
 | |
|         places = list(Place.objects.all())
 | |
|         self.assertEqual(places, [place1, place2])
 | |
| 
 | |
|         dicts = list(Restaurant.objects.values("name", "serves_hot_dogs"))
 | |
|         self.assertEqual(
 | |
|             dicts, [{"name": "Guido's House of Pasta", "serves_hot_dogs": True}]
 | |
|         )
 | |
| 
 | |
|         dicts = list(
 | |
|             ItalianRestaurant.objects.values(
 | |
|                 "name", "serves_hot_dogs", "serves_gnocchi"
 | |
|             )
 | |
|         )
 | |
|         self.assertEqual(
 | |
|             dicts,
 | |
|             [
 | |
|                 {
 | |
|                     "name": "Guido's House of Pasta",
 | |
|                     "serves_gnocchi": True,
 | |
|                     "serves_hot_dogs": True,
 | |
|                 }
 | |
|             ],
 | |
|         )
 | |
| 
 | |
|         dicts = list(ParkingLot.objects.values("name", "capacity"))
 | |
|         self.assertEqual(
 | |
|             dicts,
 | |
|             [
 | |
|                 {
 | |
|                     "capacity": 100,
 | |
|                     "name": "Main St",
 | |
|                 }
 | |
|             ],
 | |
|         )
 | |
| 
 | |
|         # You can also update objects when using a raw save.
 | |
|         place1.name = "Guido's All New House of Pasta"
 | |
|         place1.save_base(raw=True)
 | |
| 
 | |
|         restaurant.serves_hot_dogs = False
 | |
|         restaurant.save_base(raw=True)
 | |
| 
 | |
|         italian_restaurant.serves_gnocchi = False
 | |
|         italian_restaurant.save_base(raw=True)
 | |
| 
 | |
|         place2.name = "Derelict lot"
 | |
|         place2.save_base(raw=True)
 | |
| 
 | |
|         park.capacity = 50
 | |
|         park.save_base(raw=True)
 | |
| 
 | |
|         # No extra parent objects after an update, either.
 | |
|         places = list(Place.objects.all())
 | |
|         self.assertEqual(places, [place2, place1])
 | |
|         self.assertEqual(places[0].name, "Derelict lot")
 | |
|         self.assertEqual(places[1].name, "Guido's All New House of Pasta")
 | |
| 
 | |
|         dicts = list(Restaurant.objects.values("name", "serves_hot_dogs"))
 | |
|         self.assertEqual(
 | |
|             dicts,
 | |
|             [
 | |
|                 {
 | |
|                     "name": "Guido's All New House of Pasta",
 | |
|                     "serves_hot_dogs": False,
 | |
|                 }
 | |
|             ],
 | |
|         )
 | |
| 
 | |
|         dicts = list(
 | |
|             ItalianRestaurant.objects.values(
 | |
|                 "name", "serves_hot_dogs", "serves_gnocchi"
 | |
|             )
 | |
|         )
 | |
|         self.assertEqual(
 | |
|             dicts,
 | |
|             [
 | |
|                 {
 | |
|                     "name": "Guido's All New House of Pasta",
 | |
|                     "serves_gnocchi": False,
 | |
|                     "serves_hot_dogs": False,
 | |
|                 }
 | |
|             ],
 | |
|         )
 | |
| 
 | |
|         dicts = list(ParkingLot.objects.values("name", "capacity"))
 | |
|         self.assertEqual(
 | |
|             dicts,
 | |
|             [
 | |
|                 {
 | |
|                     "capacity": 50,
 | |
|                     "name": "Derelict lot",
 | |
|                 }
 | |
|             ],
 | |
|         )
 | |
| 
 | |
|         # If you try to raw_save a parent attribute onto a child object,
 | |
|         # the attribute will be ignored.
 | |
| 
 | |
|         italian_restaurant.name = "Lorenzo's Pasta Hut"
 | |
|         italian_restaurant.save_base(raw=True)
 | |
| 
 | |
|         # Note that the name has not changed
 | |
|         # - name is an attribute of Place, not ItalianRestaurant
 | |
|         dicts = list(
 | |
|             ItalianRestaurant.objects.values(
 | |
|                 "name", "serves_hot_dogs", "serves_gnocchi"
 | |
|             )
 | |
|         )
 | |
|         self.assertEqual(
 | |
|             dicts,
 | |
|             [
 | |
|                 {
 | |
|                     "name": "Guido's All New House of Pasta",
 | |
|                     "serves_gnocchi": False,
 | |
|                     "serves_hot_dogs": False,
 | |
|                 }
 | |
|             ],
 | |
|         )
 | |
| 
 | |
|     def test_issue_7105(self):
 | |
|         # Regressions tests for #7105: dates() queries should be able to use
 | |
|         # fields from the parent model as easily as the child.
 | |
|         Child.objects.create(
 | |
|             name="child", created=datetime.datetime(2008, 6, 26, 17, 0, 0)
 | |
|         )
 | |
|         datetimes = list(Child.objects.datetimes("created", "month"))
 | |
|         self.assertEqual(datetimes, [datetime.datetime(2008, 6, 1, 0, 0)])
 | |
| 
 | |
|     def test_issue_7276(self):
 | |
|         # Regression test for #7276: calling delete() on a model with
 | |
|         # multi-table inheritance should delete the associated rows from any
 | |
|         # ancestor tables, as well as any descendent objects.
 | |
|         place1 = Place(name="Guido's House of Pasta", address="944 W. Fullerton")
 | |
|         place1.save_base(raw=True)
 | |
|         restaurant = Restaurant(
 | |
|             place_ptr=place1,
 | |
|             serves_hot_dogs=True,
 | |
|             serves_pizza=False,
 | |
|         )
 | |
|         restaurant.save_base(raw=True)
 | |
|         italian_restaurant = ItalianRestaurant(
 | |
|             restaurant_ptr=restaurant, serves_gnocchi=True
 | |
|         )
 | |
|         italian_restaurant.save_base(raw=True)
 | |
| 
 | |
|         ident = ItalianRestaurant.objects.all()[0].id
 | |
|         self.assertEqual(Place.objects.get(pk=ident), place1)
 | |
|         Restaurant.objects.create(
 | |
|             name="a",
 | |
|             address="xx",
 | |
|             serves_hot_dogs=True,
 | |
|             serves_pizza=False,
 | |
|         )
 | |
| 
 | |
|         # This should delete both Restaurants, plus the related places, plus
 | |
|         # the ItalianRestaurant.
 | |
|         Restaurant.objects.all().delete()
 | |
| 
 | |
|         with self.assertRaises(Place.DoesNotExist):
 | |
|             Place.objects.get(pk=ident)
 | |
|         with self.assertRaises(ItalianRestaurant.DoesNotExist):
 | |
|             ItalianRestaurant.objects.get(pk=ident)
 | |
| 
 | |
|     def test_issue_6755(self):
 | |
|         """
 | |
|         Regression test for #6755
 | |
|         """
 | |
|         r = Restaurant(serves_pizza=False, serves_hot_dogs=False)
 | |
|         r.save()
 | |
|         self.assertEqual(r.id, r.place_ptr_id)
 | |
|         orig_id = r.id
 | |
|         r = Restaurant(place_ptr_id=orig_id, serves_pizza=True, serves_hot_dogs=False)
 | |
|         r.save()
 | |
|         self.assertEqual(r.id, orig_id)
 | |
|         self.assertEqual(r.id, r.place_ptr_id)
 | |
| 
 | |
|     def test_issue_11764(self):
 | |
|         """
 | |
|         Regression test for #11764
 | |
|         """
 | |
|         wholesalers = list(Wholesaler.objects.select_related())
 | |
|         self.assertEqual(wholesalers, [])
 | |
| 
 | |
|     def test_issue_7853(self):
 | |
|         """
 | |
|         Regression test for #7853
 | |
|         If the parent class has a self-referential link, make sure that any
 | |
|         updates to that link via the child update the right table.
 | |
|         """
 | |
|         obj = SelfRefChild.objects.create(child_data=37, parent_data=42)
 | |
|         obj.delete()
 | |
| 
 | |
|     def test_get_next_previous_by_date(self):
 | |
|         """
 | |
|         Regression tests for #8076
 | |
|         get_(next/previous)_by_date should work
 | |
|         """
 | |
|         c1 = ArticleWithAuthor(
 | |
|             headline="ArticleWithAuthor 1",
 | |
|             author="Person 1",
 | |
|             pub_date=datetime.datetime(2005, 8, 1, 3, 0),
 | |
|         )
 | |
|         c1.save()
 | |
|         c2 = ArticleWithAuthor(
 | |
|             headline="ArticleWithAuthor 2",
 | |
|             author="Person 2",
 | |
|             pub_date=datetime.datetime(2005, 8, 1, 10, 0),
 | |
|         )
 | |
|         c2.save()
 | |
|         c3 = ArticleWithAuthor(
 | |
|             headline="ArticleWithAuthor 3",
 | |
|             author="Person 3",
 | |
|             pub_date=datetime.datetime(2005, 8, 2),
 | |
|         )
 | |
|         c3.save()
 | |
| 
 | |
|         self.assertEqual(c1.get_next_by_pub_date(), c2)
 | |
|         self.assertEqual(c2.get_next_by_pub_date(), c3)
 | |
|         with self.assertRaises(ArticleWithAuthor.DoesNotExist):
 | |
|             c3.get_next_by_pub_date()
 | |
|         self.assertEqual(c3.get_previous_by_pub_date(), c2)
 | |
|         self.assertEqual(c2.get_previous_by_pub_date(), c1)
 | |
|         with self.assertRaises(ArticleWithAuthor.DoesNotExist):
 | |
|             c1.get_previous_by_pub_date()
 | |
| 
 | |
|     def test_inherited_fields(self):
 | |
|         """
 | |
|         Regression test for #8825 and #9390
 | |
|         Make sure all inherited fields (esp. m2m fields, in this case) appear
 | |
|         on the child class.
 | |
|         """
 | |
|         m2mchildren = list(M2MChild.objects.filter(articles__isnull=False))
 | |
|         self.assertEqual(m2mchildren, [])
 | |
| 
 | |
|         # Ordering should not include any database column more than once (this
 | |
|         # is most likely to occur naturally with model inheritance, so we
 | |
|         # check it here). Regression test for #9390. This necessarily pokes at
 | |
|         # the SQL string for the query, since the duplicate problems are only
 | |
|         # apparent at that late stage.
 | |
|         qs = ArticleWithAuthor.objects.order_by("pub_date", "pk")
 | |
|         sql = qs.query.get_compiler(qs.db).as_sql()[0]
 | |
|         fragment = sql[sql.find("ORDER BY") :]
 | |
|         pos = fragment.find("pub_date")
 | |
|         self.assertEqual(fragment.find("pub_date", pos + 1), -1)
 | |
| 
 | |
|     def test_queryset_update_on_parent_model(self):
 | |
|         """
 | |
|         Regression test for #10362
 | |
|         It is possible to call update() and only change a field in
 | |
|         an ancestor model.
 | |
|         """
 | |
|         article = ArticleWithAuthor.objects.create(
 | |
|             author="fred",
 | |
|             headline="Hey there!",
 | |
|             pub_date=datetime.datetime(2009, 3, 1, 8, 0, 0),
 | |
|         )
 | |
|         update = ArticleWithAuthor.objects.filter(author="fred").update(
 | |
|             headline="Oh, no!"
 | |
|         )
 | |
|         self.assertEqual(update, 1)
 | |
|         update = ArticleWithAuthor.objects.filter(pk=article.pk).update(
 | |
|             headline="Oh, no!"
 | |
|         )
 | |
|         self.assertEqual(update, 1)
 | |
| 
 | |
|         derivedm1 = DerivedM.objects.create(
 | |
|             customPK=44,
 | |
|             base_name="b1",
 | |
|             derived_name="d1",
 | |
|         )
 | |
|         self.assertEqual(derivedm1.customPK, 44)
 | |
|         self.assertEqual(derivedm1.base_name, "b1")
 | |
|         self.assertEqual(derivedm1.derived_name, "d1")
 | |
|         derivedms = list(DerivedM.objects.all())
 | |
|         self.assertEqual(derivedms, [derivedm1])
 | |
| 
 | |
|     def test_use_explicit_o2o_to_parent_as_pk(self):
 | |
|         """
 | |
|         The connector from child to parent need not be the pk on the child.
 | |
|         """
 | |
|         self.assertEqual(ParkingLot3._meta.pk.name, "primary_key")
 | |
|         # the child->parent link
 | |
|         self.assertEqual(ParkingLot3._meta.get_ancestor_link(Place).name, "parent")
 | |
| 
 | |
|     def test_use_explicit_o2o_to_parent_from_abstract_model(self):
 | |
|         self.assertEqual(ParkingLot4A._meta.pk.name, "parent")
 | |
|         ParkingLot4A.objects.create(
 | |
|             name="Parking4A",
 | |
|             address="21 Jump Street",
 | |
|         )
 | |
| 
 | |
|         self.assertEqual(ParkingLot4B._meta.pk.name, "parent")
 | |
|         ParkingLot4A.objects.create(
 | |
|             name="Parking4B",
 | |
|             address="21 Jump Street",
 | |
|         )
 | |
| 
 | |
|     def test_all_fields_from_abstract_base_class(self):
 | |
|         """
 | |
|         Regression tests for #7588
 | |
|         """
 | |
|         # All fields from an ABC, including those inherited non-abstractly
 | |
|         # should be available on child classes (#7588). Creating this instance
 | |
|         # should work without error.
 | |
|         QualityControl.objects.create(
 | |
|             headline="Problems in Django",
 | |
|             pub_date=datetime.datetime.now(),
 | |
|             quality=10,
 | |
|             assignee="adrian",
 | |
|         )
 | |
| 
 | |
|     def test_abstract_base_class_m2m_relation_inheritance(self):
 | |
|         # many-to-many relations defined on an abstract base class are
 | |
|         # correctly inherited (and created) on the child class.
 | |
|         p1 = Person.objects.create(name="Alice")
 | |
|         p2 = Person.objects.create(name="Bob")
 | |
|         p3 = Person.objects.create(name="Carol")
 | |
|         p4 = Person.objects.create(name="Dave")
 | |
| 
 | |
|         birthday = BirthdayParty.objects.create(name="Birthday party for Alice")
 | |
|         birthday.attendees.set([p1, p3])
 | |
| 
 | |
|         bachelor = BachelorParty.objects.create(name="Bachelor party for Bob")
 | |
|         bachelor.attendees.set([p2, p4])
 | |
| 
 | |
|         parties = list(p1.birthdayparty_set.all())
 | |
|         self.assertEqual(parties, [birthday])
 | |
| 
 | |
|         parties = list(p1.bachelorparty_set.all())
 | |
|         self.assertEqual(parties, [])
 | |
| 
 | |
|         parties = list(p2.bachelorparty_set.all())
 | |
|         self.assertEqual(parties, [bachelor])
 | |
| 
 | |
|         # A subclass of a subclass of an abstract model doesn't get its own
 | |
|         # accessor.
 | |
|         self.assertFalse(hasattr(p2, "messybachelorparty_set"))
 | |
| 
 | |
|         # ... but it does inherit the m2m from its parent
 | |
|         messy = MessyBachelorParty.objects.create(name="Bachelor party for Dave")
 | |
|         messy.attendees.set([p4])
 | |
|         messy_parent = messy.bachelorparty_ptr
 | |
| 
 | |
|         parties = list(p4.bachelorparty_set.all())
 | |
|         self.assertEqual(parties, [bachelor, messy_parent])
 | |
| 
 | |
|     def test_abstract_verbose_name_plural_inheritance(self):
 | |
|         """
 | |
|         verbose_name_plural correctly inherited from ABC if inheritance chain
 | |
|         includes an abstract model.
 | |
|         """
 | |
|         # Regression test for #11369: verbose_name_plural should be inherited
 | |
|         # from an ABC even when there are one or more intermediate
 | |
|         # abstract models in the inheritance chain, for consistency with
 | |
|         # verbose_name.
 | |
|         self.assertEqual(InternalCertificationAudit._meta.verbose_name_plural, "Audits")
 | |
| 
 | |
|     def test_inherited_nullable_exclude(self):
 | |
|         obj = SelfRefChild.objects.create(child_data=37, parent_data=42)
 | |
|         self.assertQuerySetEqual(
 | |
|             SelfRefParent.objects.exclude(self_data=72), [obj.pk], attrgetter("pk")
 | |
|         )
 | |
|         self.assertQuerySetEqual(
 | |
|             SelfRefChild.objects.exclude(self_data=72), [obj.pk], attrgetter("pk")
 | |
|         )
 | |
| 
 | |
|     def test_concrete_abstract_concrete_pk(self):
 | |
|         """
 | |
|         Primary key set correctly with concrete->abstract->concrete inheritance.
 | |
|         """
 | |
|         # Regression test for #13987: Primary key is incorrectly determined
 | |
|         # when more than one model has a concrete->abstract->concrete
 | |
|         # inheritance hierarchy.
 | |
|         self.assertEqual(
 | |
|             len(
 | |
|                 [field for field in BusStation._meta.local_fields if field.primary_key]
 | |
|             ),
 | |
|             1,
 | |
|         )
 | |
|         self.assertEqual(
 | |
|             len(
 | |
|                 [
 | |
|                     field
 | |
|                     for field in TrainStation._meta.local_fields
 | |
|                     if field.primary_key
 | |
|                 ]
 | |
|             ),
 | |
|             1,
 | |
|         )
 | |
|         self.assertIs(BusStation._meta.pk.model, BusStation)
 | |
|         self.assertIs(TrainStation._meta.pk.model, TrainStation)
 | |
| 
 | |
|     def test_inherited_unique_field_with_form(self):
 | |
|         """
 | |
|         A model which has different primary key for the parent model passes
 | |
|         unique field checking correctly (#17615).
 | |
|         """
 | |
| 
 | |
|         class ProfileForm(forms.ModelForm):
 | |
|             class Meta:
 | |
|                 model = Profile
 | |
|                 fields = "__all__"
 | |
| 
 | |
|         User.objects.create(username="user_only")
 | |
|         p = Profile.objects.create(username="user_with_profile")
 | |
|         form = ProfileForm(
 | |
|             {"username": "user_with_profile", "extra": "hello"}, instance=p
 | |
|         )
 | |
|         self.assertTrue(form.is_valid())
 | |
| 
 | |
|     def test_inheritance_joins(self):
 | |
|         # Test for #17502 - check that filtering through two levels of
 | |
|         # inheritance chain doesn't generate extra joins.
 | |
|         qs = ItalianRestaurant.objects.all()
 | |
|         self.assertEqual(str(qs.query).count("JOIN"), 2)
 | |
|         qs = ItalianRestaurant.objects.filter(name="foo")
 | |
|         self.assertEqual(str(qs.query).count("JOIN"), 2)
 | |
| 
 | |
|     @expectedFailure
 | |
|     def test_inheritance_values_joins(self):
 | |
|         # It would be nice (but not too important) to skip the middle join in
 | |
|         # this case. Skipping is possible as nothing from the middle model is
 | |
|         # used in the qs and top contains direct pointer to the bottom model.
 | |
|         qs = ItalianRestaurant.objects.values_list("serves_gnocchi").filter(name="foo")
 | |
|         self.assertEqual(str(qs.query).count("JOIN"), 1)
 | |
| 
 | |
|     def test_issue_21554(self):
 | |
|         senator = Senator.objects.create(name="John Doe", title="X", state="Y")
 | |
|         senator = Senator.objects.get(pk=senator.pk)
 | |
|         self.assertEqual(senator.name, "John Doe")
 | |
|         self.assertEqual(senator.title, "X")
 | |
|         self.assertEqual(senator.state, "Y")
 | |
| 
 | |
|     def test_inheritance_resolve_columns(self):
 | |
|         Restaurant.objects.create(
 | |
|             name="Bobs Cafe",
 | |
|             address="Somewhere",
 | |
|             serves_pizza=True,
 | |
|             serves_hot_dogs=True,
 | |
|         )
 | |
|         p = Place.objects.select_related("restaurant")[0]
 | |
|         self.assertIsInstance(p.restaurant.serves_pizza, bool)
 | |
| 
 | |
|     def test_inheritance_select_related(self):
 | |
|         # Regression test for #7246
 | |
|         r1 = Restaurant.objects.create(
 | |
|             name="Nobu", serves_hot_dogs=True, serves_pizza=False
 | |
|         )
 | |
|         r2 = Restaurant.objects.create(
 | |
|             name="Craft", serves_hot_dogs=False, serves_pizza=True
 | |
|         )
 | |
|         Supplier.objects.create(name="John", restaurant=r1)
 | |
|         Supplier.objects.create(name="Jane", restaurant=r2)
 | |
| 
 | |
|         self.assertQuerySetEqual(
 | |
|             Supplier.objects.order_by("name").select_related(),
 | |
|             [
 | |
|                 "Jane",
 | |
|                 "John",
 | |
|             ],
 | |
|             attrgetter("name"),
 | |
|         )
 | |
| 
 | |
|         jane = Supplier.objects.order_by("name").select_related("restaurant")[0]
 | |
|         self.assertEqual(jane.restaurant.name, "Craft")
 | |
| 
 | |
|     def test_filter_with_parent_fk(self):
 | |
|         r = Restaurant.objects.create()
 | |
|         s = Supplier.objects.create(restaurant=r)
 | |
|         # The mismatch between Restaurant and Place is intentional (#28175).
 | |
|         self.assertSequenceEqual(
 | |
|             Supplier.objects.filter(restaurant__in=Place.objects.all()), [s]
 | |
|         )
 | |
| 
 | |
|     def test_ptr_accessor_assigns_state(self):
 | |
|         r = Restaurant.objects.create()
 | |
|         self.assertIs(r.place_ptr._state.adding, False)
 | |
|         self.assertEqual(r.place_ptr._state.db, "default")
 | |
| 
 | |
|     def test_related_filtering_query_efficiency_ticket_15844(self):
 | |
|         r = Restaurant.objects.create(
 | |
|             name="Guido's House of Pasta",
 | |
|             address="944 W. Fullerton",
 | |
|             serves_hot_dogs=True,
 | |
|             serves_pizza=False,
 | |
|         )
 | |
|         s = Supplier.objects.create(restaurant=r)
 | |
|         with self.assertNumQueries(1):
 | |
|             self.assertSequenceEqual(Supplier.objects.filter(restaurant=r), [s])
 | |
|         with self.assertNumQueries(1):
 | |
|             self.assertSequenceEqual(r.supplier_set.all(), [s])
 | |
| 
 | |
|     def test_queries_on_parent_access(self):
 | |
|         italian_restaurant = ItalianRestaurant.objects.create(
 | |
|             name="Guido's House of Pasta",
 | |
|             address="944 W. Fullerton",
 | |
|             serves_hot_dogs=True,
 | |
|             serves_pizza=False,
 | |
|             serves_gnocchi=True,
 | |
|         )
 | |
| 
 | |
|         # No queries are made when accessing the parent objects.
 | |
|         italian_restaurant = ItalianRestaurant.objects.get(pk=italian_restaurant.pk)
 | |
|         with self.assertNumQueries(0):
 | |
|             restaurant = italian_restaurant.restaurant_ptr
 | |
|             self.assertEqual(restaurant.place_ptr.restaurant, restaurant)
 | |
|             self.assertEqual(restaurant.italianrestaurant, italian_restaurant)
 | |
| 
 | |
|         # One query is made when accessing the parent objects when the instance
 | |
|         # is deferred.
 | |
|         italian_restaurant = ItalianRestaurant.objects.only("serves_gnocchi").get(
 | |
|             pk=italian_restaurant.pk
 | |
|         )
 | |
|         with self.assertNumQueries(1):
 | |
|             restaurant = italian_restaurant.restaurant_ptr
 | |
|             self.assertEqual(restaurant.place_ptr.restaurant, restaurant)
 | |
|             self.assertEqual(restaurant.italianrestaurant, italian_restaurant)
 | |
| 
 | |
|         # No queries are made when accessing the parent objects when the
 | |
|         # instance has deferred a field not present in the parent table.
 | |
|         italian_restaurant = ItalianRestaurant.objects.defer("serves_gnocchi").get(
 | |
|             pk=italian_restaurant.pk
 | |
|         )
 | |
|         with self.assertNumQueries(0):
 | |
|             restaurant = italian_restaurant.restaurant_ptr
 | |
|             self.assertEqual(restaurant.place_ptr.restaurant, restaurant)
 | |
|             self.assertEqual(restaurant.italianrestaurant, italian_restaurant)
 | |
| 
 | |
|     def test_id_field_update_on_ancestor_change(self):
 | |
|         place1 = Place.objects.create(name="House of Pasta", address="944 Fullerton")
 | |
|         place2 = Place.objects.create(name="House of Pizza", address="954 Fullerton")
 | |
|         place3 = Place.objects.create(name="Burger house", address="964 Fullerton")
 | |
|         restaurant1 = Restaurant.objects.create(
 | |
|             place_ptr=place1,
 | |
|             serves_hot_dogs=True,
 | |
|             serves_pizza=False,
 | |
|         )
 | |
|         restaurant2 = Restaurant.objects.create(
 | |
|             place_ptr=place2,
 | |
|             serves_hot_dogs=True,
 | |
|             serves_pizza=False,
 | |
|         )
 | |
| 
 | |
|         italian_restaurant = ItalianRestaurant.objects.create(
 | |
|             restaurant_ptr=restaurant1,
 | |
|             serves_gnocchi=True,
 | |
|         )
 | |
|         # Changing the parent of a restaurant changes the restaurant's ID & PK.
 | |
|         restaurant1.place_ptr = place3
 | |
|         self.assertEqual(restaurant1.pk, place3.pk)
 | |
|         self.assertEqual(restaurant1.id, place3.id)
 | |
|         self.assertEqual(restaurant1.pk, restaurant1.id)
 | |
|         restaurant1.place_ptr = None
 | |
|         self.assertIsNone(restaurant1.pk)
 | |
|         self.assertIsNone(restaurant1.id)
 | |
|         # Changing the parent of an italian restaurant changes the restaurant's
 | |
|         # ID & PK.
 | |
|         italian_restaurant.restaurant_ptr = restaurant2
 | |
|         self.assertEqual(italian_restaurant.pk, restaurant2.pk)
 | |
|         self.assertEqual(italian_restaurant.id, restaurant2.id)
 | |
|         self.assertEqual(italian_restaurant.pk, italian_restaurant.id)
 | |
|         italian_restaurant.restaurant_ptr = None
 | |
|         self.assertIsNone(italian_restaurant.pk)
 | |
|         self.assertIsNone(italian_restaurant.id)
 | |
| 
 | |
|     def test_create_new_instance_with_pk_equals_none(self):
 | |
|         p1 = Profile.objects.create(username="john")
 | |
|         p2 = User.objects.get(pk=p1.user_ptr_id).profile
 | |
|         # Create a new profile by setting pk = None.
 | |
|         p2.pk = None
 | |
|         p2.user_ptr_id = None
 | |
|         p2.username = "bill"
 | |
|         p2.save()
 | |
|         self.assertEqual(Profile.objects.count(), 2)
 | |
|         self.assertEqual(User.objects.get(pk=p1.user_ptr_id).username, "john")
 | |
| 
 | |
|     def test_create_new_instance_with_pk_equals_none_multi_inheritance(self):
 | |
|         c1 = Congressman.objects.create(state="PA", name="John", title="senator 1")
 | |
|         c2 = Person.objects.get(pk=c1.pk).congressman
 | |
|         # Create a new congressman by setting pk = None.
 | |
|         c2.pk = None
 | |
|         c2.id = None
 | |
|         c2.politician_ptr_id = None
 | |
|         c2.name = "Bill"
 | |
|         c2.title = "senator 2"
 | |
|         c2.save()
 | |
|         self.assertEqual(Congressman.objects.count(), 2)
 | |
|         self.assertEqual(Person.objects.get(pk=c1.pk).name, "John")
 | |
|         self.assertEqual(
 | |
|             Politician.objects.get(pk=c1.politician_ptr_id).title,
 | |
|             "senator 1",
 | |
|         )
 | |
| 
 | |
|     def test_mti_update_parent_through_child(self):
 | |
|         Politician.objects.create()
 | |
|         Congressman.objects.create()
 | |
|         Congressman.objects.update(title="senator 1")
 | |
|         self.assertEqual(Congressman.objects.get().title, "senator 1")
 | |
| 
 | |
|     def test_mti_update_grand_parent_through_child(self):
 | |
|         Politician.objects.create()
 | |
|         Senator.objects.create()
 | |
|         Senator.objects.update(title="senator 1")
 | |
|         self.assertEqual(Senator.objects.get().title, "senator 1")
 |