[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:
Markus Holtermann 2015-04-25 03:08:23 +02:00
parent fc342bff94
commit 419f296259
3 changed files with 16 additions and 6 deletions

View File

@ -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)

View File

@ -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
=============

View File

@ -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)