1. from django.db import IntegrityError, connection, transaction
    
  2. from django.test import TestCase
    
  3. 
    
  4. from .models import (
    
  5.     Bar,
    
  6.     Director,
    
  7.     Favorites,
    
  8.     HiddenPointer,
    
  9.     ManualPrimaryKey,
    
  10.     MultiModel,
    
  11.     Place,
    
  12.     Pointer,
    
  13.     RelatedModel,
    
  14.     Restaurant,
    
  15.     School,
    
  16.     Target,
    
  17.     ToFieldPointer,
    
  18.     UndergroundBar,
    
  19.     Waiter,
    
  20. )
    
  21. 
    
  22. 
    
  23. class OneToOneTests(TestCase):
    
  24.     @classmethod
    
  25.     def setUpTestData(cls):
    
  26.         cls.p1 = Place.objects.create(name="Demon Dogs", address="944 W. Fullerton")
    
  27.         cls.p2 = Place.objects.create(name="Ace Hardware", address="1013 N. Ashland")
    
  28.         cls.r1 = Restaurant.objects.create(
    
  29.             place=cls.p1, serves_hot_dogs=True, serves_pizza=False
    
  30.         )
    
  31.         cls.b1 = Bar.objects.create(place=cls.p1, serves_cocktails=False)
    
  32. 
    
  33.     def test_getter(self):
    
  34.         # A Restaurant can access its place.
    
  35.         self.assertEqual(repr(self.r1.place), "<Place: Demon Dogs the place>")
    
  36.         # A Place can access its restaurant, if available.
    
  37.         self.assertEqual(
    
  38.             repr(self.p1.restaurant), "<Restaurant: Demon Dogs the restaurant>"
    
  39.         )
    
  40.         # p2 doesn't have an associated restaurant.
    
  41.         with self.assertRaisesMessage(
    
  42.             Restaurant.DoesNotExist, "Place has no restaurant"
    
  43.         ):
    
  44.             self.p2.restaurant
    
  45.         # The exception raised on attribute access when a related object
    
  46.         # doesn't exist should be an instance of a subclass of `AttributeError`
    
  47.         # refs #21563
    
  48.         self.assertFalse(hasattr(self.p2, "restaurant"))
    
  49. 
    
  50.     def test_setter(self):
    
  51.         # Set the place using assignment notation. Because place is the primary
    
  52.         # key on Restaurant, the save will create a new restaurant
    
  53.         self.r1.place = self.p2
    
  54.         self.r1.save()
    
  55.         self.assertEqual(
    
  56.             repr(self.p2.restaurant), "<Restaurant: Ace Hardware the restaurant>"
    
  57.         )
    
  58.         self.assertEqual(repr(self.r1.place), "<Place: Ace Hardware the place>")
    
  59.         self.assertEqual(self.p2.pk, self.r1.pk)
    
  60.         # Set the place back again, using assignment in the reverse direction.
    
  61.         self.p1.restaurant = self.r1
    
  62.         self.assertEqual(
    
  63.             repr(self.p1.restaurant), "<Restaurant: Demon Dogs the restaurant>"
    
  64.         )
    
  65.         r = Restaurant.objects.get(pk=self.p1.id)
    
  66.         self.assertEqual(repr(r.place), "<Place: Demon Dogs the place>")
    
  67. 
    
  68.     def test_manager_all(self):
    
  69.         # Restaurant.objects.all() just returns the Restaurants, not the Places.
    
  70.         self.assertSequenceEqual(Restaurant.objects.all(), [self.r1])
    
  71.         # Place.objects.all() returns all Places, regardless of whether they
    
  72.         # have Restaurants.
    
  73.         self.assertSequenceEqual(Place.objects.order_by("name"), [self.p2, self.p1])
    
  74. 
    
  75.     def test_manager_get(self):
    
  76.         def assert_get_restaurant(**params):
    
  77.             self.assertEqual(
    
  78.                 repr(Restaurant.objects.get(**params)),
    
  79.                 "<Restaurant: Demon Dogs the restaurant>",
    
  80.             )
    
  81. 
    
  82.         assert_get_restaurant(place__id__exact=self.p1.pk)
    
  83.         assert_get_restaurant(place__id=self.p1.pk)
    
  84.         assert_get_restaurant(place__exact=self.p1.pk)
    
  85.         assert_get_restaurant(place__exact=self.p1)
    
  86.         assert_get_restaurant(place=self.p1.pk)
    
  87.         assert_get_restaurant(place=self.p1)
    
  88.         assert_get_restaurant(pk=self.p1.pk)
    
  89.         assert_get_restaurant(place__pk__exact=self.p1.pk)
    
  90.         assert_get_restaurant(place__pk=self.p1.pk)
    
  91.         assert_get_restaurant(place__name__startswith="Demon")
    
  92. 
    
  93.         def assert_get_place(**params):
    
  94.             self.assertEqual(
    
  95.                 repr(Place.objects.get(**params)), "<Place: Demon Dogs the place>"
    
  96.             )
    
  97. 
    
  98.         assert_get_place(restaurant__place__exact=self.p1.pk)
    
  99.         assert_get_place(restaurant__place__exact=self.p1)
    
  100.         assert_get_place(restaurant__place__pk=self.p1.pk)
    
  101.         assert_get_place(restaurant__exact=self.p1.pk)
    
  102.         assert_get_place(restaurant__exact=self.r1)
    
  103.         assert_get_place(restaurant__pk=self.p1.pk)
    
  104.         assert_get_place(restaurant=self.p1.pk)
    
  105.         assert_get_place(restaurant=self.r1)
    
  106.         assert_get_place(id__exact=self.p1.pk)
    
  107.         assert_get_place(pk=self.p1.pk)
    
  108. 
    
  109.     def test_foreign_key(self):
    
  110.         # Add a Waiter to the Restaurant.
    
  111.         w = self.r1.waiter_set.create(name="Joe")
    
  112.         self.assertEqual(
    
  113.             repr(w), "<Waiter: Joe the waiter at Demon Dogs the restaurant>"
    
  114.         )
    
  115. 
    
  116.         # Query the waiters
    
  117.         def assert_filter_waiters(**params):
    
  118.             self.assertSequenceEqual(Waiter.objects.filter(**params), [w])
    
  119. 
    
  120.         assert_filter_waiters(restaurant__place__exact=self.p1.pk)
    
  121.         assert_filter_waiters(restaurant__place__exact=self.p1)
    
  122.         assert_filter_waiters(restaurant__place__pk=self.p1.pk)
    
  123.         assert_filter_waiters(restaurant__exact=self.r1.pk)
    
  124.         assert_filter_waiters(restaurant__exact=self.r1)
    
  125.         assert_filter_waiters(restaurant__pk=self.r1.pk)
    
  126.         assert_filter_waiters(restaurant=self.r1.pk)
    
  127.         assert_filter_waiters(restaurant=self.r1)
    
  128.         assert_filter_waiters(id__exact=w.pk)
    
  129.         assert_filter_waiters(pk=w.pk)
    
  130.         # Delete the restaurant; the waiter should also be removed
    
  131.         r = Restaurant.objects.get(pk=self.r1.pk)
    
  132.         r.delete()
    
  133.         self.assertEqual(Waiter.objects.count(), 0)
    
  134. 
    
  135.     def test_multiple_o2o(self):
    
  136.         # One-to-one fields still work if you create your own primary key
    
  137.         o1 = ManualPrimaryKey(primary_key="abc123", name="primary")
    
  138.         o1.save()
    
  139.         o2 = RelatedModel(link=o1, name="secondary")
    
  140.         o2.save()
    
  141. 
    
  142.         # You can have multiple one-to-one fields on a model, too.
    
  143.         x1 = MultiModel(link1=self.p1, link2=o1, name="x1")
    
  144.         x1.save()
    
  145.         self.assertEqual(repr(o1.multimodel), "<MultiModel: Multimodel x1>")
    
  146.         # This will fail because each one-to-one field must be unique (and
    
  147.         # link2=o1 was used for x1, above).
    
  148.         mm = MultiModel(link1=self.p2, link2=o1, name="x1")
    
  149.         with self.assertRaises(IntegrityError):
    
  150.             with transaction.atomic():
    
  151.                 mm.save()
    
  152. 
    
  153.     def test_unsaved_object(self):
    
  154.         """
    
  155.         #10811 -- Assigning an unsaved object to a OneToOneField
    
  156.         should raise an exception.
    
  157.         """
    
  158.         place = Place(name="User", address="London")
    
  159.         with self.assertRaises(Restaurant.DoesNotExist):
    
  160.             place.restaurant
    
  161.         msg = (
    
  162.             "save() prohibited to prevent data loss due to unsaved related object "
    
  163.             "'place'."
    
  164.         )
    
  165.         with self.assertRaisesMessage(ValueError, msg):
    
  166.             Restaurant.objects.create(
    
  167.                 place=place, serves_hot_dogs=True, serves_pizza=False
    
  168.             )
    
  169.         # place should not cache restaurant
    
  170.         with self.assertRaises(Restaurant.DoesNotExist):
    
  171.             place.restaurant
    
  172. 
    
  173.     def test_reverse_relationship_cache_cascade(self):
    
  174.         """
    
  175.         Regression test for #9023: accessing the reverse relationship shouldn't
    
  176.         result in a cascading delete().
    
  177.         """
    
  178.         bar = UndergroundBar.objects.create(place=self.p1, serves_cocktails=False)
    
  179. 
    
  180.         # The bug in #9023: if you access the one-to-one relation *before*
    
  181.         # setting to None and deleting, the cascade happens anyway.
    
  182.         self.p1.undergroundbar
    
  183.         bar.place.name = "foo"
    
  184.         bar.place = None
    
  185.         bar.save()
    
  186.         self.p1.delete()
    
  187. 
    
  188.         self.assertEqual(Place.objects.count(), 1)
    
  189.         self.assertEqual(UndergroundBar.objects.count(), 1)
    
  190. 
    
  191.     def test_create_models_m2m(self):
    
  192.         """
    
  193.         Models are created via the m2m relation if the remote model has a
    
  194.         OneToOneField (#1064, #1506).
    
  195.         """
    
  196.         f = Favorites(name="Fred")
    
  197.         f.save()
    
  198.         f.restaurants.set([self.r1])
    
  199.         self.assertSequenceEqual(f.restaurants.all(), [self.r1])
    
  200. 
    
  201.     def test_reverse_object_cache(self):
    
  202.         """
    
  203.         The name of the cache for the reverse object is correct (#7173).
    
  204.         """
    
  205.         self.assertEqual(self.p1.restaurant, self.r1)
    
  206.         self.assertEqual(self.p1.bar, self.b1)
    
  207. 
    
  208.     def test_assign_none_reverse_relation(self):
    
  209.         p = Place.objects.get(name="Demon Dogs")
    
  210.         # Assigning None succeeds if field is null=True.
    
  211.         ug_bar = UndergroundBar.objects.create(place=p, serves_cocktails=False)
    
  212.         p.undergroundbar = None
    
  213.         self.assertIsNone(ug_bar.place)
    
  214.         ug_bar.save()
    
  215.         ug_bar.refresh_from_db()
    
  216.         self.assertIsNone(ug_bar.place)
    
  217. 
    
  218.     def test_assign_none_null_reverse_relation(self):
    
  219.         p = Place.objects.get(name="Demon Dogs")
    
  220.         # Assigning None doesn't throw AttributeError if there isn't a related
    
  221.         # UndergroundBar.
    
  222.         p.undergroundbar = None
    
  223. 
    
  224.     def test_assign_none_to_null_cached_reverse_relation(self):
    
  225.         p = Place.objects.get(name="Demon Dogs")
    
  226.         # Prime the relation's cache with a value of None.
    
  227.         with self.assertRaises(Place.undergroundbar.RelatedObjectDoesNotExist):
    
  228.             getattr(p, "undergroundbar")
    
  229.         # Assigning None works if there isn't a related UndergroundBar and the
    
  230.         # reverse cache has a value of None.
    
  231.         p.undergroundbar = None
    
  232. 
    
  233.     def test_assign_o2o_id_value(self):
    
  234.         b = UndergroundBar.objects.create(place=self.p1)
    
  235.         b.place_id = self.p2.pk
    
  236.         b.save()
    
  237.         self.assertEqual(b.place_id, self.p2.pk)
    
  238.         self.assertFalse(UndergroundBar.place.is_cached(b))
    
  239.         self.assertEqual(b.place, self.p2)
    
  240.         self.assertTrue(UndergroundBar.place.is_cached(b))
    
  241.         # Reassigning the same value doesn't clear a cached instance.
    
  242.         b.place_id = self.p2.pk
    
  243.         self.assertTrue(UndergroundBar.place.is_cached(b))
    
  244. 
    
  245.     def test_assign_o2o_id_none(self):
    
  246.         b = UndergroundBar.objects.create(place=self.p1)
    
  247.         b.place_id = None
    
  248.         b.save()
    
  249.         self.assertIsNone(b.place_id)
    
  250.         self.assertFalse(UndergroundBar.place.is_cached(b))
    
  251.         self.assertIsNone(b.place)
    
  252.         self.assertTrue(UndergroundBar.place.is_cached(b))
    
  253. 
    
  254.     def test_related_object_cache(self):
    
  255.         """Regression test for #6886 (the related-object cache)"""
    
  256. 
    
  257.         # Look up the objects again so that we get "fresh" objects
    
  258.         p = Place.objects.get(name="Demon Dogs")
    
  259.         r = p.restaurant
    
  260. 
    
  261.         # Accessing the related object again returns the exactly same object
    
  262.         self.assertIs(p.restaurant, r)
    
  263. 
    
  264.         # But if we kill the cache, we get a new object
    
  265.         del p._state.fields_cache["restaurant"]
    
  266.         self.assertIsNot(p.restaurant, r)
    
  267. 
    
  268.         # Reassigning the Restaurant object results in an immediate cache update
    
  269.         # We can't use a new Restaurant because that'll violate one-to-one, but
    
  270.         # with a new *instance* the is test below will fail if #6886 regresses.
    
  271.         r2 = Restaurant.objects.get(pk=r.pk)
    
  272.         p.restaurant = r2
    
  273.         self.assertIs(p.restaurant, r2)
    
  274. 
    
  275.         # Assigning None succeeds if field is null=True.
    
  276.         ug_bar = UndergroundBar.objects.create(place=p, serves_cocktails=False)
    
  277.         ug_bar.place = None
    
  278.         self.assertIsNone(ug_bar.place)
    
  279. 
    
  280.         # Assigning None will not fail: Place.restaurant is null=False
    
  281.         setattr(p, "restaurant", None)
    
  282. 
    
  283.         # You also can't assign an object of the wrong type here
    
  284.         msg = (
    
  285.             'Cannot assign "<Place: Demon Dogs the place>": '
    
  286.             '"Place.restaurant" must be a "Restaurant" instance.'
    
  287.         )
    
  288.         with self.assertRaisesMessage(ValueError, msg):
    
  289.             setattr(p, "restaurant", p)
    
  290. 
    
  291.         # Creation using keyword argument should cache the related object.
    
  292.         p = Place.objects.get(name="Demon Dogs")
    
  293.         r = Restaurant(place=p)
    
  294.         self.assertIs(r.place, p)
    
  295. 
    
  296.         # Creation using keyword argument and unsaved related instance (#8070).
    
  297.         p = Place()
    
  298.         r = Restaurant(place=p)
    
  299.         self.assertIs(r.place, p)
    
  300. 
    
  301.         # Creation using attname keyword argument and an id will cause the related
    
  302.         # object to be fetched.
    
  303.         p = Place.objects.get(name="Demon Dogs")
    
  304.         r = Restaurant(place_id=p.id)
    
  305.         self.assertIsNot(r.place, p)
    
  306.         self.assertEqual(r.place, p)
    
  307. 
    
  308.     def test_filter_one_to_one_relations(self):
    
  309.         """
    
  310.         Regression test for #9968
    
  311. 
    
  312.         filtering reverse one-to-one relations with primary_key=True was
    
  313.         misbehaving. We test both (primary_key=True & False) cases here to
    
  314.         prevent any reappearance of the problem.
    
  315.         """
    
  316.         target = Target.objects.create()
    
  317.         self.assertSequenceEqual(Target.objects.filter(pointer=None), [target])
    
  318.         self.assertSequenceEqual(Target.objects.exclude(pointer=None), [])
    
  319.         self.assertSequenceEqual(Target.objects.filter(second_pointer=None), [target])
    
  320.         self.assertSequenceEqual(Target.objects.exclude(second_pointer=None), [])
    
  321. 
    
  322.     def test_o2o_primary_key_delete(self):
    
  323.         t = Target.objects.create(name="name")
    
  324.         Pointer.objects.create(other=t)
    
  325.         num_deleted, objs = Pointer.objects.filter(other__name="name").delete()
    
  326.         self.assertEqual(num_deleted, 1)
    
  327.         self.assertEqual(objs, {"one_to_one.Pointer": 1})
    
  328. 
    
  329.     def test_save_nullable_o2o_after_parent(self):
    
  330.         place = Place(name="Rose tattoo")
    
  331.         bar = UndergroundBar(place=place)
    
  332.         place.save()
    
  333.         bar.save()
    
  334.         bar.refresh_from_db()
    
  335.         self.assertEqual(bar.place, place)
    
  336. 
    
  337.     def test_reverse_object_does_not_exist_cache(self):
    
  338.         """
    
  339.         Regression for #13839 and #17439.
    
  340. 
    
  341.         DoesNotExist on a reverse one-to-one relation is cached.
    
  342.         """
    
  343.         p = Place(name="Zombie Cats", address="Not sure")
    
  344.         p.save()
    
  345.         with self.assertNumQueries(1):
    
  346.             with self.assertRaises(Restaurant.DoesNotExist):
    
  347.                 p.restaurant
    
  348.         with self.assertNumQueries(0):
    
  349.             with self.assertRaises(Restaurant.DoesNotExist):
    
  350.                 p.restaurant
    
  351. 
    
  352.     def test_reverse_object_cached_when_related_is_accessed(self):
    
  353.         """
    
  354.         Regression for #13839 and #17439.
    
  355. 
    
  356.         The target of a one-to-one relation is cached
    
  357.         when the origin is accessed through the reverse relation.
    
  358.         """
    
  359.         # Use a fresh object without caches
    
  360.         r = Restaurant.objects.get(pk=self.r1.pk)
    
  361.         p = r.place
    
  362.         with self.assertNumQueries(0):
    
  363.             self.assertEqual(p.restaurant, r)
    
  364. 
    
  365.     def test_related_object_cached_when_reverse_is_accessed(self):
    
  366.         """
    
  367.         Regression for #13839 and #17439.
    
  368. 
    
  369.         The origin of a one-to-one relation is cached
    
  370.         when the target is accessed through the reverse relation.
    
  371.         """
    
  372.         # Use a fresh object without caches
    
  373.         p = Place.objects.get(pk=self.p1.pk)
    
  374.         r = p.restaurant
    
  375.         with self.assertNumQueries(0):
    
  376.             self.assertEqual(r.place, p)
    
  377. 
    
  378.     def test_reverse_object_cached_when_related_is_set(self):
    
  379.         """
    
  380.         Regression for #13839 and #17439.
    
  381. 
    
  382.         The target of a one-to-one relation is always cached.
    
  383.         """
    
  384.         p = Place(name="Zombie Cats", address="Not sure")
    
  385.         p.save()
    
  386.         self.r1.place = p
    
  387.         self.r1.save()
    
  388.         with self.assertNumQueries(0):
    
  389.             self.assertEqual(p.restaurant, self.r1)
    
  390. 
    
  391.     def test_reverse_object_cached_when_related_is_unset(self):
    
  392.         """
    
  393.         Regression for #13839 and #17439.
    
  394. 
    
  395.         The target of a one-to-one relation is always cached.
    
  396.         """
    
  397.         b = UndergroundBar(place=self.p1, serves_cocktails=True)
    
  398.         b.save()
    
  399.         with self.assertNumQueries(0):
    
  400.             self.assertEqual(self.p1.undergroundbar, b)
    
  401.         b.place = None
    
  402.         b.save()
    
  403.         with self.assertNumQueries(0):
    
  404.             with self.assertRaises(UndergroundBar.DoesNotExist):
    
  405.                 self.p1.undergroundbar
    
  406. 
    
  407.     def test_get_reverse_on_unsaved_object(self):
    
  408.         """
    
  409.         Regression for #18153 and #19089.
    
  410. 
    
  411.         Accessing the reverse relation on an unsaved object
    
  412.         always raises an exception.
    
  413.         """
    
  414.         p = Place()
    
  415. 
    
  416.         # When there's no instance of the origin of the one-to-one
    
  417.         with self.assertNumQueries(0):
    
  418.             with self.assertRaises(UndergroundBar.DoesNotExist):
    
  419.                 p.undergroundbar
    
  420. 
    
  421.         UndergroundBar.objects.create()
    
  422. 
    
  423.         # When there's one instance of the origin
    
  424.         # (p.undergroundbar used to return that instance)
    
  425.         with self.assertNumQueries(0):
    
  426.             with self.assertRaises(UndergroundBar.DoesNotExist):
    
  427.                 p.undergroundbar
    
  428. 
    
  429.         # Several instances of the origin are only possible if database allows
    
  430.         # inserting multiple NULL rows for a unique constraint
    
  431.         if connection.features.supports_nullable_unique_constraints:
    
  432.             UndergroundBar.objects.create()
    
  433. 
    
  434.             # When there are several instances of the origin
    
  435.             with self.assertNumQueries(0):
    
  436.                 with self.assertRaises(UndergroundBar.DoesNotExist):
    
  437.                     p.undergroundbar
    
  438. 
    
  439.     def test_set_reverse_on_unsaved_object(self):
    
  440.         """
    
  441.         Writing to the reverse relation on an unsaved object
    
  442.         is impossible too.
    
  443.         """
    
  444.         p = Place()
    
  445.         b = UndergroundBar.objects.create()
    
  446. 
    
  447.         # Assigning a reverse relation on an unsaved object is allowed.
    
  448.         p.undergroundbar = b
    
  449. 
    
  450.         # However saving the object is not allowed.
    
  451.         msg = (
    
  452.             "save() prohibited to prevent data loss due to unsaved related object "
    
  453.             "'place'."
    
  454.         )
    
  455.         with self.assertNumQueries(0):
    
  456.             with self.assertRaisesMessage(ValueError, msg):
    
  457.                 b.save()
    
  458. 
    
  459.     def test_nullable_o2o_delete(self):
    
  460.         u = UndergroundBar.objects.create(place=self.p1)
    
  461.         u.place_id = None
    
  462.         u.save()
    
  463.         self.p1.delete()
    
  464.         self.assertTrue(UndergroundBar.objects.filter(pk=u.pk).exists())
    
  465.         self.assertIsNone(UndergroundBar.objects.get(pk=u.pk).place)
    
  466. 
    
  467.     def test_hidden_accessor(self):
    
  468.         """
    
  469.         When a '+' ending related name is specified no reverse accessor should
    
  470.         be added to the related model.
    
  471.         """
    
  472.         self.assertFalse(
    
  473.             hasattr(
    
  474.                 Target,
    
  475.                 HiddenPointer._meta.get_field(
    
  476.                     "target"
    
  477.                 ).remote_field.get_accessor_name(),
    
  478.             )
    
  479.         )
    
  480. 
    
  481.     def test_related_object(self):
    
  482.         public_school = School.objects.create(is_public=True)
    
  483.         public_director = Director.objects.create(school=public_school, is_temp=False)
    
  484. 
    
  485.         private_school = School.objects.create(is_public=False)
    
  486.         private_director = Director.objects.create(school=private_school, is_temp=True)
    
  487. 
    
  488.         # Only one school is available via all() due to the custom default manager.
    
  489.         self.assertSequenceEqual(School.objects.all(), [public_school])
    
  490. 
    
  491.         # Only one director is available via all() due to the custom default manager.
    
  492.         self.assertSequenceEqual(Director.objects.all(), [public_director])
    
  493. 
    
  494.         self.assertEqual(public_director.school, public_school)
    
  495.         self.assertEqual(public_school.director, public_director)
    
  496. 
    
  497.         # Make sure the base manager is used so that the related objects
    
  498.         # is still accessible even if the default manager doesn't normally
    
  499.         # allow it.
    
  500.         self.assertEqual(private_director.school, private_school)
    
  501. 
    
  502.         # Make sure the base manager is used so that an student can still access
    
  503.         # its related school even if the default manager doesn't normally
    
  504.         # allow it.
    
  505.         self.assertEqual(private_school.director, private_director)
    
  506. 
    
  507.         School._meta.base_manager_name = "objects"
    
  508.         School._meta._expire_cache()
    
  509.         try:
    
  510.             private_director = Director._base_manager.get(pk=private_director.pk)
    
  511.             with self.assertRaises(School.DoesNotExist):
    
  512.                 private_director.school
    
  513.         finally:
    
  514.             School._meta.base_manager_name = None
    
  515.             School._meta._expire_cache()
    
  516. 
    
  517.         Director._meta.base_manager_name = "objects"
    
  518.         Director._meta._expire_cache()
    
  519.         try:
    
  520.             private_school = School._base_manager.get(pk=private_school.pk)
    
  521.             with self.assertRaises(Director.DoesNotExist):
    
  522.                 private_school.director
    
  523.         finally:
    
  524.             Director._meta.base_manager_name = None
    
  525.             Director._meta._expire_cache()
    
  526. 
    
  527.     def test_hasattr_related_object(self):
    
  528.         # The exception raised on attribute access when a related object
    
  529.         # doesn't exist should be an instance of a subclass of `AttributeError`
    
  530.         # refs #21563
    
  531.         self.assertFalse(hasattr(Director(), "director"))
    
  532.         self.assertFalse(hasattr(School(), "school"))
    
  533. 
    
  534.     def test_update_one_to_one_pk(self):
    
  535.         p1 = Place.objects.create()
    
  536.         p2 = Place.objects.create()
    
  537.         r1 = Restaurant.objects.create(place=p1)
    
  538.         r2 = Restaurant.objects.create(place=p2)
    
  539.         w = Waiter.objects.create(restaurant=r1)
    
  540. 
    
  541.         Waiter.objects.update(restaurant=r2)
    
  542.         w.refresh_from_db()
    
  543.         self.assertEqual(w.restaurant, r2)
    
  544. 
    
  545.     def test_rel_pk_subquery(self):
    
  546.         r = Restaurant.objects.first()
    
  547.         q1 = Restaurant.objects.filter(place_id=r.pk)
    
  548.         # Subquery using primary key and a query against the
    
  549.         # same model works correctly.
    
  550.         q2 = Restaurant.objects.filter(place_id__in=q1)
    
  551.         self.assertSequenceEqual(q2, [r])
    
  552.         # Subquery using 'pk__in' instead of 'place_id__in' work, too.
    
  553.         q2 = Restaurant.objects.filter(
    
  554.             pk__in=Restaurant.objects.filter(place__id=r.place.pk)
    
  555.         )
    
  556.         self.assertSequenceEqual(q2, [r])
    
  557.         q3 = Restaurant.objects.filter(place__in=Place.objects.all())
    
  558.         self.assertSequenceEqual(q3, [r])
    
  559.         q4 = Restaurant.objects.filter(place__in=Place.objects.filter(id=r.pk))
    
  560.         self.assertSequenceEqual(q4, [r])
    
  561. 
    
  562.     def test_rel_pk_exact(self):
    
  563.         r = Restaurant.objects.first()
    
  564.         r2 = Restaurant.objects.filter(pk__exact=r).first()
    
  565.         self.assertEqual(r, r2)
    
  566. 
    
  567.     def test_primary_key_to_field_filter(self):
    
  568.         target = Target.objects.create(name="foo")
    
  569.         pointer = ToFieldPointer.objects.create(target=target)
    
  570.         self.assertSequenceEqual(
    
  571.             ToFieldPointer.objects.filter(target=target), [pointer]
    
  572.         )
    
  573.         self.assertSequenceEqual(
    
  574.             ToFieldPointer.objects.filter(pk__exact=pointer), [pointer]
    
  575.         )
    
  576. 
    
  577.     def test_cached_relation_invalidated_on_save(self):
    
  578.         """
    
  579.         Model.save() invalidates stale OneToOneField relations after a primary
    
  580.         key assignment.
    
  581.         """
    
  582.         self.assertEqual(self.b1.place, self.p1)  # caches b1.place
    
  583.         self.b1.place_id = self.p2.pk
    
  584.         self.b1.save()
    
  585.         self.assertEqual(self.b1.place, self.p2)