[1.8.x] Fixed #24701 -- Converted model manager names to unicode in migrations
Thanks to Reto Aebersold for reporting the issue and Tim Graham and
Claude Paroz for the review.
Backport of faad6070ee
from master
This commit is contained in:
parent
fc342bff94
commit
419f296259
|
@ -419,7 +419,7 @@ class ModelState(object):
|
|||
bases = (models.Model,)
|
||||
|
||||
# Constructs all managers on the model
|
||||
managers = {}
|
||||
managers_mapping = {}
|
||||
|
||||
def reconstruct_manager(mgr):
|
||||
as_manager, manager_path, qs_path, args, kwargs = mgr.deconstruct()
|
||||
|
@ -431,16 +431,17 @@ class ModelState(object):
|
|||
instance = manager_class(*args, **kwargs)
|
||||
# We rely on the ordering of the creation_counter of the original
|
||||
# instance
|
||||
managers[mgr.name] = (mgr.creation_counter, instance)
|
||||
name = force_text(mgr.name)
|
||||
managers_mapping[name] = (mgr.creation_counter, instance)
|
||||
|
||||
if hasattr(model, "_default_manager"):
|
||||
default_manager_name = model._default_manager.name
|
||||
default_manager_name = force_text(model._default_manager.name)
|
||||
# Make sure the default manager is always the first
|
||||
if model._default_manager.use_in_migrations:
|
||||
reconstruct_manager(model._default_manager)
|
||||
else:
|
||||
# Force this manager to be the first and thus default
|
||||
managers[default_manager_name] = (0, models.Manager())
|
||||
managers_mapping[default_manager_name] = (0, models.Manager())
|
||||
# Sort all managers by their creation counter
|
||||
for _, manager, _ in sorted(model._meta.managers):
|
||||
if manager.name == "_base_manager" or not manager.use_in_migrations:
|
||||
|
@ -450,7 +451,7 @@ class ModelState(object):
|
|||
# instance for further processing
|
||||
managers = [
|
||||
(name, instance) for name, (cc, instance) in
|
||||
sorted(managers.items(), key=lambda v: v[1])
|
||||
sorted(managers_mapping.items(), key=lambda v: v[1])
|
||||
]
|
||||
if managers == [(default_manager_name, models.Manager())]:
|
||||
managers = []
|
||||
|
@ -496,6 +497,7 @@ class ModelState(object):
|
|||
# Sort all managers by their creation counter
|
||||
sorted_managers = sorted(self.managers, key=lambda v: v[1].creation_counter)
|
||||
for mgr_name, manager in sorted_managers:
|
||||
mgr_name = force_text(mgr_name)
|
||||
as_manager, manager_path, qs_path, args, kwargs = manager.deconstruct()
|
||||
if as_manager:
|
||||
qs_class = import_string(qs_path)
|
||||
|
|
|
@ -66,6 +66,9 @@ Bugfixes
|
|||
* Fixed a migration crash when adding new relations to models
|
||||
(:ticket:`24573`).
|
||||
|
||||
* Fixed a migration crash when applying migrations with model managers on
|
||||
Python 3 that were generated on Python 2 (:ticket:`24701`).
|
||||
|
||||
Optimizations
|
||||
=============
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ from django.db.migrations.state import (
|
|||
InvalidBasesError, ModelState, ProjectState, get_related_models_recursive,
|
||||
)
|
||||
from django.test import SimpleTestCase, TestCase, override_settings
|
||||
from django.utils import six
|
||||
|
||||
from .models import (
|
||||
FoodManager, FoodQuerySet, ModelWithCustomBase, NoMigrationFoodManager,
|
||||
|
@ -143,6 +144,7 @@ class StateTests(TestCase):
|
|||
|
||||
# The default manager is used in migrations
|
||||
self.assertEqual([name for name, mgr in food_state.managers], ['food_mgr'])
|
||||
self.assertTrue(all(isinstance(name, six.text_type) for name, mgr in food_state.managers))
|
||||
self.assertEqual(food_state.managers[0][1].args, ('a', 'b', 1, 2))
|
||||
|
||||
# No explicit managers defined. Migrations will fall back to the default
|
||||
|
@ -152,11 +154,13 @@ class StateTests(TestCase):
|
|||
# default
|
||||
self.assertEqual([name for name, mgr in food_no_default_manager_state.managers],
|
||||
['food_no_mgr', 'food_mgr'])
|
||||
self.assertTrue(all(isinstance(name, six.text_type) for name, mgr in food_no_default_manager_state.managers))
|
||||
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.assertTrue(all(isinstance(name, six.text_type) for name, mgr in food_order_manager_state.managers))
|
||||
self.assertEqual([mgr.args for name, mgr in food_order_manager_state.managers],
|
||||
[('a', 'b', 1, 2), ('x', 'y', 3, 4)])
|
||||
|
||||
|
@ -203,7 +207,7 @@ class StateTests(TestCase):
|
|||
# The ordering we really want is objects, mgr1, mgr2
|
||||
('default', base_mgr),
|
||||
('food_mgr2', mgr2),
|
||||
('food_mgr1', mgr1),
|
||||
(b'food_mgr1', mgr1),
|
||||
]
|
||||
))
|
||||
|
||||
|
@ -217,6 +221,7 @@ class StateTests(TestCase):
|
|||
managers = sorted(Food._meta.managers)
|
||||
self.assertEqual([mgr.name for _, mgr, _ in managers],
|
||||
['default', 'food_mgr1', 'food_mgr2'])
|
||||
self.assertTrue(all(isinstance(mgr.name, six.text_type) for _, mgr, _ in managers))
|
||||
self.assertEqual([mgr.__class__ for _, mgr, _ in managers],
|
||||
[models.Manager, FoodManager, FoodManager])
|
||||
self.assertIs(managers[0][1], Food._default_manager)
|
||||
|
|
Loading…
Reference in New Issue