1. from django.apps.registry import Apps
    
  2. from django.contrib.contenttypes.fields import GenericForeignKey
    
  3. from django.db import models
    
  4. from django.db.migrations.exceptions import InvalidBasesError
    
  5. from django.db.migrations.operations import (
    
  6.     AddField,
    
  7.     AlterField,
    
  8.     DeleteModel,
    
  9.     RemoveField,
    
  10. )
    
  11. from django.db.migrations.state import (
    
  12.     ModelState,
    
  13.     ProjectState,
    
  14.     get_related_models_recursive,
    
  15. )
    
  16. from django.test import SimpleTestCase, override_settings
    
  17. from django.test.utils import isolate_apps
    
  18. 
    
  19. from .models import (
    
  20.     FoodManager,
    
  21.     FoodQuerySet,
    
  22.     ModelWithCustomBase,
    
  23.     NoMigrationFoodManager,
    
  24.     UnicodeModel,
    
  25. )
    
  26. 
    
  27. 
    
  28. class StateTests(SimpleTestCase):
    
  29.     """
    
  30.     Tests state construction, rendering and modification by operations.
    
  31.     """
    
  32. 
    
  33.     def test_create(self):
    
  34.         """
    
  35.         Tests making a ProjectState from an Apps
    
  36.         """
    
  37. 
    
  38.         new_apps = Apps(["migrations"])
    
  39. 
    
  40.         class Author(models.Model):
    
  41.             name = models.CharField(max_length=255)
    
  42.             bio = models.TextField()
    
  43.             age = models.IntegerField(blank=True, null=True)
    
  44. 
    
  45.             class Meta:
    
  46.                 app_label = "migrations"
    
  47.                 apps = new_apps
    
  48.                 unique_together = ["name", "bio"]
    
  49.                 index_together = ["bio", "age"]
    
  50. 
    
  51.         class AuthorProxy(Author):
    
  52.             class Meta:
    
  53.                 app_label = "migrations"
    
  54.                 apps = new_apps
    
  55.                 proxy = True
    
  56.                 ordering = ["name"]
    
  57. 
    
  58.         class SubAuthor(Author):
    
  59.             width = models.FloatField(null=True)
    
  60. 
    
  61.             class Meta:
    
  62.                 app_label = "migrations"
    
  63.                 apps = new_apps
    
  64. 
    
  65.         class Book(models.Model):
    
  66.             title = models.CharField(max_length=1000)
    
  67.             author = models.ForeignKey(Author, models.CASCADE)
    
  68.             contributors = models.ManyToManyField(Author)
    
  69. 
    
  70.             class Meta:
    
  71.                 app_label = "migrations"
    
  72.                 apps = new_apps
    
  73.                 verbose_name = "tome"
    
  74.                 db_table = "test_tome"
    
  75.                 indexes = [models.Index(fields=["title"])]
    
  76. 
    
  77.         class Food(models.Model):
    
  78.             food_mgr = FoodManager("a", "b")
    
  79.             food_qs = FoodQuerySet.as_manager()
    
  80.             food_no_mgr = NoMigrationFoodManager("x", "y")
    
  81. 
    
  82.             class Meta:
    
  83.                 app_label = "migrations"
    
  84.                 apps = new_apps
    
  85. 
    
  86.         class FoodNoManagers(models.Model):
    
  87.             class Meta:
    
  88.                 app_label = "migrations"
    
  89.                 apps = new_apps
    
  90. 
    
  91.         class FoodNoDefaultManager(models.Model):
    
  92.             food_no_mgr = NoMigrationFoodManager("x", "y")
    
  93.             food_mgr = FoodManager("a", "b")
    
  94.             food_qs = FoodQuerySet.as_manager()
    
  95. 
    
  96.             class Meta:
    
  97.                 app_label = "migrations"
    
  98.                 apps = new_apps
    
  99. 
    
  100.         mgr1 = FoodManager("a", "b")
    
  101.         mgr2 = FoodManager("x", "y", c=3, d=4)
    
  102. 
    
  103.         class FoodOrderedManagers(models.Model):
    
  104.             # The managers on this model should be ordered by their creation
    
  105.             # counter and not by the order in model body
    
  106. 
    
  107.             food_no_mgr = NoMigrationFoodManager("x", "y")
    
  108.             food_mgr2 = mgr2
    
  109.             food_mgr1 = mgr1
    
  110. 
    
  111.             class Meta:
    
  112.                 app_label = "migrations"
    
  113.                 apps = new_apps
    
  114. 
    
  115.         project_state = ProjectState.from_apps(new_apps)
    
  116.         author_state = project_state.models["migrations", "author"]
    
  117.         author_proxy_state = project_state.models["migrations", "authorproxy"]
    
  118.         sub_author_state = project_state.models["migrations", "subauthor"]
    
  119.         book_state = project_state.models["migrations", "book"]
    
  120.         food_state = project_state.models["migrations", "food"]
    
  121.         food_no_managers_state = project_state.models["migrations", "foodnomanagers"]
    
  122.         food_no_default_manager_state = project_state.models[
    
  123.             "migrations", "foodnodefaultmanager"
    
  124.         ]
    
  125.         food_order_manager_state = project_state.models[
    
  126.             "migrations", "foodorderedmanagers"
    
  127.         ]
    
  128.         book_index = models.Index(fields=["title"])
    
  129.         book_index.set_name_with_model(Book)
    
  130. 
    
  131.         self.assertEqual(author_state.app_label, "migrations")
    
  132.         self.assertEqual(author_state.name, "Author")
    
  133.         self.assertEqual(list(author_state.fields), ["id", "name", "bio", "age"])
    
  134.         self.assertEqual(author_state.fields["name"].max_length, 255)
    
  135.         self.assertIs(author_state.fields["bio"].null, False)
    
  136.         self.assertIs(author_state.fields["age"].null, True)
    
  137.         self.assertEqual(
    
  138.             author_state.options,
    
  139.             {
    
  140.                 "unique_together": {("name", "bio")},
    
  141.                 "index_together": {("bio", "age")},
    
  142.                 "indexes": [],
    
  143.                 "constraints": [],
    
  144.             },
    
  145.         )
    
  146.         self.assertEqual(author_state.bases, (models.Model,))
    
  147. 
    
  148.         self.assertEqual(book_state.app_label, "migrations")
    
  149.         self.assertEqual(book_state.name, "Book")
    
  150.         self.assertEqual(
    
  151.             list(book_state.fields), ["id", "title", "author", "contributors"]
    
  152.         )
    
  153.         self.assertEqual(book_state.fields["title"].max_length, 1000)
    
  154.         self.assertIs(book_state.fields["author"].null, False)
    
  155.         self.assertEqual(
    
  156.             book_state.fields["contributors"].__class__.__name__, "ManyToManyField"
    
  157.         )
    
  158.         self.assertEqual(
    
  159.             book_state.options,
    
  160.             {
    
  161.                 "verbose_name": "tome",
    
  162.                 "db_table": "test_tome",
    
  163.                 "indexes": [book_index],
    
  164.                 "constraints": [],
    
  165.             },
    
  166.         )
    
  167.         self.assertEqual(book_state.bases, (models.Model,))
    
  168. 
    
  169.         self.assertEqual(author_proxy_state.app_label, "migrations")
    
  170.         self.assertEqual(author_proxy_state.name, "AuthorProxy")
    
  171.         self.assertEqual(author_proxy_state.fields, {})
    
  172.         self.assertEqual(
    
  173.             author_proxy_state.options,
    
  174.             {"proxy": True, "ordering": ["name"], "indexes": [], "constraints": []},
    
  175.         )
    
  176.         self.assertEqual(author_proxy_state.bases, ("migrations.author",))
    
  177. 
    
  178.         self.assertEqual(sub_author_state.app_label, "migrations")
    
  179.         self.assertEqual(sub_author_state.name, "SubAuthor")
    
  180.         self.assertEqual(len(sub_author_state.fields), 2)
    
  181.         self.assertEqual(sub_author_state.bases, ("migrations.author",))
    
  182. 
    
  183.         # The default manager is used in migrations
    
  184.         self.assertEqual([name for name, mgr in food_state.managers], ["food_mgr"])
    
  185.         self.assertTrue(all(isinstance(name, str) for name, mgr in food_state.managers))
    
  186.         self.assertEqual(food_state.managers[0][1].args, ("a", "b", 1, 2))
    
  187. 
    
  188.         # No explicit managers defined. Migrations will fall back to the default
    
  189.         self.assertEqual(food_no_managers_state.managers, [])
    
  190. 
    
  191.         # food_mgr is used in migration but isn't the default mgr, hence add the
    
  192.         # default
    
  193.         self.assertEqual(
    
  194.             [name for name, mgr in food_no_default_manager_state.managers],
    
  195.             ["food_no_mgr", "food_mgr"],
    
  196.         )
    
  197.         self.assertTrue(
    
  198.             all(
    
  199.                 isinstance(name, str)
    
  200.                 for name, mgr in food_no_default_manager_state.managers
    
  201.             )
    
  202.         )
    
  203.         self.assertEqual(
    
  204.             food_no_default_manager_state.managers[0][1].__class__, models.Manager
    
  205.         )
    
  206.         self.assertIsInstance(food_no_default_manager_state.managers[1][1], FoodManager)
    
  207. 
    
  208.         self.assertEqual(
    
  209.             [name for name, mgr in food_order_manager_state.managers],
    
  210.             ["food_mgr1", "food_mgr2"],
    
  211.         )
    
  212.         self.assertTrue(
    
  213.             all(
    
  214.                 isinstance(name, str) for name, mgr in food_order_manager_state.managers
    
  215.             )
    
  216.         )
    
  217.         self.assertEqual(
    
  218.             [mgr.args for name, mgr in food_order_manager_state.managers],
    
  219.             [("a", "b", 1, 2), ("x", "y", 3, 4)],
    
  220.         )
    
  221. 
    
  222.     def test_custom_default_manager_added_to_the_model_state(self):
    
  223.         """
    
  224.         When the default manager of the model is a custom manager,
    
  225.         it needs to be added to the model state.
    
  226.         """
    
  227.         new_apps = Apps(["migrations"])
    
  228.         custom_manager = models.Manager()
    
  229. 
    
  230.         class Author(models.Model):
    
  231.             objects = models.TextField()
    
  232.             authors = custom_manager
    
  233. 
    
  234.             class Meta:
    
  235.                 app_label = "migrations"
    
  236.                 apps = new_apps
    
  237. 
    
  238.         project_state = ProjectState.from_apps(new_apps)
    
  239.         author_state = project_state.models["migrations", "author"]
    
  240.         self.assertEqual(author_state.managers, [("authors", custom_manager)])
    
  241. 
    
  242.     def test_custom_default_manager_named_objects_with_false_migration_flag(self):
    
  243.         """
    
  244.         When a manager is added with a name of 'objects' but it does not
    
  245.         have `use_in_migrations = True`, no migration should be added to the
    
  246.         model state (#26643).
    
  247.         """
    
  248.         new_apps = Apps(["migrations"])
    
  249. 
    
  250.         class Author(models.Model):
    
  251.             objects = models.Manager()
    
  252. 
    
  253.             class Meta:
    
  254.                 app_label = "migrations"
    
  255.                 apps = new_apps
    
  256. 
    
  257.         project_state = ProjectState.from_apps(new_apps)
    
  258.         author_state = project_state.models["migrations", "author"]
    
  259.         self.assertEqual(author_state.managers, [])
    
  260. 
    
  261.     def test_no_duplicate_managers(self):
    
  262.         """
    
  263.         When a manager is added with `use_in_migrations = True` and a parent
    
  264.         model had a manager with the same name and `use_in_migrations = True`,
    
  265.         the parent's manager shouldn't appear in the model state (#26881).
    
  266.         """
    
  267.         new_apps = Apps(["migrations"])
    
  268. 
    
  269.         class PersonManager(models.Manager):
    
  270.             use_in_migrations = True
    
  271. 
    
  272.         class Person(models.Model):
    
  273.             objects = PersonManager()
    
  274. 
    
  275.             class Meta:
    
  276.                 abstract = True
    
  277. 
    
  278.         class BossManager(PersonManager):
    
  279.             use_in_migrations = True
    
  280. 
    
  281.         class Boss(Person):
    
  282.             objects = BossManager()
    
  283. 
    
  284.             class Meta:
    
  285.                 app_label = "migrations"
    
  286.                 apps = new_apps
    
  287. 
    
  288.         project_state = ProjectState.from_apps(new_apps)
    
  289.         boss_state = project_state.models["migrations", "boss"]
    
  290.         self.assertEqual(boss_state.managers, [("objects", Boss.objects)])
    
  291. 
    
  292.     def test_custom_default_manager(self):
    
  293.         new_apps = Apps(["migrations"])
    
  294. 
    
  295.         class Author(models.Model):
    
  296.             manager1 = models.Manager()
    
  297.             manager2 = models.Manager()
    
  298. 
    
  299.             class Meta:
    
  300.                 app_label = "migrations"
    
  301.                 apps = new_apps
    
  302.                 default_manager_name = "manager2"
    
  303. 
    
  304.         project_state = ProjectState.from_apps(new_apps)
    
  305.         author_state = project_state.models["migrations", "author"]
    
  306.         self.assertEqual(author_state.options["default_manager_name"], "manager2")
    
  307.         self.assertEqual(author_state.managers, [("manager2", Author.manager1)])
    
  308. 
    
  309.     def test_custom_base_manager(self):
    
  310.         new_apps = Apps(["migrations"])
    
  311. 
    
  312.         class Author(models.Model):
    
  313.             manager1 = models.Manager()
    
  314.             manager2 = models.Manager()
    
  315. 
    
  316.             class Meta:
    
  317.                 app_label = "migrations"
    
  318.                 apps = new_apps
    
  319.                 base_manager_name = "manager2"
    
  320. 
    
  321.         class Author2(models.Model):
    
  322.             manager1 = models.Manager()
    
  323.             manager2 = models.Manager()
    
  324. 
    
  325.             class Meta:
    
  326.                 app_label = "migrations"
    
  327.                 apps = new_apps
    
  328.                 base_manager_name = "manager1"
    
  329. 
    
  330.         project_state = ProjectState.from_apps(new_apps)
    
  331. 
    
  332.         author_state = project_state.models["migrations", "author"]
    
  333.         self.assertEqual(author_state.options["base_manager_name"], "manager2")
    
  334.         self.assertEqual(
    
  335.             author_state.managers,
    
  336.             [
    
  337.                 ("manager1", Author.manager1),
    
  338.                 ("manager2", Author.manager2),
    
  339.             ],
    
  340.         )
    
  341. 
    
  342.         author2_state = project_state.models["migrations", "author2"]
    
  343.         self.assertEqual(author2_state.options["base_manager_name"], "manager1")
    
  344.         self.assertEqual(
    
  345.             author2_state.managers,
    
  346.             [
    
  347.                 ("manager1", Author2.manager1),
    
  348.             ],
    
  349.         )
    
  350. 
    
  351.     def test_apps_bulk_update(self):
    
  352.         """
    
  353.         StateApps.bulk_update() should update apps.ready to False and reset
    
  354.         the value afterward.
    
  355.         """
    
  356.         project_state = ProjectState()
    
  357.         apps = project_state.apps
    
  358.         with apps.bulk_update():
    
  359.             self.assertFalse(apps.ready)
    
  360.         self.assertTrue(apps.ready)
    
  361.         with self.assertRaises(ValueError):
    
  362.             with apps.bulk_update():
    
  363.                 self.assertFalse(apps.ready)
    
  364.                 raise ValueError()
    
  365.         self.assertTrue(apps.ready)
    
  366. 
    
  367.     def test_render(self):
    
  368.         """
    
  369.         Tests rendering a ProjectState into an Apps.
    
  370.         """
    
  371.         project_state = ProjectState()
    
  372.         project_state.add_model(
    
  373.             ModelState(
    
  374.                 app_label="migrations",
    
  375.                 name="Tag",
    
  376.                 fields=[
    
  377.                     ("id", models.AutoField(primary_key=True)),
    
  378.                     ("name", models.CharField(max_length=100)),
    
  379.                     ("hidden", models.BooleanField()),
    
  380.                 ],
    
  381.             )
    
  382.         )
    
  383.         project_state.add_model(
    
  384.             ModelState(
    
  385.                 app_label="migrations",
    
  386.                 name="SubTag",
    
  387.                 fields=[
    
  388.                     (
    
  389.                         "tag_ptr",
    
  390.                         models.OneToOneField(
    
  391.                             "migrations.Tag",
    
  392.                             models.CASCADE,
    
  393.                             auto_created=True,
    
  394.                             parent_link=True,
    
  395.                             primary_key=True,
    
  396.                             to_field="id",
    
  397.                             serialize=False,
    
  398.                         ),
    
  399.                     ),
    
  400.                     ("awesome", models.BooleanField()),
    
  401.                 ],
    
  402.                 bases=("migrations.Tag",),
    
  403.             )
    
  404.         )
    
  405. 
    
  406.         base_mgr = models.Manager()
    
  407.         mgr1 = FoodManager("a", "b")
    
  408.         mgr2 = FoodManager("x", "y", c=3, d=4)
    
  409.         project_state.add_model(
    
  410.             ModelState(
    
  411.                 app_label="migrations",
    
  412.                 name="Food",
    
  413.                 fields=[
    
  414.                     ("id", models.AutoField(primary_key=True)),
    
  415.                 ],
    
  416.                 managers=[
    
  417.                     # The ordering we really want is objects, mgr1, mgr2
    
  418.                     ("default", base_mgr),
    
  419.                     ("food_mgr2", mgr2),
    
  420.                     ("food_mgr1", mgr1),
    
  421.                 ],
    
  422.             )
    
  423.         )
    
  424. 
    
  425.         new_apps = project_state.apps
    
  426.         self.assertEqual(
    
  427.             new_apps.get_model("migrations", "Tag")._meta.get_field("name").max_length,
    
  428.             100,
    
  429.         )
    
  430.         self.assertIs(
    
  431.             new_apps.get_model("migrations", "Tag")._meta.get_field("hidden").null,
    
  432.             False,
    
  433.         )
    
  434. 
    
  435.         self.assertEqual(
    
  436.             len(new_apps.get_model("migrations", "SubTag")._meta.local_fields), 2
    
  437.         )
    
  438. 
    
  439.         Food = new_apps.get_model("migrations", "Food")
    
  440.         self.assertEqual(
    
  441.             [mgr.name for mgr in Food._meta.managers],
    
  442.             ["default", "food_mgr1", "food_mgr2"],
    
  443.         )
    
  444.         self.assertTrue(all(isinstance(mgr.name, str) for mgr in Food._meta.managers))
    
  445.         self.assertEqual(
    
  446.             [mgr.__class__ for mgr in Food._meta.managers],
    
  447.             [models.Manager, FoodManager, FoodManager],
    
  448.         )
    
  449. 
    
  450.     def test_render_model_inheritance(self):
    
  451.         class Book(models.Model):
    
  452.             title = models.CharField(max_length=1000)
    
  453. 
    
  454.             class Meta:
    
  455.                 app_label = "migrations"
    
  456.                 apps = Apps()
    
  457. 
    
  458.         class Novel(Book):
    
  459.             class Meta:
    
  460.                 app_label = "migrations"
    
  461.                 apps = Apps()
    
  462. 
    
  463.         # First, test rendering individually
    
  464.         apps = Apps(["migrations"])
    
  465. 
    
  466.         # We shouldn't be able to render yet
    
  467.         ms = ModelState.from_model(Novel)
    
  468.         with self.assertRaises(InvalidBasesError):
    
  469.             ms.render(apps)
    
  470. 
    
  471.         # Once the parent model is in the app registry, it should be fine
    
  472.         ModelState.from_model(Book).render(apps)
    
  473.         ModelState.from_model(Novel).render(apps)
    
  474. 
    
  475.     def test_render_model_with_multiple_inheritance(self):
    
  476.         class Foo(models.Model):
    
  477.             class Meta:
    
  478.                 app_label = "migrations"
    
  479.                 apps = Apps()
    
  480. 
    
  481.         class Bar(models.Model):
    
  482.             class Meta:
    
  483.                 app_label = "migrations"
    
  484.                 apps = Apps()
    
  485. 
    
  486.         class FooBar(Foo, Bar):
    
  487.             class Meta:
    
  488.                 app_label = "migrations"
    
  489.                 apps = Apps()
    
  490. 
    
  491.         class AbstractSubFooBar(FooBar):
    
  492.             class Meta:
    
  493.                 abstract = True
    
  494.                 apps = Apps()
    
  495. 
    
  496.         class SubFooBar(AbstractSubFooBar):
    
  497.             class Meta:
    
  498.                 app_label = "migrations"
    
  499.                 apps = Apps()
    
  500. 
    
  501.         apps = Apps(["migrations"])
    
  502. 
    
  503.         # We shouldn't be able to render yet
    
  504.         ms = ModelState.from_model(FooBar)
    
  505.         with self.assertRaises(InvalidBasesError):
    
  506.             ms.render(apps)
    
  507. 
    
  508.         # Once the parent models are in the app registry, it should be fine
    
  509.         ModelState.from_model(Foo).render(apps)
    
  510.         self.assertSequenceEqual(ModelState.from_model(Foo).bases, [models.Model])
    
  511.         ModelState.from_model(Bar).render(apps)
    
  512.         self.assertSequenceEqual(ModelState.from_model(Bar).bases, [models.Model])
    
  513.         ModelState.from_model(FooBar).render(apps)
    
  514.         self.assertSequenceEqual(
    
  515.             ModelState.from_model(FooBar).bases, ["migrations.foo", "migrations.bar"]
    
  516.         )
    
  517.         ModelState.from_model(SubFooBar).render(apps)
    
  518.         self.assertSequenceEqual(
    
  519.             ModelState.from_model(SubFooBar).bases, ["migrations.foobar"]
    
  520.         )
    
  521. 
    
  522.     def test_render_project_dependencies(self):
    
  523.         """
    
  524.         The ProjectState render method correctly renders models
    
  525.         to account for inter-model base dependencies.
    
  526.         """
    
  527.         new_apps = Apps()
    
  528. 
    
  529.         class A(models.Model):
    
  530.             class Meta:
    
  531.                 app_label = "migrations"
    
  532.                 apps = new_apps
    
  533. 
    
  534.         class B(A):
    
  535.             class Meta:
    
  536.                 app_label = "migrations"
    
  537.                 apps = new_apps
    
  538. 
    
  539.         class C(B):
    
  540.             class Meta:
    
  541.                 app_label = "migrations"
    
  542.                 apps = new_apps
    
  543. 
    
  544.         class D(A):
    
  545.             class Meta:
    
  546.                 app_label = "migrations"
    
  547.                 apps = new_apps
    
  548. 
    
  549.         class E(B):
    
  550.             class Meta:
    
  551.                 app_label = "migrations"
    
  552.                 apps = new_apps
    
  553.                 proxy = True
    
  554. 
    
  555.         class F(D):
    
  556.             class Meta:
    
  557.                 app_label = "migrations"
    
  558.                 apps = new_apps
    
  559.                 proxy = True
    
  560. 
    
  561.         # Make a ProjectState and render it
    
  562.         project_state = ProjectState()
    
  563.         project_state.add_model(ModelState.from_model(A))
    
  564.         project_state.add_model(ModelState.from_model(B))
    
  565.         project_state.add_model(ModelState.from_model(C))
    
  566.         project_state.add_model(ModelState.from_model(D))
    
  567.         project_state.add_model(ModelState.from_model(E))
    
  568.         project_state.add_model(ModelState.from_model(F))
    
  569.         final_apps = project_state.apps
    
  570.         self.assertEqual(len(final_apps.get_models()), 6)
    
  571. 
    
  572.         # Now make an invalid ProjectState and make sure it fails
    
  573.         project_state = ProjectState()
    
  574.         project_state.add_model(ModelState.from_model(A))
    
  575.         project_state.add_model(ModelState.from_model(B))
    
  576.         project_state.add_model(ModelState.from_model(C))
    
  577.         project_state.add_model(ModelState.from_model(F))
    
  578.         with self.assertRaises(InvalidBasesError):
    
  579.             project_state.apps
    
  580. 
    
  581.     def test_render_unique_app_labels(self):
    
  582.         """
    
  583.         The ProjectState render method doesn't raise an
    
  584.         ImproperlyConfigured exception about unique labels if two dotted app
    
  585.         names have the same last part.
    
  586.         """
    
  587. 
    
  588.         class A(models.Model):
    
  589.             class Meta:
    
  590.                 app_label = "django.contrib.auth"
    
  591. 
    
  592.         class B(models.Model):
    
  593.             class Meta:
    
  594.                 app_label = "vendor.auth"
    
  595. 
    
  596.         # Make a ProjectState and render it
    
  597.         project_state = ProjectState()
    
  598.         project_state.add_model(ModelState.from_model(A))
    
  599.         project_state.add_model(ModelState.from_model(B))
    
  600.         self.assertEqual(len(project_state.apps.get_models()), 2)
    
  601. 
    
  602.     def test_reload_related_model_on_non_relational_fields(self):
    
  603.         """
    
  604.         The model is reloaded even on changes that are not involved in
    
  605.         relations. Other models pointing to or from it are also reloaded.
    
  606.         """
    
  607.         project_state = ProjectState()
    
  608.         project_state.apps  # Render project state.
    
  609.         project_state.add_model(ModelState("migrations", "A", []))
    
  610.         project_state.add_model(
    
  611.             ModelState(
    
  612.                 "migrations",
    
  613.                 "B",
    
  614.                 [
    
  615.                     ("a", models.ForeignKey("A", models.CASCADE)),
    
  616.                 ],
    
  617.             )
    
  618.         )
    
  619.         project_state.add_model(
    
  620.             ModelState(
    
  621.                 "migrations",
    
  622.                 "C",
    
  623.                 [
    
  624.                     ("b", models.ForeignKey("B", models.CASCADE)),
    
  625.                     ("name", models.TextField()),
    
  626.                 ],
    
  627.             )
    
  628.         )
    
  629.         project_state.add_model(
    
  630.             ModelState(
    
  631.                 "migrations",
    
  632.                 "D",
    
  633.                 [
    
  634.                     ("a", models.ForeignKey("A", models.CASCADE)),
    
  635.                 ],
    
  636.             )
    
  637.         )
    
  638.         operation = AlterField(
    
  639.             model_name="C",
    
  640.             name="name",
    
  641.             field=models.TextField(blank=True),
    
  642.         )
    
  643.         operation.state_forwards("migrations", project_state)
    
  644.         project_state.reload_model("migrations", "a", delay=True)
    
  645.         A = project_state.apps.get_model("migrations.A")
    
  646.         B = project_state.apps.get_model("migrations.B")
    
  647.         D = project_state.apps.get_model("migrations.D")
    
  648.         self.assertIs(B._meta.get_field("a").related_model, A)
    
  649.         self.assertIs(D._meta.get_field("a").related_model, A)
    
  650. 
    
  651.     def test_reload_model_relationship_consistency(self):
    
  652.         project_state = ProjectState()
    
  653.         project_state.add_model(ModelState("migrations", "A", []))
    
  654.         project_state.add_model(
    
  655.             ModelState(
    
  656.                 "migrations",
    
  657.                 "B",
    
  658.                 [
    
  659.                     ("a", models.ForeignKey("A", models.CASCADE)),
    
  660.                 ],
    
  661.             )
    
  662.         )
    
  663.         project_state.add_model(
    
  664.             ModelState(
    
  665.                 "migrations",
    
  666.                 "C",
    
  667.                 [
    
  668.                     ("b", models.ForeignKey("B", models.CASCADE)),
    
  669.                 ],
    
  670.             )
    
  671.         )
    
  672.         A = project_state.apps.get_model("migrations.A")
    
  673.         B = project_state.apps.get_model("migrations.B")
    
  674.         C = project_state.apps.get_model("migrations.C")
    
  675.         self.assertEqual([r.related_model for r in A._meta.related_objects], [B])
    
  676.         self.assertEqual([r.related_model for r in B._meta.related_objects], [C])
    
  677.         self.assertEqual([r.related_model for r in C._meta.related_objects], [])
    
  678. 
    
  679.         project_state.reload_model("migrations", "a", delay=True)
    
  680.         A = project_state.apps.get_model("migrations.A")
    
  681.         B = project_state.apps.get_model("migrations.B")
    
  682.         C = project_state.apps.get_model("migrations.C")
    
  683.         self.assertEqual([r.related_model for r in A._meta.related_objects], [B])
    
  684.         self.assertEqual([r.related_model for r in B._meta.related_objects], [C])
    
  685.         self.assertEqual([r.related_model for r in C._meta.related_objects], [])
    
  686. 
    
  687.     def test_add_relations(self):
    
  688.         """
    
  689.         #24573 - Adding relations to existing models should reload the
    
  690.         referenced models too.
    
  691.         """
    
  692.         new_apps = Apps()
    
  693. 
    
  694.         class A(models.Model):
    
  695.             class Meta:
    
  696.                 app_label = "something"
    
  697.                 apps = new_apps
    
  698. 
    
  699.         class B(A):
    
  700.             class Meta:
    
  701.                 app_label = "something"
    
  702.                 apps = new_apps
    
  703. 
    
  704.         class C(models.Model):
    
  705.             class Meta:
    
  706.                 app_label = "something"
    
  707.                 apps = new_apps
    
  708. 
    
  709.         project_state = ProjectState()
    
  710.         project_state.add_model(ModelState.from_model(A))
    
  711.         project_state.add_model(ModelState.from_model(B))
    
  712.         project_state.add_model(ModelState.from_model(C))
    
  713. 
    
  714.         project_state.apps  # We need to work with rendered models
    
  715. 
    
  716.         old_state = project_state.clone()
    
  717.         model_a_old = old_state.apps.get_model("something", "A")
    
  718.         model_b_old = old_state.apps.get_model("something", "B")
    
  719.         model_c_old = old_state.apps.get_model("something", "C")
    
  720.         # The relations between the old models are correct
    
  721.         self.assertIs(model_a_old._meta.get_field("b").related_model, model_b_old)
    
  722.         self.assertIs(model_b_old._meta.get_field("a_ptr").related_model, model_a_old)
    
  723. 
    
  724.         operation = AddField(
    
  725.             "c",
    
  726.             "to_a",
    
  727.             models.OneToOneField(
    
  728.                 "something.A",
    
  729.                 models.CASCADE,
    
  730.                 related_name="from_c",
    
  731.             ),
    
  732.         )
    
  733.         operation.state_forwards("something", project_state)
    
  734.         model_a_new = project_state.apps.get_model("something", "A")
    
  735.         model_b_new = project_state.apps.get_model("something", "B")
    
  736.         model_c_new = project_state.apps.get_model("something", "C")
    
  737. 
    
  738.         # All models have changed
    
  739.         self.assertIsNot(model_a_old, model_a_new)
    
  740.         self.assertIsNot(model_b_old, model_b_new)
    
  741.         self.assertIsNot(model_c_old, model_c_new)
    
  742.         # The relations between the old models still hold
    
  743.         self.assertIs(model_a_old._meta.get_field("b").related_model, model_b_old)
    
  744.         self.assertIs(model_b_old._meta.get_field("a_ptr").related_model, model_a_old)
    
  745.         # The relations between the new models correct
    
  746.         self.assertIs(model_a_new._meta.get_field("b").related_model, model_b_new)
    
  747.         self.assertIs(model_b_new._meta.get_field("a_ptr").related_model, model_a_new)
    
  748.         self.assertIs(model_a_new._meta.get_field("from_c").related_model, model_c_new)
    
  749.         self.assertIs(model_c_new._meta.get_field("to_a").related_model, model_a_new)
    
  750. 
    
  751.     def test_remove_relations(self):
    
  752.         """
    
  753.         #24225 - Relations between models are updated while
    
  754.         remaining the relations and references for models of an old state.
    
  755.         """
    
  756.         new_apps = Apps()
    
  757. 
    
  758.         class A(models.Model):
    
  759.             class Meta:
    
  760.                 app_label = "something"
    
  761.                 apps = new_apps
    
  762. 
    
  763.         class B(models.Model):
    
  764.             to_a = models.ForeignKey(A, models.CASCADE)
    
  765. 
    
  766.             class Meta:
    
  767.                 app_label = "something"
    
  768.                 apps = new_apps
    
  769. 
    
  770.         def get_model_a(state):
    
  771.             return [
    
  772.                 mod for mod in state.apps.get_models() if mod._meta.model_name == "a"
    
  773.             ][0]
    
  774. 
    
  775.         project_state = ProjectState()
    
  776.         project_state.add_model(ModelState.from_model(A))
    
  777.         project_state.add_model(ModelState.from_model(B))
    
  778.         self.assertEqual(len(get_model_a(project_state)._meta.related_objects), 1)
    
  779.         old_state = project_state.clone()
    
  780. 
    
  781.         operation = RemoveField("b", "to_a")
    
  782.         operation.state_forwards("something", project_state)
    
  783.         # Model from old_state still has the relation
    
  784.         model_a_old = get_model_a(old_state)
    
  785.         model_a_new = get_model_a(project_state)
    
  786.         self.assertIsNot(model_a_old, model_a_new)
    
  787.         self.assertEqual(len(model_a_old._meta.related_objects), 1)
    
  788.         self.assertEqual(len(model_a_new._meta.related_objects), 0)
    
  789. 
    
  790.         # Same test for deleted model
    
  791.         project_state = ProjectState()
    
  792.         project_state.add_model(ModelState.from_model(A))
    
  793.         project_state.add_model(ModelState.from_model(B))
    
  794.         old_state = project_state.clone()
    
  795. 
    
  796.         operation = DeleteModel("b")
    
  797.         operation.state_forwards("something", project_state)
    
  798.         model_a_old = get_model_a(old_state)
    
  799.         model_a_new = get_model_a(project_state)
    
  800.         self.assertIsNot(model_a_old, model_a_new)
    
  801.         self.assertEqual(len(model_a_old._meta.related_objects), 1)
    
  802.         self.assertEqual(len(model_a_new._meta.related_objects), 0)
    
  803. 
    
  804.     def test_self_relation(self):
    
  805.         """
    
  806.         #24513 - Modifying an object pointing to itself would cause it to be
    
  807.         rendered twice and thus breaking its related M2M through objects.
    
  808.         """
    
  809. 
    
  810.         class A(models.Model):
    
  811.             to_a = models.ManyToManyField("something.A", symmetrical=False)
    
  812. 
    
  813.             class Meta:
    
  814.                 app_label = "something"
    
  815. 
    
  816.         def get_model_a(state):
    
  817.             return [
    
  818.                 mod for mod in state.apps.get_models() if mod._meta.model_name == "a"
    
  819.             ][0]
    
  820. 
    
  821.         project_state = ProjectState()
    
  822.         project_state.add_model(ModelState.from_model(A))
    
  823.         self.assertEqual(len(get_model_a(project_state)._meta.related_objects), 1)
    
  824.         old_state = project_state.clone()
    
  825. 
    
  826.         operation = AlterField(
    
  827.             model_name="a",
    
  828.             name="to_a",
    
  829.             field=models.ManyToManyField("something.A", symmetrical=False, blank=True),
    
  830.         )
    
  831.         # At this point the model would be rendered twice causing its related
    
  832.         # M2M through objects to point to an old copy and thus breaking their
    
  833.         # attribute lookup.
    
  834.         operation.state_forwards("something", project_state)
    
  835. 
    
  836.         model_a_old = get_model_a(old_state)
    
  837.         model_a_new = get_model_a(project_state)
    
  838.         self.assertIsNot(model_a_old, model_a_new)
    
  839. 
    
  840.         # The old model's _meta is still consistent
    
  841.         field_to_a_old = model_a_old._meta.get_field("to_a")
    
  842.         self.assertEqual(field_to_a_old.m2m_field_name(), "from_a")
    
  843.         self.assertEqual(field_to_a_old.m2m_reverse_field_name(), "to_a")
    
  844.         self.assertIs(field_to_a_old.related_model, model_a_old)
    
  845.         self.assertIs(
    
  846.             field_to_a_old.remote_field.through._meta.get_field("to_a").related_model,
    
  847.             model_a_old,
    
  848.         )
    
  849.         self.assertIs(
    
  850.             field_to_a_old.remote_field.through._meta.get_field("from_a").related_model,
    
  851.             model_a_old,
    
  852.         )
    
  853. 
    
  854.         # The new model's _meta is still consistent
    
  855.         field_to_a_new = model_a_new._meta.get_field("to_a")
    
  856.         self.assertEqual(field_to_a_new.m2m_field_name(), "from_a")
    
  857.         self.assertEqual(field_to_a_new.m2m_reverse_field_name(), "to_a")
    
  858.         self.assertIs(field_to_a_new.related_model, model_a_new)
    
  859.         self.assertIs(
    
  860.             field_to_a_new.remote_field.through._meta.get_field("to_a").related_model,
    
  861.             model_a_new,
    
  862.         )
    
  863.         self.assertIs(
    
  864.             field_to_a_new.remote_field.through._meta.get_field("from_a").related_model,
    
  865.             model_a_new,
    
  866.         )
    
  867. 
    
  868.     def test_equality(self):
    
  869.         """
    
  870.         == and != are implemented correctly.
    
  871.         """
    
  872.         # Test two things that should be equal
    
  873.         project_state = ProjectState()
    
  874.         project_state.add_model(
    
  875.             ModelState(
    
  876.                 "migrations",
    
  877.                 "Tag",
    
  878.                 [
    
  879.                     ("id", models.AutoField(primary_key=True)),
    
  880.                     ("name", models.CharField(max_length=100)),
    
  881.                     ("hidden", models.BooleanField()),
    
  882.                 ],
    
  883.                 {},
    
  884.                 None,
    
  885.             )
    
  886.         )
    
  887.         project_state.apps  # Fill the apps cached property
    
  888.         other_state = project_state.clone()
    
  889.         self.assertEqual(project_state, project_state)
    
  890.         self.assertEqual(project_state, other_state)
    
  891.         self.assertIs(project_state != project_state, False)
    
  892.         self.assertIs(project_state != other_state, False)
    
  893.         self.assertNotEqual(project_state.apps, other_state.apps)
    
  894. 
    
  895.         # Make a very small change (max_len 99) and see if that affects it
    
  896.         project_state = ProjectState()
    
  897.         project_state.add_model(
    
  898.             ModelState(
    
  899.                 "migrations",
    
  900.                 "Tag",
    
  901.                 [
    
  902.                     ("id", models.AutoField(primary_key=True)),
    
  903.                     ("name", models.CharField(max_length=99)),
    
  904.                     ("hidden", models.BooleanField()),
    
  905.                 ],
    
  906.                 {},
    
  907.                 None,
    
  908.             )
    
  909.         )
    
  910.         self.assertNotEqual(project_state, other_state)
    
  911.         self.assertIs(project_state == other_state, False)
    
  912. 
    
  913.     def test_dangling_references_throw_error(self):
    
  914.         new_apps = Apps()
    
  915. 
    
  916.         class Author(models.Model):
    
  917.             name = models.TextField()
    
  918. 
    
  919.             class Meta:
    
  920.                 app_label = "migrations"
    
  921.                 apps = new_apps
    
  922. 
    
  923.         class Publisher(models.Model):
    
  924.             name = models.TextField()
    
  925. 
    
  926.             class Meta:
    
  927.                 app_label = "migrations"
    
  928.                 apps = new_apps
    
  929. 
    
  930.         class Book(models.Model):
    
  931.             author = models.ForeignKey(Author, models.CASCADE)
    
  932.             publisher = models.ForeignKey(Publisher, models.CASCADE)
    
  933. 
    
  934.             class Meta:
    
  935.                 app_label = "migrations"
    
  936.                 apps = new_apps
    
  937. 
    
  938.         class Magazine(models.Model):
    
  939.             authors = models.ManyToManyField(Author)
    
  940. 
    
  941.             class Meta:
    
  942.                 app_label = "migrations"
    
  943.                 apps = new_apps
    
  944. 
    
  945.         # Make a valid ProjectState and render it
    
  946.         project_state = ProjectState()
    
  947.         project_state.add_model(ModelState.from_model(Author))
    
  948.         project_state.add_model(ModelState.from_model(Publisher))
    
  949.         project_state.add_model(ModelState.from_model(Book))
    
  950.         project_state.add_model(ModelState.from_model(Magazine))
    
  951.         self.assertEqual(len(project_state.apps.get_models()), 4)
    
  952. 
    
  953.         # now make an invalid one with a ForeignKey
    
  954.         project_state = ProjectState()
    
  955.         project_state.add_model(ModelState.from_model(Book))
    
  956.         msg = (
    
  957.             "The field migrations.Book.author was declared with a lazy reference "
    
  958.             "to 'migrations.author', but app 'migrations' doesn't provide model "
    
  959.             "'author'.\n"
    
  960.             "The field migrations.Book.publisher was declared with a lazy reference "
    
  961.             "to 'migrations.publisher', but app 'migrations' doesn't provide model "
    
  962.             "'publisher'."
    
  963.         )
    
  964.         with self.assertRaisesMessage(ValueError, msg):
    
  965.             project_state.apps
    
  966. 
    
  967.         # And another with ManyToManyField.
    
  968.         project_state = ProjectState()
    
  969.         project_state.add_model(ModelState.from_model(Magazine))
    
  970.         msg = (
    
  971.             "The field migrations.Magazine.authors was declared with a lazy reference "
    
  972.             "to 'migrations.author', but app 'migrations' doesn't provide model "
    
  973.             "'author'.\n"
    
  974.             "The field migrations.Magazine_authors.author was declared with a lazy "
    
  975.             "reference to 'migrations.author', but app 'migrations' doesn't provide "
    
  976.             "model 'author'."
    
  977.         )
    
  978.         with self.assertRaisesMessage(ValueError, msg):
    
  979.             project_state.apps
    
  980. 
    
  981.         # And now with multiple models and multiple fields.
    
  982.         project_state.add_model(ModelState.from_model(Book))
    
  983.         msg = (
    
  984.             "The field migrations.Book.author was declared with a lazy reference "
    
  985.             "to 'migrations.author', but app 'migrations' doesn't provide model "
    
  986.             "'author'.\n"
    
  987.             "The field migrations.Book.publisher was declared with a lazy reference "
    
  988.             "to 'migrations.publisher', but app 'migrations' doesn't provide model "
    
  989.             "'publisher'.\n"
    
  990.             "The field migrations.Magazine.authors was declared with a lazy reference "
    
  991.             "to 'migrations.author', but app 'migrations' doesn't provide model "
    
  992.             "'author'.\n"
    
  993.             "The field migrations.Magazine_authors.author was declared with a lazy "
    
  994.             "reference to 'migrations.author', but app 'migrations' doesn't provide "
    
  995.             "model 'author'."
    
  996.         )
    
  997.         with self.assertRaisesMessage(ValueError, msg):
    
  998.             project_state.apps
    
  999. 
    
  1000.     def test_reference_mixed_case_app_label(self):
    
  1001.         new_apps = Apps()
    
  1002. 
    
  1003.         class Author(models.Model):
    
  1004.             class Meta:
    
  1005.                 app_label = "MiXedCase_migrations"
    
  1006.                 apps = new_apps
    
  1007. 
    
  1008.         class Book(models.Model):
    
  1009.             author = models.ForeignKey(Author, models.CASCADE)
    
  1010. 
    
  1011.             class Meta:
    
  1012.                 app_label = "MiXedCase_migrations"
    
  1013.                 apps = new_apps
    
  1014. 
    
  1015.         class Magazine(models.Model):
    
  1016.             authors = models.ManyToManyField(Author)
    
  1017. 
    
  1018.             class Meta:
    
  1019.                 app_label = "MiXedCase_migrations"
    
  1020.                 apps = new_apps
    
  1021. 
    
  1022.         project_state = ProjectState()
    
  1023.         project_state.add_model(ModelState.from_model(Author))
    
  1024.         project_state.add_model(ModelState.from_model(Book))
    
  1025.         project_state.add_model(ModelState.from_model(Magazine))
    
  1026.         self.assertEqual(len(project_state.apps.get_models()), 3)
    
  1027. 
    
  1028.     def test_real_apps(self):
    
  1029.         """
    
  1030.         Including real apps can resolve dangling FK errors.
    
  1031.         This test relies on the fact that contenttypes is always loaded.
    
  1032.         """
    
  1033.         new_apps = Apps()
    
  1034. 
    
  1035.         class TestModel(models.Model):
    
  1036.             ct = models.ForeignKey("contenttypes.ContentType", models.CASCADE)
    
  1037. 
    
  1038.             class Meta:
    
  1039.                 app_label = "migrations"
    
  1040.                 apps = new_apps
    
  1041. 
    
  1042.         # If we just stick it into an empty state it should fail
    
  1043.         project_state = ProjectState()
    
  1044.         project_state.add_model(ModelState.from_model(TestModel))
    
  1045.         with self.assertRaises(ValueError):
    
  1046.             project_state.apps
    
  1047. 
    
  1048.         # If we include the real app it should succeed
    
  1049.         project_state = ProjectState(real_apps={"contenttypes"})
    
  1050.         project_state.add_model(ModelState.from_model(TestModel))
    
  1051.         rendered_state = project_state.apps
    
  1052.         self.assertEqual(
    
  1053.             len(
    
  1054.                 [
    
  1055.                     x
    
  1056.                     for x in rendered_state.get_models()
    
  1057.                     if x._meta.app_label == "migrations"
    
  1058.                 ]
    
  1059.             ),
    
  1060.             1,
    
  1061.         )
    
  1062. 
    
  1063.     def test_real_apps_non_set(self):
    
  1064.         with self.assertRaises(AssertionError):
    
  1065.             ProjectState(real_apps=["contenttypes"])
    
  1066. 
    
  1067.     def test_ignore_order_wrt(self):
    
  1068.         """
    
  1069.         Makes sure ProjectState doesn't include OrderWrt fields when
    
  1070.         making from existing models.
    
  1071.         """
    
  1072.         new_apps = Apps()
    
  1073. 
    
  1074.         class Author(models.Model):
    
  1075.             name = models.TextField()
    
  1076. 
    
  1077.             class Meta:
    
  1078.                 app_label = "migrations"
    
  1079.                 apps = new_apps
    
  1080. 
    
  1081.         class Book(models.Model):
    
  1082.             author = models.ForeignKey(Author, models.CASCADE)
    
  1083. 
    
  1084.             class Meta:
    
  1085.                 app_label = "migrations"
    
  1086.                 apps = new_apps
    
  1087.                 order_with_respect_to = "author"
    
  1088. 
    
  1089.         # Make a valid ProjectState and render it
    
  1090.         project_state = ProjectState()
    
  1091.         project_state.add_model(ModelState.from_model(Author))
    
  1092.         project_state.add_model(ModelState.from_model(Book))
    
  1093.         self.assertEqual(
    
  1094.             list(project_state.models["migrations", "book"].fields),
    
  1095.             ["id", "author"],
    
  1096.         )
    
  1097. 
    
  1098.     def test_modelstate_get_field_order_wrt(self):
    
  1099.         new_apps = Apps()
    
  1100. 
    
  1101.         class Author(models.Model):
    
  1102.             name = models.TextField()
    
  1103. 
    
  1104.             class Meta:
    
  1105.                 app_label = "migrations"
    
  1106.                 apps = new_apps
    
  1107. 
    
  1108.         class Book(models.Model):
    
  1109.             author = models.ForeignKey(Author, models.CASCADE)
    
  1110. 
    
  1111.             class Meta:
    
  1112.                 app_label = "migrations"
    
  1113.                 apps = new_apps
    
  1114.                 order_with_respect_to = "author"
    
  1115. 
    
  1116.         model_state = ModelState.from_model(Book)
    
  1117.         order_wrt_field = model_state.get_field("_order")
    
  1118.         self.assertIsInstance(order_wrt_field, models.ForeignKey)
    
  1119.         self.assertEqual(order_wrt_field.related_model, "migrations.author")
    
  1120. 
    
  1121.     def test_modelstate_get_field_no_order_wrt_order_field(self):
    
  1122.         new_apps = Apps()
    
  1123. 
    
  1124.         class HistoricalRecord(models.Model):
    
  1125.             _order = models.PositiveSmallIntegerField()
    
  1126. 
    
  1127.             class Meta:
    
  1128.                 app_label = "migrations"
    
  1129.                 apps = new_apps
    
  1130. 
    
  1131.         model_state = ModelState.from_model(HistoricalRecord)
    
  1132.         order_field = model_state.get_field("_order")
    
  1133.         self.assertIsNone(order_field.related_model)
    
  1134.         self.assertIsInstance(order_field, models.PositiveSmallIntegerField)
    
  1135. 
    
  1136.     def test_manager_refer_correct_model_version(self):
    
  1137.         """
    
  1138.         #24147 - Managers refer to the correct version of a
    
  1139.         historical model
    
  1140.         """
    
  1141.         project_state = ProjectState()
    
  1142.         project_state.add_model(
    
  1143.             ModelState(
    
  1144.                 app_label="migrations",
    
  1145.                 name="Tag",
    
  1146.                 fields=[
    
  1147.                     ("id", models.AutoField(primary_key=True)),
    
  1148.                     ("hidden", models.BooleanField()),
    
  1149.                 ],
    
  1150.                 managers=[
    
  1151.                     ("food_mgr", FoodManager("a", "b")),
    
  1152.                     ("food_qs", FoodQuerySet.as_manager()),
    
  1153.                 ],
    
  1154.             )
    
  1155.         )
    
  1156. 
    
  1157.         old_model = project_state.apps.get_model("migrations", "tag")
    
  1158. 
    
  1159.         new_state = project_state.clone()
    
  1160.         operation = RemoveField("tag", "hidden")
    
  1161.         operation.state_forwards("migrations", new_state)
    
  1162. 
    
  1163.         new_model = new_state.apps.get_model("migrations", "tag")
    
  1164. 
    
  1165.         self.assertIsNot(old_model, new_model)
    
  1166.         self.assertIs(old_model, old_model.food_mgr.model)
    
  1167.         self.assertIs(old_model, old_model.food_qs.model)
    
  1168.         self.assertIs(new_model, new_model.food_mgr.model)
    
  1169.         self.assertIs(new_model, new_model.food_qs.model)
    
  1170.         self.assertIsNot(old_model.food_mgr, new_model.food_mgr)
    
  1171.         self.assertIsNot(old_model.food_qs, new_model.food_qs)
    
  1172.         self.assertIsNot(old_model.food_mgr.model, new_model.food_mgr.model)
    
  1173.         self.assertIsNot(old_model.food_qs.model, new_model.food_qs.model)
    
  1174. 
    
  1175.     def test_choices_iterator(self):
    
  1176.         """
    
  1177.         #24483 - ProjectState.from_apps should not destructively consume
    
  1178.         Field.choices iterators.
    
  1179.         """
    
  1180.         new_apps = Apps(["migrations"])
    
  1181.         choices = [("a", "A"), ("b", "B")]
    
  1182. 
    
  1183.         class Author(models.Model):
    
  1184.             name = models.CharField(max_length=255)
    
  1185.             choice = models.CharField(max_length=255, choices=iter(choices))
    
  1186. 
    
  1187.             class Meta:
    
  1188.                 app_label = "migrations"
    
  1189.                 apps = new_apps
    
  1190. 
    
  1191.         ProjectState.from_apps(new_apps)
    
  1192.         choices_field = Author._meta.get_field("choice")
    
  1193.         self.assertEqual(list(choices_field.choices), choices)
    
  1194. 
    
  1195. 
    
  1196. class StateRelationsTests(SimpleTestCase):
    
  1197.     def get_base_project_state(self):
    
  1198.         new_apps = Apps()
    
  1199. 
    
  1200.         class User(models.Model):
    
  1201.             class Meta:
    
  1202.                 app_label = "tests"
    
  1203.                 apps = new_apps
    
  1204. 
    
  1205.         class Comment(models.Model):
    
  1206.             text = models.TextField()
    
  1207.             user = models.ForeignKey(User, models.CASCADE)
    
  1208.             comments = models.ManyToManyField("self")
    
  1209. 
    
  1210.             class Meta:
    
  1211.                 app_label = "tests"
    
  1212.                 apps = new_apps
    
  1213. 
    
  1214.         class Post(models.Model):
    
  1215.             text = models.TextField()
    
  1216.             authors = models.ManyToManyField(User)
    
  1217. 
    
  1218.             class Meta:
    
  1219.                 app_label = "tests"
    
  1220.                 apps = new_apps
    
  1221. 
    
  1222.         project_state = ProjectState()
    
  1223.         project_state.add_model(ModelState.from_model(User))
    
  1224.         project_state.add_model(ModelState.from_model(Comment))
    
  1225.         project_state.add_model(ModelState.from_model(Post))
    
  1226.         return project_state
    
  1227. 
    
  1228.     def test_relations_population(self):
    
  1229.         tests = [
    
  1230.             (
    
  1231.                 "add_model",
    
  1232.                 [
    
  1233.                     ModelState(
    
  1234.                         app_label="migrations",
    
  1235.                         name="Tag",
    
  1236.                         fields=[("id", models.AutoField(primary_key=True))],
    
  1237.                     ),
    
  1238.                 ],
    
  1239.             ),
    
  1240.             ("remove_model", ["tests", "comment"]),
    
  1241.             ("rename_model", ["tests", "comment", "opinion"]),
    
  1242.             (
    
  1243.                 "add_field",
    
  1244.                 [
    
  1245.                     "tests",
    
  1246.                     "post",
    
  1247.                     "next_post",
    
  1248.                     models.ForeignKey("self", models.CASCADE),
    
  1249.                     True,
    
  1250.                 ],
    
  1251.             ),
    
  1252.             ("remove_field", ["tests", "post", "text"]),
    
  1253.             ("rename_field", ["tests", "comment", "user", "author"]),
    
  1254.             (
    
  1255.                 "alter_field",
    
  1256.                 [
    
  1257.                     "tests",
    
  1258.                     "comment",
    
  1259.                     "user",
    
  1260.                     models.IntegerField(),
    
  1261.                     True,
    
  1262.                 ],
    
  1263.             ),
    
  1264.         ]
    
  1265.         for method, args in tests:
    
  1266.             with self.subTest(method=method):
    
  1267.                 project_state = self.get_base_project_state()
    
  1268.                 getattr(project_state, method)(*args)
    
  1269.                 # ProjectState's `_relations` are populated on `relations` access.
    
  1270.                 self.assertIsNone(project_state._relations)
    
  1271.                 self.assertEqual(project_state.relations, project_state._relations)
    
  1272.                 self.assertIsNotNone(project_state._relations)
    
  1273. 
    
  1274.     def test_add_model(self):
    
  1275.         project_state = self.get_base_project_state()
    
  1276.         self.assertEqual(
    
  1277.             list(project_state.relations["tests", "user"]),
    
  1278.             [("tests", "comment"), ("tests", "post")],
    
  1279.         )
    
  1280.         self.assertEqual(
    
  1281.             list(project_state.relations["tests", "comment"]),
    
  1282.             [("tests", "comment")],
    
  1283.         )
    
  1284.         self.assertNotIn(("tests", "post"), project_state.relations)
    
  1285. 
    
  1286.     def test_add_model_no_relations(self):
    
  1287.         project_state = ProjectState()
    
  1288.         project_state.add_model(
    
  1289.             ModelState(
    
  1290.                 app_label="migrations",
    
  1291.                 name="Tag",
    
  1292.                 fields=[("id", models.AutoField(primary_key=True))],
    
  1293.             )
    
  1294.         )
    
  1295.         self.assertEqual(project_state.relations, {})
    
  1296. 
    
  1297.     def test_add_model_other_app(self):
    
  1298.         project_state = self.get_base_project_state()
    
  1299.         self.assertEqual(
    
  1300.             list(project_state.relations["tests", "user"]),
    
  1301.             [("tests", "comment"), ("tests", "post")],
    
  1302.         )
    
  1303.         project_state.add_model(
    
  1304.             ModelState(
    
  1305.                 app_label="tests_other",
    
  1306.                 name="comment",
    
  1307.                 fields=[
    
  1308.                     ("id", models.AutoField(primary_key=True)),
    
  1309.                     ("user", models.ForeignKey("tests.user", models.CASCADE)),
    
  1310.                 ],
    
  1311.             )
    
  1312.         )
    
  1313.         self.assertEqual(
    
  1314.             list(project_state.relations["tests", "user"]),
    
  1315.             [("tests", "comment"), ("tests", "post"), ("tests_other", "comment")],
    
  1316.         )
    
  1317. 
    
  1318.     def test_remove_model(self):
    
  1319.         project_state = self.get_base_project_state()
    
  1320.         self.assertEqual(
    
  1321.             list(project_state.relations["tests", "user"]),
    
  1322.             [("tests", "comment"), ("tests", "post")],
    
  1323.         )
    
  1324.         self.assertEqual(
    
  1325.             list(project_state.relations["tests", "comment"]),
    
  1326.             [("tests", "comment")],
    
  1327.         )
    
  1328. 
    
  1329.         project_state.remove_model("tests", "comment")
    
  1330.         self.assertEqual(
    
  1331.             list(project_state.relations["tests", "user"]),
    
  1332.             [("tests", "post")],
    
  1333.         )
    
  1334.         self.assertNotIn(("tests", "comment"), project_state.relations)
    
  1335.         project_state.remove_model("tests", "post")
    
  1336.         self.assertEqual(project_state.relations, {})
    
  1337.         project_state.remove_model("tests", "user")
    
  1338.         self.assertEqual(project_state.relations, {})
    
  1339. 
    
  1340.     def test_rename_model(self):
    
  1341.         project_state = self.get_base_project_state()
    
  1342.         self.assertEqual(
    
  1343.             list(project_state.relations["tests", "user"]),
    
  1344.             [("tests", "comment"), ("tests", "post")],
    
  1345.         )
    
  1346.         self.assertEqual(
    
  1347.             list(project_state.relations["tests", "comment"]),
    
  1348.             [("tests", "comment")],
    
  1349.         )
    
  1350. 
    
  1351.         related_field = project_state.relations["tests", "user"]["tests", "comment"]
    
  1352.         project_state.rename_model("tests", "comment", "opinion")
    
  1353.         self.assertEqual(
    
  1354.             list(project_state.relations["tests", "user"]),
    
  1355.             [("tests", "post"), ("tests", "opinion")],
    
  1356.         )
    
  1357.         self.assertEqual(
    
  1358.             list(project_state.relations["tests", "opinion"]),
    
  1359.             [("tests", "opinion")],
    
  1360.         )
    
  1361.         self.assertNotIn(("tests", "comment"), project_state.relations)
    
  1362.         self.assertEqual(
    
  1363.             project_state.relations["tests", "user"]["tests", "opinion"],
    
  1364.             related_field,
    
  1365.         )
    
  1366. 
    
  1367.         project_state.rename_model("tests", "user", "author")
    
  1368.         self.assertEqual(
    
  1369.             list(project_state.relations["tests", "author"]),
    
  1370.             [("tests", "post"), ("tests", "opinion")],
    
  1371.         )
    
  1372.         self.assertNotIn(("tests", "user"), project_state.relations)
    
  1373. 
    
  1374.     def test_rename_model_no_relations(self):
    
  1375.         project_state = self.get_base_project_state()
    
  1376.         self.assertEqual(
    
  1377.             list(project_state.relations["tests", "user"]),
    
  1378.             [("tests", "comment"), ("tests", "post")],
    
  1379.         )
    
  1380.         related_field = project_state.relations["tests", "user"]["tests", "post"]
    
  1381.         self.assertNotIn(("tests", "post"), project_state.relations)
    
  1382.         # Rename a model without relations.
    
  1383.         project_state.rename_model("tests", "post", "blog")
    
  1384.         self.assertEqual(
    
  1385.             list(project_state.relations["tests", "user"]),
    
  1386.             [("tests", "comment"), ("tests", "blog")],
    
  1387.         )
    
  1388.         self.assertNotIn(("tests", "blog"), project_state.relations)
    
  1389.         self.assertEqual(
    
  1390.             related_field,
    
  1391.             project_state.relations["tests", "user"]["tests", "blog"],
    
  1392.         )
    
  1393. 
    
  1394.     def test_add_field(self):
    
  1395.         project_state = self.get_base_project_state()
    
  1396.         self.assertNotIn(("tests", "post"), project_state.relations)
    
  1397.         # Add a self-referential foreign key.
    
  1398.         new_field = models.ForeignKey("self", models.CASCADE)
    
  1399.         project_state.add_field(
    
  1400.             "tests",
    
  1401.             "post",
    
  1402.             "next_post",
    
  1403.             new_field,
    
  1404.             preserve_default=True,
    
  1405.         )
    
  1406.         self.assertEqual(
    
  1407.             list(project_state.relations["tests", "post"]),
    
  1408.             [("tests", "post")],
    
  1409.         )
    
  1410.         self.assertEqual(
    
  1411.             project_state.relations["tests", "post"]["tests", "post"],
    
  1412.             {"next_post": new_field},
    
  1413.         )
    
  1414.         # Add a foreign key.
    
  1415.         new_field = models.ForeignKey("tests.post", models.CASCADE)
    
  1416.         project_state.add_field(
    
  1417.             "tests",
    
  1418.             "comment",
    
  1419.             "post",
    
  1420.             new_field,
    
  1421.             preserve_default=True,
    
  1422.         )
    
  1423.         self.assertEqual(
    
  1424.             list(project_state.relations["tests", "post"]),
    
  1425.             [("tests", "post"), ("tests", "comment")],
    
  1426.         )
    
  1427.         self.assertEqual(
    
  1428.             project_state.relations["tests", "post"]["tests", "comment"],
    
  1429.             {"post": new_field},
    
  1430.         )
    
  1431. 
    
  1432.     def test_add_field_m2m_with_through(self):
    
  1433.         project_state = self.get_base_project_state()
    
  1434.         project_state.add_model(
    
  1435.             ModelState(
    
  1436.                 app_label="tests",
    
  1437.                 name="Tag",
    
  1438.                 fields=[("id", models.AutoField(primary_key=True))],
    
  1439.             )
    
  1440.         )
    
  1441.         project_state.add_model(
    
  1442.             ModelState(
    
  1443.                 app_label="tests",
    
  1444.                 name="PostTag",
    
  1445.                 fields=[
    
  1446.                     ("id", models.AutoField(primary_key=True)),
    
  1447.                     ("post", models.ForeignKey("tests.post", models.CASCADE)),
    
  1448.                     ("tag", models.ForeignKey("tests.tag", models.CASCADE)),
    
  1449.                 ],
    
  1450.             )
    
  1451.         )
    
  1452.         self.assertEqual(
    
  1453.             list(project_state.relations["tests", "post"]),
    
  1454.             [("tests", "posttag")],
    
  1455.         )
    
  1456.         self.assertEqual(
    
  1457.             list(project_state.relations["tests", "tag"]),
    
  1458.             [("tests", "posttag")],
    
  1459.         )
    
  1460.         # Add a many-to-many field with the through model.
    
  1461.         new_field = models.ManyToManyField("tests.tag", through="tests.posttag")
    
  1462.         project_state.add_field(
    
  1463.             "tests",
    
  1464.             "post",
    
  1465.             "tags",
    
  1466.             new_field,
    
  1467.             preserve_default=True,
    
  1468.         )
    
  1469.         self.assertEqual(
    
  1470.             list(project_state.relations["tests", "post"]),
    
  1471.             [("tests", "posttag")],
    
  1472.         )
    
  1473.         self.assertEqual(
    
  1474.             list(project_state.relations["tests", "tag"]),
    
  1475.             [("tests", "posttag"), ("tests", "post")],
    
  1476.         )
    
  1477.         self.assertEqual(
    
  1478.             project_state.relations["tests", "tag"]["tests", "post"],
    
  1479.             {"tags": new_field},
    
  1480.         )
    
  1481. 
    
  1482.     def test_remove_field(self):
    
  1483.         project_state = self.get_base_project_state()
    
  1484.         self.assertEqual(
    
  1485.             list(project_state.relations["tests", "user"]),
    
  1486.             [("tests", "comment"), ("tests", "post")],
    
  1487.         )
    
  1488.         # Remove a many-to-many field.
    
  1489.         project_state.remove_field("tests", "post", "authors")
    
  1490.         self.assertEqual(
    
  1491.             list(project_state.relations["tests", "user"]),
    
  1492.             [("tests", "comment")],
    
  1493.         )
    
  1494.         # Remove a foreign key.
    
  1495.         project_state.remove_field("tests", "comment", "user")
    
  1496.         self.assertEqual(project_state.relations["tests", "user"], {})
    
  1497. 
    
  1498.     def test_remove_field_no_relations(self):
    
  1499.         project_state = self.get_base_project_state()
    
  1500.         self.assertEqual(
    
  1501.             list(project_state.relations["tests", "user"]),
    
  1502.             [("tests", "comment"), ("tests", "post")],
    
  1503.         )
    
  1504.         # Remove a non-relation field.
    
  1505.         project_state.remove_field("tests", "post", "text")
    
  1506.         self.assertEqual(
    
  1507.             list(project_state.relations["tests", "user"]),
    
  1508.             [("tests", "comment"), ("tests", "post")],
    
  1509.         )
    
  1510. 
    
  1511.     def test_rename_field(self):
    
  1512.         project_state = self.get_base_project_state()
    
  1513.         field = project_state.models["tests", "comment"].fields["user"]
    
  1514.         self.assertEqual(
    
  1515.             project_state.relations["tests", "user"]["tests", "comment"],
    
  1516.             {"user": field},
    
  1517.         )
    
  1518. 
    
  1519.         project_state.rename_field("tests", "comment", "user", "author")
    
  1520.         renamed_field = project_state.models["tests", "comment"].fields["author"]
    
  1521.         self.assertEqual(
    
  1522.             project_state.relations["tests", "user"]["tests", "comment"],
    
  1523.             {"author": renamed_field},
    
  1524.         )
    
  1525.         self.assertEqual(field, renamed_field)
    
  1526. 
    
  1527.     def test_rename_field_no_relations(self):
    
  1528.         project_state = self.get_base_project_state()
    
  1529.         self.assertEqual(
    
  1530.             list(project_state.relations["tests", "user"]),
    
  1531.             [("tests", "comment"), ("tests", "post")],
    
  1532.         )
    
  1533.         # Rename a non-relation field.
    
  1534.         project_state.rename_field("tests", "post", "text", "description")
    
  1535.         self.assertEqual(
    
  1536.             list(project_state.relations["tests", "user"]),
    
  1537.             [("tests", "comment"), ("tests", "post")],
    
  1538.         )
    
  1539. 
    
  1540.     def test_alter_field(self):
    
  1541.         project_state = self.get_base_project_state()
    
  1542.         self.assertEqual(
    
  1543.             list(project_state.relations["tests", "user"]),
    
  1544.             [("tests", "comment"), ("tests", "post")],
    
  1545.         )
    
  1546.         # Alter a foreign key to a non-relation field.
    
  1547.         project_state.alter_field(
    
  1548.             "tests",
    
  1549.             "comment",
    
  1550.             "user",
    
  1551.             models.IntegerField(),
    
  1552.             preserve_default=True,
    
  1553.         )
    
  1554.         self.assertEqual(
    
  1555.             list(project_state.relations["tests", "user"]),
    
  1556.             [("tests", "post")],
    
  1557.         )
    
  1558.         # Alter a non-relation field to a many-to-many field.
    
  1559.         m2m_field = models.ManyToManyField("tests.user")
    
  1560.         project_state.alter_field(
    
  1561.             "tests",
    
  1562.             "comment",
    
  1563.             "user",
    
  1564.             m2m_field,
    
  1565.             preserve_default=True,
    
  1566.         )
    
  1567.         self.assertEqual(
    
  1568.             list(project_state.relations["tests", "user"]),
    
  1569.             [("tests", "post"), ("tests", "comment")],
    
  1570.         )
    
  1571.         self.assertEqual(
    
  1572.             project_state.relations["tests", "user"]["tests", "comment"],
    
  1573.             {"user": m2m_field},
    
  1574.         )
    
  1575. 
    
  1576.     def test_alter_field_m2m_to_fk(self):
    
  1577.         project_state = self.get_base_project_state()
    
  1578.         project_state.add_model(
    
  1579.             ModelState(
    
  1580.                 app_label="tests_other",
    
  1581.                 name="user_other",
    
  1582.                 fields=[("id", models.AutoField(primary_key=True))],
    
  1583.             )
    
  1584.         )
    
  1585.         self.assertEqual(
    
  1586.             list(project_state.relations["tests", "user"]),
    
  1587.             [("tests", "comment"), ("tests", "post")],
    
  1588.         )
    
  1589.         self.assertNotIn(("tests_other", "user_other"), project_state.relations)
    
  1590.         # Alter a many-to-many field to a foreign key.
    
  1591.         foreign_key = models.ForeignKey("tests_other.user_other", models.CASCADE)
    
  1592.         project_state.alter_field(
    
  1593.             "tests",
    
  1594.             "post",
    
  1595.             "authors",
    
  1596.             foreign_key,
    
  1597.             preserve_default=True,
    
  1598.         )
    
  1599.         self.assertEqual(
    
  1600.             list(project_state.relations["tests", "user"]),
    
  1601.             [("tests", "comment")],
    
  1602.         )
    
  1603.         self.assertEqual(
    
  1604.             list(project_state.relations["tests_other", "user_other"]),
    
  1605.             [("tests", "post")],
    
  1606.         )
    
  1607.         self.assertEqual(
    
  1608.             project_state.relations["tests_other", "user_other"]["tests", "post"],
    
  1609.             {"authors": foreign_key},
    
  1610.         )
    
  1611. 
    
  1612.     def test_many_relations_to_same_model(self):
    
  1613.         project_state = self.get_base_project_state()
    
  1614.         new_field = models.ForeignKey("tests.user", models.CASCADE)
    
  1615.         project_state.add_field(
    
  1616.             "tests",
    
  1617.             "comment",
    
  1618.             "reviewer",
    
  1619.             new_field,
    
  1620.             preserve_default=True,
    
  1621.         )
    
  1622.         self.assertEqual(
    
  1623.             list(project_state.relations["tests", "user"]),
    
  1624.             [("tests", "comment"), ("tests", "post")],
    
  1625.         )
    
  1626.         comment_rels = project_state.relations["tests", "user"]["tests", "comment"]
    
  1627.         # Two foreign keys to the same model.
    
  1628.         self.assertEqual(len(comment_rels), 2)
    
  1629.         self.assertEqual(comment_rels["reviewer"], new_field)
    
  1630.         # Rename the second foreign key.
    
  1631.         project_state.rename_field("tests", "comment", "reviewer", "supervisor")
    
  1632.         self.assertEqual(len(comment_rels), 2)
    
  1633.         self.assertEqual(comment_rels["supervisor"], new_field)
    
  1634.         # Remove the first foreign key.
    
  1635.         project_state.remove_field("tests", "comment", "user")
    
  1636.         self.assertEqual(comment_rels, {"supervisor": new_field})
    
  1637. 
    
  1638. 
    
  1639. class ModelStateTests(SimpleTestCase):
    
  1640.     def test_custom_model_base(self):
    
  1641.         state = ModelState.from_model(ModelWithCustomBase)
    
  1642.         self.assertEqual(state.bases, (models.Model,))
    
  1643. 
    
  1644.     def test_bound_field_sanity_check(self):
    
  1645.         field = models.CharField(max_length=1)
    
  1646.         field.model = models.Model
    
  1647.         with self.assertRaisesMessage(
    
  1648.             ValueError, 'ModelState.fields cannot be bound to a model - "field" is.'
    
  1649.         ):
    
  1650.             ModelState("app", "Model", [("field", field)])
    
  1651. 
    
  1652.     def test_sanity_check_to(self):
    
  1653.         field = models.ForeignKey(UnicodeModel, models.CASCADE)
    
  1654.         with self.assertRaisesMessage(
    
  1655.             ValueError,
    
  1656.             'ModelState.fields cannot refer to a model class - "field.to" does. '
    
  1657.             "Use a string reference instead.",
    
  1658.         ):
    
  1659.             ModelState("app", "Model", [("field", field)])
    
  1660. 
    
  1661.     def test_sanity_check_through(self):
    
  1662.         field = models.ManyToManyField("UnicodeModel")
    
  1663.         field.remote_field.through = UnicodeModel
    
  1664.         with self.assertRaisesMessage(
    
  1665.             ValueError,
    
  1666.             'ModelState.fields cannot refer to a model class - "field.through" does. '
    
  1667.             "Use a string reference instead.",
    
  1668.         ):
    
  1669.             ModelState("app", "Model", [("field", field)])
    
  1670. 
    
  1671.     def test_sanity_index_name(self):
    
  1672.         field = models.IntegerField()
    
  1673.         options = {"indexes": [models.Index(fields=["field"])]}
    
  1674.         msg = (
    
  1675.             "Indexes passed to ModelState require a name attribute. <Index: "
    
  1676.             "fields=['field']> doesn't have one."
    
  1677.         )
    
  1678.         with self.assertRaisesMessage(ValueError, msg):
    
  1679.             ModelState("app", "Model", [("field", field)], options=options)
    
  1680. 
    
  1681.     def test_fields_immutability(self):
    
  1682.         """
    
  1683.         Rendering a model state doesn't alter its internal fields.
    
  1684.         """
    
  1685.         apps = Apps()
    
  1686.         field = models.CharField(max_length=1)
    
  1687.         state = ModelState("app", "Model", [("name", field)])
    
  1688.         Model = state.render(apps)
    
  1689.         self.assertNotEqual(Model._meta.get_field("name"), field)
    
  1690. 
    
  1691.     def test_repr(self):
    
  1692.         field = models.CharField(max_length=1)
    
  1693.         state = ModelState(
    
  1694.             "app", "Model", [("name", field)], bases=["app.A", "app.B", "app.C"]
    
  1695.         )
    
  1696.         self.assertEqual(repr(state), "<ModelState: 'app.Model'>")
    
  1697. 
    
  1698.         project_state = ProjectState()
    
  1699.         project_state.add_model(state)
    
  1700.         with self.assertRaisesMessage(
    
  1701.             InvalidBasesError, "Cannot resolve bases for [<ModelState: 'app.Model'>]"
    
  1702.         ):
    
  1703.             project_state.apps
    
  1704. 
    
  1705.     def test_fields_ordering_equality(self):
    
  1706.         state = ModelState(
    
  1707.             "migrations",
    
  1708.             "Tag",
    
  1709.             [
    
  1710.                 ("id", models.AutoField(primary_key=True)),
    
  1711.                 ("name", models.CharField(max_length=100)),
    
  1712.                 ("hidden", models.BooleanField()),
    
  1713.             ],
    
  1714.         )
    
  1715.         reordered_state = ModelState(
    
  1716.             "migrations",
    
  1717.             "Tag",
    
  1718.             [
    
  1719.                 ("id", models.AutoField(primary_key=True)),
    
  1720.                 # Purposely re-ordered.
    
  1721.                 ("hidden", models.BooleanField()),
    
  1722.                 ("name", models.CharField(max_length=100)),
    
  1723.             ],
    
  1724.         )
    
  1725.         self.assertEqual(state, reordered_state)
    
  1726. 
    
  1727.     @override_settings(TEST_SWAPPABLE_MODEL="migrations.SomeFakeModel")
    
  1728.     def test_create_swappable(self):
    
  1729.         """
    
  1730.         Tests making a ProjectState from an Apps with a swappable model
    
  1731.         """
    
  1732.         new_apps = Apps(["migrations"])
    
  1733. 
    
  1734.         class Author(models.Model):
    
  1735.             name = models.CharField(max_length=255)
    
  1736.             bio = models.TextField()
    
  1737.             age = models.IntegerField(blank=True, null=True)
    
  1738. 
    
  1739.             class Meta:
    
  1740.                 app_label = "migrations"
    
  1741.                 apps = new_apps
    
  1742.                 swappable = "TEST_SWAPPABLE_MODEL"
    
  1743. 
    
  1744.         author_state = ModelState.from_model(Author)
    
  1745.         self.assertEqual(author_state.app_label, "migrations")
    
  1746.         self.assertEqual(author_state.name, "Author")
    
  1747.         self.assertEqual(list(author_state.fields), ["id", "name", "bio", "age"])
    
  1748.         self.assertEqual(author_state.fields["name"].max_length, 255)
    
  1749.         self.assertIs(author_state.fields["bio"].null, False)
    
  1750.         self.assertIs(author_state.fields["age"].null, True)
    
  1751.         self.assertEqual(
    
  1752.             author_state.options,
    
  1753.             {"swappable": "TEST_SWAPPABLE_MODEL", "indexes": [], "constraints": []},
    
  1754.         )
    
  1755.         self.assertEqual(author_state.bases, (models.Model,))
    
  1756.         self.assertEqual(author_state.managers, [])
    
  1757. 
    
  1758.     @override_settings(TEST_SWAPPABLE_MODEL="migrations.SomeFakeModel")
    
  1759.     def test_create_swappable_from_abstract(self):
    
  1760.         """
    
  1761.         A swappable model inheriting from a hierarchy:
    
  1762.         concrete -> abstract -> concrete.
    
  1763.         """
    
  1764.         new_apps = Apps(["migrations"])
    
  1765. 
    
  1766.         class SearchableLocation(models.Model):
    
  1767.             keywords = models.CharField(max_length=256)
    
  1768. 
    
  1769.             class Meta:
    
  1770.                 app_label = "migrations"
    
  1771.                 apps = new_apps
    
  1772. 
    
  1773.         class Station(SearchableLocation):
    
  1774.             name = models.CharField(max_length=128)
    
  1775. 
    
  1776.             class Meta:
    
  1777.                 abstract = True
    
  1778. 
    
  1779.         class BusStation(Station):
    
  1780.             bus_routes = models.CharField(max_length=128)
    
  1781.             inbound = models.BooleanField(default=False)
    
  1782. 
    
  1783.             class Meta(Station.Meta):
    
  1784.                 app_label = "migrations"
    
  1785.                 apps = new_apps
    
  1786.                 swappable = "TEST_SWAPPABLE_MODEL"
    
  1787. 
    
  1788.         station_state = ModelState.from_model(BusStation)
    
  1789.         self.assertEqual(station_state.app_label, "migrations")
    
  1790.         self.assertEqual(station_state.name, "BusStation")
    
  1791.         self.assertEqual(
    
  1792.             list(station_state.fields),
    
  1793.             ["searchablelocation_ptr", "name", "bus_routes", "inbound"],
    
  1794.         )
    
  1795.         self.assertEqual(station_state.fields["name"].max_length, 128)
    
  1796.         self.assertIs(station_state.fields["bus_routes"].null, False)
    
  1797.         self.assertEqual(
    
  1798.             station_state.options,
    
  1799.             {
    
  1800.                 "abstract": False,
    
  1801.                 "swappable": "TEST_SWAPPABLE_MODEL",
    
  1802.                 "indexes": [],
    
  1803.                 "constraints": [],
    
  1804.             },
    
  1805.         )
    
  1806.         self.assertEqual(station_state.bases, ("migrations.searchablelocation",))
    
  1807.         self.assertEqual(station_state.managers, [])
    
  1808. 
    
  1809.     @override_settings(TEST_SWAPPABLE_MODEL="migrations.SomeFakeModel")
    
  1810.     def test_custom_manager_swappable(self):
    
  1811.         """
    
  1812.         Tests making a ProjectState from unused models with custom managers
    
  1813.         """
    
  1814.         new_apps = Apps(["migrations"])
    
  1815. 
    
  1816.         class Food(models.Model):
    
  1817.             food_mgr = FoodManager("a", "b")
    
  1818.             food_qs = FoodQuerySet.as_manager()
    
  1819.             food_no_mgr = NoMigrationFoodManager("x", "y")
    
  1820. 
    
  1821.             class Meta:
    
  1822.                 app_label = "migrations"
    
  1823.                 apps = new_apps
    
  1824.                 swappable = "TEST_SWAPPABLE_MODEL"
    
  1825. 
    
  1826.         food_state = ModelState.from_model(Food)
    
  1827. 
    
  1828.         # The default manager is used in migrations
    
  1829.         self.assertEqual([name for name, mgr in food_state.managers], ["food_mgr"])
    
  1830.         self.assertEqual(food_state.managers[0][1].args, ("a", "b", 1, 2))
    
  1831. 
    
  1832.     @isolate_apps("migrations", "django.contrib.contenttypes")
    
  1833.     def test_order_with_respect_to_private_field(self):
    
  1834.         class PrivateFieldModel(models.Model):
    
  1835.             content_type = models.ForeignKey("contenttypes.ContentType", models.CASCADE)
    
  1836.             object_id = models.PositiveIntegerField()
    
  1837.             private = GenericForeignKey()
    
  1838. 
    
  1839.             class Meta:
    
  1840.                 order_with_respect_to = "private"
    
  1841. 
    
  1842.         state = ModelState.from_model(PrivateFieldModel)
    
  1843.         self.assertNotIn("order_with_respect_to", state.options)
    
  1844. 
    
  1845.     @isolate_apps("migrations")
    
  1846.     def test_abstract_model_children_inherit_indexes(self):
    
  1847.         class Abstract(models.Model):
    
  1848.             name = models.CharField(max_length=50)
    
  1849. 
    
  1850.             class Meta:
    
  1851.                 app_label = "migrations"
    
  1852.                 abstract = True
    
  1853.                 indexes = [models.Index(fields=["name"])]
    
  1854. 
    
  1855.         class Child1(Abstract):
    
  1856.             pass
    
  1857. 
    
  1858.         class Child2(Abstract):
    
  1859.             pass
    
  1860. 
    
  1861.         child1_state = ModelState.from_model(Child1)
    
  1862.         child2_state = ModelState.from_model(Child2)
    
  1863.         index_names = [index.name for index in child1_state.options["indexes"]]
    
  1864.         self.assertEqual(index_names, ["migrations__name_b0afd7_idx"])
    
  1865.         index_names = [index.name for index in child2_state.options["indexes"]]
    
  1866.         self.assertEqual(index_names, ["migrations__name_016466_idx"])
    
  1867. 
    
  1868.         # Modifying the state doesn't modify the index on the model.
    
  1869.         child1_state.options["indexes"][0].name = "bar"
    
  1870.         self.assertEqual(Child1._meta.indexes[0].name, "migrations__name_b0afd7_idx")
    
  1871. 
    
  1872.     @isolate_apps("migrations")
    
  1873.     def test_explicit_index_name(self):
    
  1874.         class TestModel(models.Model):
    
  1875.             name = models.CharField(max_length=50)
    
  1876. 
    
  1877.             class Meta:
    
  1878.                 app_label = "migrations"
    
  1879.                 indexes = [models.Index(fields=["name"], name="foo_idx")]
    
  1880. 
    
  1881.         model_state = ModelState.from_model(TestModel)
    
  1882.         index_names = [index.name for index in model_state.options["indexes"]]
    
  1883.         self.assertEqual(index_names, ["foo_idx"])
    
  1884. 
    
  1885.     @isolate_apps("migrations")
    
  1886.     def test_from_model_constraints(self):
    
  1887.         class ModelWithConstraints(models.Model):
    
  1888.             size = models.IntegerField()
    
  1889. 
    
  1890.             class Meta:
    
  1891.                 constraints = [
    
  1892.                     models.CheckConstraint(check=models.Q(size__gt=1), name="size_gt_1")
    
  1893.                 ]
    
  1894. 
    
  1895.         state = ModelState.from_model(ModelWithConstraints)
    
  1896.         model_constraints = ModelWithConstraints._meta.constraints
    
  1897.         state_constraints = state.options["constraints"]
    
  1898.         self.assertEqual(model_constraints, state_constraints)
    
  1899.         self.assertIsNot(model_constraints, state_constraints)
    
  1900.         self.assertIsNot(model_constraints[0], state_constraints[0])
    
  1901. 
    
  1902. 
    
  1903. class RelatedModelsTests(SimpleTestCase):
    
  1904.     def setUp(self):
    
  1905.         self.apps = Apps(["migrations.related_models_app"])
    
  1906. 
    
  1907.     def create_model(
    
  1908.         self, name, foreign_keys=[], bases=(), abstract=False, proxy=False
    
  1909.     ):
    
  1910.         test_name = "related_models_app"
    
  1911.         assert not (abstract and proxy)
    
  1912.         meta_contents = {
    
  1913.             "abstract": abstract,
    
  1914.             "app_label": test_name,
    
  1915.             "apps": self.apps,
    
  1916.             "proxy": proxy,
    
  1917.         }
    
  1918.         meta = type("Meta", (), meta_contents)
    
  1919.         if not bases:
    
  1920.             bases = (models.Model,)
    
  1921.         body = {
    
  1922.             "Meta": meta,
    
  1923.             "__module__": "__fake__",
    
  1924.         }
    
  1925.         fname_base = fname = "%s_%%d" % name.lower()
    
  1926.         for i, fk in enumerate(foreign_keys, 1):
    
  1927.             fname = fname_base % i
    
  1928.             body[fname] = fk
    
  1929.         return type(name, bases, body)
    
  1930. 
    
  1931.     def assertRelated(self, model, needle):
    
  1932.         self.assertEqual(
    
  1933.             get_related_models_recursive(model),
    
  1934.             {(n._meta.app_label, n._meta.model_name) for n in needle},
    
  1935.         )
    
  1936. 
    
  1937.     def test_unrelated(self):
    
  1938.         A = self.create_model("A")
    
  1939.         B = self.create_model("B")
    
  1940.         self.assertRelated(A, [])
    
  1941.         self.assertRelated(B, [])
    
  1942. 
    
  1943.     def test_direct_fk(self):
    
  1944.         A = self.create_model(
    
  1945.             "A", foreign_keys=[models.ForeignKey("B", models.CASCADE)]
    
  1946.         )
    
  1947.         B = self.create_model("B")
    
  1948.         self.assertRelated(A, [B])
    
  1949.         self.assertRelated(B, [A])
    
  1950. 
    
  1951.     def test_direct_hidden_fk(self):
    
  1952.         A = self.create_model(
    
  1953.             "A", foreign_keys=[models.ForeignKey("B", models.CASCADE, related_name="+")]
    
  1954.         )
    
  1955.         B = self.create_model("B")
    
  1956.         self.assertRelated(A, [B])
    
  1957.         self.assertRelated(B, [A])
    
  1958. 
    
  1959.     def test_fk_through_proxy(self):
    
  1960.         A = self.create_model("A")
    
  1961.         B = self.create_model("B", bases=(A,), proxy=True)
    
  1962.         C = self.create_model("C", bases=(B,), proxy=True)
    
  1963.         D = self.create_model(
    
  1964.             "D", foreign_keys=[models.ForeignKey("C", models.CASCADE)]
    
  1965.         )
    
  1966.         self.assertRelated(A, [B, C, D])
    
  1967.         self.assertRelated(B, [A, C, D])
    
  1968.         self.assertRelated(C, [A, B, D])
    
  1969.         self.assertRelated(D, [A, B, C])
    
  1970. 
    
  1971.     def test_nested_fk(self):
    
  1972.         A = self.create_model(
    
  1973.             "A", foreign_keys=[models.ForeignKey("B", models.CASCADE)]
    
  1974.         )
    
  1975.         B = self.create_model(
    
  1976.             "B", foreign_keys=[models.ForeignKey("C", models.CASCADE)]
    
  1977.         )
    
  1978.         C = self.create_model("C")
    
  1979.         self.assertRelated(A, [B, C])
    
  1980.         self.assertRelated(B, [A, C])
    
  1981.         self.assertRelated(C, [A, B])
    
  1982. 
    
  1983.     def test_two_sided(self):
    
  1984.         A = self.create_model(
    
  1985.             "A", foreign_keys=[models.ForeignKey("B", models.CASCADE)]
    
  1986.         )
    
  1987.         B = self.create_model(
    
  1988.             "B", foreign_keys=[models.ForeignKey("A", models.CASCADE)]
    
  1989.         )
    
  1990.         self.assertRelated(A, [B])
    
  1991.         self.assertRelated(B, [A])
    
  1992. 
    
  1993.     def test_circle(self):
    
  1994.         A = self.create_model(
    
  1995.             "A", foreign_keys=[models.ForeignKey("B", models.CASCADE)]
    
  1996.         )
    
  1997.         B = self.create_model(
    
  1998.             "B", foreign_keys=[models.ForeignKey("C", models.CASCADE)]
    
  1999.         )
    
  2000.         C = self.create_model(
    
  2001.             "C", foreign_keys=[models.ForeignKey("A", models.CASCADE)]
    
  2002.         )
    
  2003.         self.assertRelated(A, [B, C])
    
  2004.         self.assertRelated(B, [A, C])
    
  2005.         self.assertRelated(C, [A, B])
    
  2006. 
    
  2007.     def test_base(self):
    
  2008.         A = self.create_model("A")
    
  2009.         B = self.create_model("B", bases=(A,))
    
  2010.         self.assertRelated(A, [B])
    
  2011.         self.assertRelated(B, [A])
    
  2012. 
    
  2013.     def test_nested_base(self):
    
  2014.         A = self.create_model("A")
    
  2015.         B = self.create_model("B", bases=(A,))
    
  2016.         C = self.create_model("C", bases=(B,))
    
  2017.         self.assertRelated(A, [B, C])
    
  2018.         self.assertRelated(B, [A, C])
    
  2019.         self.assertRelated(C, [A, B])
    
  2020. 
    
  2021.     def test_multiple_bases(self):
    
  2022.         A = self.create_model("A")
    
  2023.         B = self.create_model("B")
    
  2024.         C = self.create_model(
    
  2025.             "C",
    
  2026.             bases=(
    
  2027.                 A,
    
  2028.                 B,
    
  2029.             ),
    
  2030.         )
    
  2031.         self.assertRelated(A, [B, C])
    
  2032.         self.assertRelated(B, [A, C])
    
  2033.         self.assertRelated(C, [A, B])
    
  2034. 
    
  2035.     def test_multiple_nested_bases(self):
    
  2036.         A = self.create_model("A")
    
  2037.         B = self.create_model("B")
    
  2038.         C = self.create_model(
    
  2039.             "C",
    
  2040.             bases=(
    
  2041.                 A,
    
  2042.                 B,
    
  2043.             ),
    
  2044.         )
    
  2045.         D = self.create_model("D")
    
  2046.         E = self.create_model("E", bases=(D,))
    
  2047.         F = self.create_model(
    
  2048.             "F",
    
  2049.             bases=(
    
  2050.                 C,
    
  2051.                 E,
    
  2052.             ),
    
  2053.         )
    
  2054.         Y = self.create_model("Y")
    
  2055.         Z = self.create_model("Z", bases=(Y,))
    
  2056.         self.assertRelated(A, [B, C, D, E, F])
    
  2057.         self.assertRelated(B, [A, C, D, E, F])
    
  2058.         self.assertRelated(C, [A, B, D, E, F])
    
  2059.         self.assertRelated(D, [A, B, C, E, F])
    
  2060.         self.assertRelated(E, [A, B, C, D, F])
    
  2061.         self.assertRelated(F, [A, B, C, D, E])
    
  2062.         self.assertRelated(Y, [Z])
    
  2063.         self.assertRelated(Z, [Y])
    
  2064. 
    
  2065.     def test_base_to_base_fk(self):
    
  2066.         A = self.create_model(
    
  2067.             "A", foreign_keys=[models.ForeignKey("Y", models.CASCADE)]
    
  2068.         )
    
  2069.         B = self.create_model("B", bases=(A,))
    
  2070.         Y = self.create_model("Y")
    
  2071.         Z = self.create_model("Z", bases=(Y,))
    
  2072.         self.assertRelated(A, [B, Y, Z])
    
  2073.         self.assertRelated(B, [A, Y, Z])
    
  2074.         self.assertRelated(Y, [A, B, Z])
    
  2075.         self.assertRelated(Z, [A, B, Y])
    
  2076. 
    
  2077.     def test_base_to_subclass_fk(self):
    
  2078.         A = self.create_model(
    
  2079.             "A", foreign_keys=[models.ForeignKey("Z", models.CASCADE)]
    
  2080.         )
    
  2081.         B = self.create_model("B", bases=(A,))
    
  2082.         Y = self.create_model("Y")
    
  2083.         Z = self.create_model("Z", bases=(Y,))
    
  2084.         self.assertRelated(A, [B, Y, Z])
    
  2085.         self.assertRelated(B, [A, Y, Z])
    
  2086.         self.assertRelated(Y, [A, B, Z])
    
  2087.         self.assertRelated(Z, [A, B, Y])
    
  2088. 
    
  2089.     def test_direct_m2m(self):
    
  2090.         A = self.create_model("A", foreign_keys=[models.ManyToManyField("B")])
    
  2091.         B = self.create_model("B")
    
  2092.         self.assertRelated(A, [A.a_1.rel.through, B])
    
  2093.         self.assertRelated(B, [A, A.a_1.rel.through])
    
  2094. 
    
  2095.     def test_direct_m2m_self(self):
    
  2096.         A = self.create_model("A", foreign_keys=[models.ManyToManyField("A")])
    
  2097.         self.assertRelated(A, [A.a_1.rel.through])
    
  2098. 
    
  2099.     def test_intermediate_m2m_self(self):
    
  2100.         A = self.create_model(
    
  2101.             "A", foreign_keys=[models.ManyToManyField("A", through="T")]
    
  2102.         )
    
  2103.         T = self.create_model(
    
  2104.             "T",
    
  2105.             foreign_keys=[
    
  2106.                 models.ForeignKey("A", models.CASCADE),
    
  2107.                 models.ForeignKey("A", models.CASCADE),
    
  2108.             ],
    
  2109.         )
    
  2110.         self.assertRelated(A, [T])
    
  2111.         self.assertRelated(T, [A])
    
  2112. 
    
  2113.     def test_intermediate_m2m(self):
    
  2114.         A = self.create_model(
    
  2115.             "A", foreign_keys=[models.ManyToManyField("B", through="T")]
    
  2116.         )
    
  2117.         B = self.create_model("B")
    
  2118.         T = self.create_model(
    
  2119.             "T",
    
  2120.             foreign_keys=[
    
  2121.                 models.ForeignKey("A", models.CASCADE),
    
  2122.                 models.ForeignKey("B", models.CASCADE),
    
  2123.             ],
    
  2124.         )
    
  2125.         self.assertRelated(A, [B, T])
    
  2126.         self.assertRelated(B, [A, T])
    
  2127.         self.assertRelated(T, [A, B])
    
  2128. 
    
  2129.     def test_intermediate_m2m_extern_fk(self):
    
  2130.         A = self.create_model(
    
  2131.             "A", foreign_keys=[models.ManyToManyField("B", through="T")]
    
  2132.         )
    
  2133.         B = self.create_model("B")
    
  2134.         Z = self.create_model("Z")
    
  2135.         T = self.create_model(
    
  2136.             "T",
    
  2137.             foreign_keys=[
    
  2138.                 models.ForeignKey("A", models.CASCADE),
    
  2139.                 models.ForeignKey("B", models.CASCADE),
    
  2140.                 models.ForeignKey("Z", models.CASCADE),
    
  2141.             ],
    
  2142.         )
    
  2143.         self.assertRelated(A, [B, T, Z])
    
  2144.         self.assertRelated(B, [A, T, Z])
    
  2145.         self.assertRelated(T, [A, B, Z])
    
  2146.         self.assertRelated(Z, [A, B, T])
    
  2147. 
    
  2148.     def test_intermediate_m2m_base(self):
    
  2149.         A = self.create_model(
    
  2150.             "A", foreign_keys=[models.ManyToManyField("B", through="T")]
    
  2151.         )
    
  2152.         B = self.create_model("B")
    
  2153.         S = self.create_model("S")
    
  2154.         T = self.create_model(
    
  2155.             "T",
    
  2156.             foreign_keys=[
    
  2157.                 models.ForeignKey("A", models.CASCADE),
    
  2158.                 models.ForeignKey("B", models.CASCADE),
    
  2159.             ],
    
  2160.             bases=(S,),
    
  2161.         )
    
  2162.         self.assertRelated(A, [B, S, T])
    
  2163.         self.assertRelated(B, [A, S, T])
    
  2164.         self.assertRelated(S, [A, B, T])
    
  2165.         self.assertRelated(T, [A, B, S])
    
  2166. 
    
  2167.     def test_generic_fk(self):
    
  2168.         A = self.create_model(
    
  2169.             "A",
    
  2170.             foreign_keys=[
    
  2171.                 models.ForeignKey("B", models.CASCADE),
    
  2172.                 GenericForeignKey(),
    
  2173.             ],
    
  2174.         )
    
  2175.         B = self.create_model(
    
  2176.             "B",
    
  2177.             foreign_keys=[
    
  2178.                 models.ForeignKey("C", models.CASCADE),
    
  2179.             ],
    
  2180.         )
    
  2181.         self.assertRelated(A, [B])
    
  2182.         self.assertRelated(B, [A])
    
  2183. 
    
  2184.     def test_abstract_base(self):
    
  2185.         A = self.create_model("A", abstract=True)
    
  2186.         B = self.create_model("B", bases=(A,))
    
  2187.         self.assertRelated(A, [B])
    
  2188.         self.assertRelated(B, [])
    
  2189. 
    
  2190.     def test_nested_abstract_base(self):
    
  2191.         A = self.create_model("A", abstract=True)
    
  2192.         B = self.create_model("B", bases=(A,), abstract=True)
    
  2193.         C = self.create_model("C", bases=(B,))
    
  2194.         self.assertRelated(A, [B, C])
    
  2195.         self.assertRelated(B, [C])
    
  2196.         self.assertRelated(C, [])
    
  2197. 
    
  2198.     def test_proxy_base(self):
    
  2199.         A = self.create_model("A")
    
  2200.         B = self.create_model("B", bases=(A,), proxy=True)
    
  2201.         self.assertRelated(A, [B])
    
  2202.         self.assertRelated(B, [])
    
  2203. 
    
  2204.     def test_nested_proxy_base(self):
    
  2205.         A = self.create_model("A")
    
  2206.         B = self.create_model("B", bases=(A,), proxy=True)
    
  2207.         C = self.create_model("C", bases=(B,), proxy=True)
    
  2208.         self.assertRelated(A, [B, C])
    
  2209.         self.assertRelated(B, [C])
    
  2210.         self.assertRelated(C, [])
    
  2211. 
    
  2212.     def test_multiple_mixed_bases(self):
    
  2213.         A = self.create_model("A", abstract=True)
    
  2214.         M = self.create_model("M")
    
  2215.         P = self.create_model("P")
    
  2216.         Q = self.create_model("Q", bases=(P,), proxy=True)
    
  2217.         Z = self.create_model("Z", bases=(A, M, Q))
    
  2218.         # M has a pointer O2O field p_ptr to P
    
  2219.         self.assertRelated(A, [M, P, Q, Z])
    
  2220.         self.assertRelated(M, [P, Q, Z])
    
  2221.         self.assertRelated(P, [M, Q, Z])
    
  2222.         self.assertRelated(Q, [M, P, Z])
    
  2223.         self.assertRelated(Z, [M, P, Q])