mirror of
https://github.com/django/django.git
synced 2025-10-23 21:59:11 +00:00
Fixed #23822 -- Added support for serializing model managers in migration
Thanks to Shai Berger, Loïc Bistuer, Simon Charette, Andrew Godwin, Tim Graham, Carl Meyer, and others for their review and input.
This commit is contained in:
committed by
Tim Graham
parent
e37ab311fc
commit
aa5ef0d4fc
@@ -3,7 +3,8 @@ from django.db import models
|
||||
from django.db.migrations.state import ProjectState, ModelState, InvalidBasesError
|
||||
from django.test import TestCase
|
||||
|
||||
from .models import ModelWithCustomBase
|
||||
from .models import (FoodManager, FoodQuerySet, ModelWithCustomBase,
|
||||
NoMigrationFoodManager)
|
||||
|
||||
|
||||
class StateTests(TestCase):
|
||||
@@ -54,11 +55,56 @@ class StateTests(TestCase):
|
||||
verbose_name = "tome"
|
||||
db_table = "test_tome"
|
||||
|
||||
class Food(models.Model):
|
||||
|
||||
food_mgr = FoodManager('a', 'b')
|
||||
food_qs = FoodQuerySet.as_manager()
|
||||
food_no_mgr = NoMigrationFoodManager('x', 'y')
|
||||
|
||||
class Meta:
|
||||
app_label = "migrations"
|
||||
apps = new_apps
|
||||
|
||||
class FoodNoManagers(models.Model):
|
||||
|
||||
class Meta:
|
||||
app_label = "migrations"
|
||||
apps = new_apps
|
||||
|
||||
class FoodNoDefaultManager(models.Model):
|
||||
|
||||
food_no_mgr = NoMigrationFoodManager('x', 'y')
|
||||
food_mgr = FoodManager('a', 'b')
|
||||
food_qs = FoodQuerySet.as_manager()
|
||||
|
||||
class Meta:
|
||||
app_label = "migrations"
|
||||
apps = new_apps
|
||||
|
||||
mgr1 = FoodManager('a', 'b')
|
||||
mgr2 = FoodManager('x', 'y', c=3, d=4)
|
||||
|
||||
class FoodOrderedManagers(models.Model):
|
||||
# The managers on this model should be orderd by their creation
|
||||
# counter and not by the order in model body
|
||||
|
||||
food_no_mgr = NoMigrationFoodManager('x', 'y')
|
||||
food_mgr2 = mgr2
|
||||
food_mgr1 = mgr1
|
||||
|
||||
class Meta:
|
||||
app_label = "migrations"
|
||||
apps = new_apps
|
||||
|
||||
project_state = ProjectState.from_apps(new_apps)
|
||||
author_state = project_state.models['migrations', 'author']
|
||||
author_proxy_state = project_state.models['migrations', 'authorproxy']
|
||||
sub_author_state = project_state.models['migrations', 'subauthor']
|
||||
book_state = project_state.models['migrations', 'book']
|
||||
food_state = project_state.models['migrations', 'food']
|
||||
food_no_managers_state = project_state.models['migrations', 'foodnomanagers']
|
||||
food_no_default_manager_state = project_state.models['migrations', 'foodnodefaultmanager']
|
||||
food_order_manager_state = project_state.models['migrations', 'foodorderedmanagers']
|
||||
|
||||
self.assertEqual(author_state.app_label, "migrations")
|
||||
self.assertEqual(author_state.name, "Author")
|
||||
@@ -89,26 +135,43 @@ class StateTests(TestCase):
|
||||
self.assertEqual(len(sub_author_state.fields), 2)
|
||||
self.assertEqual(sub_author_state.bases, ("migrations.author", ))
|
||||
|
||||
# The default manager is used in migrations
|
||||
self.assertEqual([name for name, mgr in food_state.managers], ['food_mgr'])
|
||||
self.assertEqual(food_state.managers[0][1].args, ('a', 'b', 1, 2))
|
||||
|
||||
# No explicit managers defined. Migrations will fall back to the default
|
||||
self.assertEqual(food_no_managers_state.managers, [])
|
||||
|
||||
# food_mgr is used in migration but isn't the default mgr, hence add the
|
||||
# default
|
||||
self.assertEqual([name for name, mgr in food_no_default_manager_state.managers],
|
||||
['food_no_mgr', 'food_mgr'])
|
||||
self.assertEqual(food_no_default_manager_state.managers[0][1].__class__, models.Manager)
|
||||
self.assertIsInstance(food_no_default_manager_state.managers[1][1], FoodManager)
|
||||
|
||||
self.assertEqual([name for name, mgr in food_order_manager_state.managers],
|
||||
['food_mgr1', 'food_mgr2'])
|
||||
self.assertEqual([mgr.args for name, mgr in food_order_manager_state.managers],
|
||||
[('a', 'b', 1, 2), ('x', 'y', 3, 4)])
|
||||
|
||||
def test_render(self):
|
||||
"""
|
||||
Tests rendering a ProjectState into an Apps.
|
||||
"""
|
||||
project_state = ProjectState()
|
||||
project_state.add_model_state(ModelState(
|
||||
"migrations",
|
||||
"Tag",
|
||||
[
|
||||
app_label="migrations",
|
||||
name="Tag",
|
||||
fields=[
|
||||
("id", models.AutoField(primary_key=True)),
|
||||
("name", models.CharField(max_length=100)),
|
||||
("hidden", models.BooleanField()),
|
||||
],
|
||||
{},
|
||||
None,
|
||||
))
|
||||
project_state.add_model_state(ModelState(
|
||||
"migrations",
|
||||
"SubTag",
|
||||
[
|
||||
app_label="migrations",
|
||||
name="SubTag",
|
||||
fields=[
|
||||
('tag_ptr', models.OneToOneField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
@@ -118,15 +181,40 @@ class StateTests(TestCase):
|
||||
)),
|
||||
("awesome", models.BooleanField()),
|
||||
],
|
||||
options={},
|
||||
bases=("migrations.Tag",),
|
||||
))
|
||||
|
||||
base_mgr = models.Manager()
|
||||
mgr1 = FoodManager('a', 'b')
|
||||
mgr2 = FoodManager('x', 'y', c=3, d=4)
|
||||
project_state.add_model_state(ModelState(
|
||||
app_label="migrations",
|
||||
name="Food",
|
||||
fields=[
|
||||
("id", models.AutoField(primary_key=True)),
|
||||
],
|
||||
managers=[
|
||||
# The ordering we really want is objects, mgr1, mgr2
|
||||
('default', base_mgr),
|
||||
('food_mgr2', mgr2),
|
||||
('food_mgr1', mgr1),
|
||||
]
|
||||
))
|
||||
|
||||
new_apps = project_state.render()
|
||||
self.assertEqual(new_apps.get_model("migrations", "Tag")._meta.get_field_by_name("name")[0].max_length, 100)
|
||||
self.assertEqual(new_apps.get_model("migrations", "Tag")._meta.get_field_by_name("hidden")[0].null, False)
|
||||
|
||||
self.assertEqual(len(new_apps.get_model("migrations", "SubTag")._meta.local_fields), 2)
|
||||
|
||||
Food = new_apps.get_model("migrations", "Food")
|
||||
managers = sorted(Food._meta.managers)
|
||||
self.assertEqual([mgr.name for _, mgr, _ in managers],
|
||||
['default', 'food_mgr1', 'food_mgr2'])
|
||||
self.assertEqual([mgr.__class__ for _, mgr, _ in managers],
|
||||
[models.Manager, FoodManager, FoodManager])
|
||||
self.assertIs(managers[0][1], Food._default_manager)
|
||||
|
||||
def test_render_model_inheritance(self):
|
||||
class Book(models.Model):
|
||||
title = models.CharField(max_length=1000)
|
||||
|
||||
Reference in New Issue
Block a user