Removed Manager.use_for_related_fields and Meta.manager_inheritance_from_future.
Per deprecation timeline. Refs ed0ff913c6
.
This commit is contained in:
parent
60ca37d2e5
commit
631f4ab061
|
@ -1,7 +1,6 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
import copy
|
||||
import warnings
|
||||
from collections import OrderedDict
|
||||
from contextlib import contextmanager
|
||||
|
||||
|
@ -14,7 +13,6 @@ from django.db.models.fields.related import RECURSIVE_RELATIONSHIP_CONSTANT
|
|||
from django.db.models.options import DEFAULT_NAMES, normalize_together
|
||||
from django.db.models.utils import make_model_tuple
|
||||
from django.utils import six
|
||||
from django.utils.deprecation import RemovedInDjango20Warning
|
||||
from django.utils.encoding import force_text
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.module_loading import import_string
|
||||
|
@ -604,18 +602,8 @@ class ModelState(object):
|
|||
|
||||
# Restore managers
|
||||
body.update(self.construct_managers())
|
||||
|
||||
with warnings.catch_warnings():
|
||||
warnings.filterwarnings(
|
||||
"ignore", "Managers from concrete parents will soon qualify as default managers",
|
||||
RemovedInDjango20Warning)
|
||||
|
||||
# Then, make a Model object (apps.register_model is called in __new__)
|
||||
return type(
|
||||
str(self.name),
|
||||
bases,
|
||||
body,
|
||||
)
|
||||
# Then, make a Model object (apps.register_model is called in __new__)
|
||||
return type(str(self.name), bases, body)
|
||||
|
||||
def get_field_by_name(self, name):
|
||||
for fname, field in self.fields:
|
||||
|
|
|
@ -29,7 +29,6 @@ from django.db.models.signals import (
|
|||
)
|
||||
from django.db.models.utils import make_model_tuple
|
||||
from django.utils import six
|
||||
from django.utils.deprecation import RemovedInDjango20Warning
|
||||
from django.utils.encoding import (
|
||||
force_str, force_text, python_2_unicode_compatible,
|
||||
)
|
||||
|
@ -358,7 +357,7 @@ class ModelBase(type):
|
|||
if get_absolute_url_override:
|
||||
setattr(cls, 'get_absolute_url', get_absolute_url_override)
|
||||
|
||||
if not opts.managers or cls._requires_legacy_default_manager():
|
||||
if not opts.managers:
|
||||
if any(f.name == 'objects' for f in opts.fields):
|
||||
raise ValueError(
|
||||
"Model %s must specify a custom Manager, because it has a "
|
||||
|
@ -370,79 +369,6 @@ class ModelBase(type):
|
|||
|
||||
class_prepared.send(sender=cls)
|
||||
|
||||
def _requires_legacy_default_manager(cls): # RemovedInDjango20Warning
|
||||
opts = cls._meta
|
||||
|
||||
if opts.manager_inheritance_from_future:
|
||||
return False
|
||||
|
||||
future_default_manager = opts.default_manager
|
||||
|
||||
# Step 1: Locate a manager that would have been promoted
|
||||
# to default manager with the legacy system.
|
||||
for manager in opts.managers:
|
||||
originating_model = manager._originating_model
|
||||
if (cls is originating_model or cls._meta.proxy or
|
||||
originating_model._meta.abstract):
|
||||
|
||||
if manager is not cls._default_manager and not opts.default_manager_name:
|
||||
warnings.warn(
|
||||
"Managers from concrete parents will soon qualify as default "
|
||||
"managers if they appear before any other managers in the "
|
||||
"MRO. As a result, '{legacy_default_manager}' declared on "
|
||||
"'{legacy_default_manager_model}' will no longer be the "
|
||||
"default manager for '{model}' in favor of "
|
||||
"'{future_default_manager}' declared on "
|
||||
"'{future_default_manager_model}'. "
|
||||
"You can redeclare '{legacy_default_manager}' on '{cls}' "
|
||||
"to keep things the way they are or you can switch to the new "
|
||||
"behavior right away by setting "
|
||||
"`Meta.manager_inheritance_from_future` to `True`.".format(
|
||||
cls=cls.__name__,
|
||||
model=opts.label,
|
||||
legacy_default_manager=manager.name,
|
||||
legacy_default_manager_model=manager._originating_model._meta.label,
|
||||
future_default_manager=future_default_manager.name,
|
||||
future_default_manager_model=future_default_manager._originating_model._meta.label,
|
||||
),
|
||||
RemovedInDjango20Warning, 2
|
||||
)
|
||||
|
||||
opts.default_manager_name = manager.name
|
||||
opts._expire_cache()
|
||||
|
||||
break
|
||||
|
||||
# Step 2: Since there are managers but none of them qualified as
|
||||
# default managers under the legacy system (meaning that there are
|
||||
# managers from concrete parents that would be promoted under the
|
||||
# new system), we need to create a new Manager instance for the
|
||||
# 'objects' attribute as a deprecation shim.
|
||||
else:
|
||||
# If the "future" default manager was auto created there is no
|
||||
# point warning the user since it's basically the same manager.
|
||||
if not future_default_manager.auto_created:
|
||||
warnings.warn(
|
||||
"Managers from concrete parents will soon qualify as "
|
||||
"default managers. As a result, the 'objects' manager "
|
||||
"won't be created (or recreated) automatically "
|
||||
"anymore on '{model}' and '{future_default_manager}' "
|
||||
"declared on '{future_default_manager_model}' will be "
|
||||
"promoted to default manager. You can declare "
|
||||
"explicitly `objects = models.Manager()` on '{cls}' "
|
||||
"to keep things the way they are or you can switch "
|
||||
"to the new behavior right away by setting "
|
||||
"`Meta.manager_inheritance_from_future` to `True`.".format(
|
||||
cls=cls.__name__,
|
||||
model=opts.label,
|
||||
future_default_manager=future_default_manager.name,
|
||||
future_default_manager_model=future_default_manager._originating_model._meta.label,
|
||||
),
|
||||
RemovedInDjango20Warning, 2
|
||||
)
|
||||
|
||||
return True
|
||||
|
||||
@property
|
||||
def _base_manager(cls):
|
||||
return cls._meta.base_manager
|
||||
|
|
|
@ -65,13 +65,11 @@ and two directions (forward and reverse) for a total of six combinations.
|
|||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import warnings
|
||||
from operator import attrgetter
|
||||
|
||||
from django.db import connections, router, transaction
|
||||
from django.db.models import Q, signals
|
||||
from django.db.models.query import QuerySet
|
||||
from django.utils.deprecation import RemovedInDjango20Warning
|
||||
from django.utils.functional import cached_property
|
||||
|
||||
|
||||
|
@ -107,20 +105,7 @@ class ForwardManyToOneDescriptor(object):
|
|||
return hasattr(instance, self.cache_name)
|
||||
|
||||
def get_queryset(self, **hints):
|
||||
related_model = self.field.remote_field.model
|
||||
|
||||
if getattr(related_model._default_manager, 'use_for_related_fields', False):
|
||||
if not getattr(related_model._default_manager, 'silence_use_for_related_fields_deprecation', False):
|
||||
warnings.warn(
|
||||
"use_for_related_fields is deprecated, instead "
|
||||
"set Meta.base_manager_name on '{}'.".format(related_model._meta.label),
|
||||
RemovedInDjango20Warning, 2
|
||||
)
|
||||
manager = related_model._default_manager
|
||||
else:
|
||||
manager = related_model._base_manager
|
||||
|
||||
return manager.db_manager(hints=hints).all()
|
||||
return self.field.remote_field.model._base_manager.db_manager(hints=hints).all()
|
||||
|
||||
def get_prefetch_queryset(self, instances, queryset=None):
|
||||
if queryset is None:
|
||||
|
@ -323,20 +308,7 @@ class ReverseOneToOneDescriptor(object):
|
|||
return hasattr(instance, self.cache_name)
|
||||
|
||||
def get_queryset(self, **hints):
|
||||
related_model = self.related.related_model
|
||||
|
||||
if getattr(related_model._default_manager, 'use_for_related_fields', False):
|
||||
if not getattr(related_model._default_manager, 'silence_use_for_related_fields_deprecation', False):
|
||||
warnings.warn(
|
||||
"use_for_related_fields is deprecated, instead "
|
||||
"set Meta.base_manager_name on '{}'.".format(related_model._meta.label),
|
||||
RemovedInDjango20Warning, 2
|
||||
)
|
||||
manager = related_model._default_manager
|
||||
else:
|
||||
manager = related_model._base_manager
|
||||
|
||||
return manager.db_manager(hints=hints).all()
|
||||
return self.related.related_model._base_manager.db_manager(hints=hints).all()
|
||||
|
||||
def get_prefetch_queryset(self, instances, queryset=None):
|
||||
if queryset is None:
|
||||
|
|
|
@ -17,9 +17,7 @@ from django.db.models.fields.related import OneToOneField
|
|||
from django.db.models.query_utils import PathInfo
|
||||
from django.utils import six
|
||||
from django.utils.datastructures import ImmutableList, OrderedSet
|
||||
from django.utils.deprecation import (
|
||||
RemovedInDjango20Warning, RemovedInDjango21Warning,
|
||||
)
|
||||
from django.utils.deprecation import RemovedInDjango21Warning
|
||||
from django.utils.encoding import force_text, python_2_unicode_compatible
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.text import camel_case_to_spaces, format_lazy
|
||||
|
@ -41,7 +39,7 @@ DEFAULT_NAMES = (
|
|||
'auto_created', 'index_together', 'apps', 'default_permissions',
|
||||
'select_on_save', 'default_related_name', 'required_db_features',
|
||||
'required_db_vendor', 'base_manager_name', 'default_manager_name',
|
||||
'manager_inheritance_from_future', 'indexes',
|
||||
'indexes',
|
||||
)
|
||||
|
||||
|
||||
|
@ -87,7 +85,6 @@ class Options(object):
|
|||
self.local_fields = []
|
||||
self.local_many_to_many = []
|
||||
self.private_fields = []
|
||||
self.manager_inheritance_from_future = False
|
||||
self.local_managers = []
|
||||
self.base_manager_name = None
|
||||
self.default_manager_name = None
|
||||
|
@ -375,10 +372,6 @@ class Options(object):
|
|||
seen_managers.add(manager.name)
|
||||
managers.append((depth, manager.creation_counter, manager))
|
||||
|
||||
# Used for deprecation of legacy manager inheritance,
|
||||
# remove afterwards. (RemovedInDjango20Warning)
|
||||
manager._originating_model = base
|
||||
|
||||
return make_immutable_fields_list(
|
||||
"managers",
|
||||
(m[2] for m in sorted(managers)),
|
||||
|
@ -410,25 +403,6 @@ class Options(object):
|
|||
)
|
||||
)
|
||||
|
||||
# Deprecation shim for `use_for_related_fields`.
|
||||
for i, base_manager_class in enumerate(self.default_manager.__class__.mro()):
|
||||
if getattr(base_manager_class, 'use_for_related_fields', False):
|
||||
if not getattr(base_manager_class, 'silence_use_for_related_fields_deprecation', False):
|
||||
warnings.warn(
|
||||
"use_for_related_fields is deprecated, instead "
|
||||
"set Meta.base_manager_name on '{}'.".format(self.model._meta.label),
|
||||
RemovedInDjango20Warning, 2
|
||||
)
|
||||
|
||||
if i == 0:
|
||||
manager = self.default_manager
|
||||
else:
|
||||
manager = base_manager_class()
|
||||
manager.name = '_base_manager'
|
||||
manager.model = self.model
|
||||
|
||||
return manager
|
||||
|
||||
manager = Manager()
|
||||
manager.name = '_base_manager'
|
||||
manager.model = self.model
|
||||
|
|
|
@ -384,3 +384,9 @@ these features.
|
|||
removed.
|
||||
|
||||
* The ``escape`` filter now uses ``django.utils.html.conditional_escape()``.
|
||||
|
||||
* ``Manager.use_for_related_fields`` is removed.
|
||||
|
||||
* Model ``Manager`` inheritance follows MRO inheritance rules. The requirement
|
||||
to use ``Meta.manager_inheritance_from_future`` to opt-in to the behavior is
|
||||
removed.
|
||||
|
|
|
@ -118,9 +118,6 @@ class Child5(AbstractBase3):
|
|||
class Child6(Child4):
|
||||
value = models.IntegerField()
|
||||
|
||||
class Meta:
|
||||
manager_inheritance_from_future = True
|
||||
|
||||
|
||||
class Child7(Parent):
|
||||
objects = models.Manager()
|
||||
|
|
|
@ -1,13 +1,9 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
import warnings
|
||||
|
||||
from django.db import models
|
||||
from django.db.utils import DatabaseError
|
||||
from django.template import Context, Template
|
||||
from django.test import TestCase, override_settings
|
||||
from django.test.utils import isolate_apps
|
||||
from django.utils.deprecation import RemovedInDjango20Warning
|
||||
from django.utils.encoding import force_text
|
||||
|
||||
from .models import (
|
||||
|
@ -185,23 +181,20 @@ class TestManagerInheritance(TestCase):
|
|||
self.assertIsInstance(PlainModel._default_manager, CustomManager)
|
||||
|
||||
class ModelWithAbstractParent(AbstractModel):
|
||||
class Meta:
|
||||
manager_inheritance_from_future = True
|
||||
pass
|
||||
|
||||
self.assertIsInstance(ModelWithAbstractParent._base_manager, models.Manager)
|
||||
self.assertIsInstance(ModelWithAbstractParent._default_manager, CustomManager)
|
||||
|
||||
class ProxyModel(PlainModel):
|
||||
class Meta:
|
||||
manager_inheritance_from_future = True
|
||||
proxy = True
|
||||
|
||||
self.assertIsInstance(ProxyModel._base_manager, models.Manager)
|
||||
self.assertIsInstance(ProxyModel._default_manager, CustomManager)
|
||||
|
||||
class MTIModel(PlainModel):
|
||||
class Meta:
|
||||
manager_inheritance_from_future = True
|
||||
pass
|
||||
|
||||
self.assertIsInstance(MTIModel._base_manager, models.Manager)
|
||||
self.assertIsInstance(MTIModel._default_manager, CustomManager)
|
||||
|
@ -228,21 +221,18 @@ class TestManagerInheritance(TestCase):
|
|||
self.assertIsInstance(PlainModel._default_manager, CustomManager)
|
||||
|
||||
class ModelWithAbstractParent(AbstractModel):
|
||||
class Meta:
|
||||
manager_inheritance_from_future = True
|
||||
pass
|
||||
|
||||
self.assertIsInstance(ModelWithAbstractParent._default_manager, CustomManager)
|
||||
|
||||
class ProxyModel(PlainModel):
|
||||
class Meta:
|
||||
manager_inheritance_from_future = True
|
||||
proxy = True
|
||||
|
||||
self.assertIsInstance(ProxyModel._default_manager, CustomManager)
|
||||
|
||||
class MTIModel(PlainModel):
|
||||
class Meta:
|
||||
manager_inheritance_from_future = True
|
||||
pass
|
||||
|
||||
self.assertIsInstance(MTIModel._default_manager, CustomManager)
|
||||
|
||||
|
@ -268,21 +258,18 @@ class TestManagerInheritance(TestCase):
|
|||
self.assertIsInstance(PlainModel._base_manager, CustomManager)
|
||||
|
||||
class ModelWithAbstractParent(AbstractModel):
|
||||
class Meta:
|
||||
manager_inheritance_from_future = True
|
||||
pass
|
||||
|
||||
self.assertIsInstance(ModelWithAbstractParent._base_manager, CustomManager)
|
||||
|
||||
class ProxyModel(PlainModel):
|
||||
class Meta:
|
||||
manager_inheritance_from_future = True
|
||||
proxy = True
|
||||
|
||||
self.assertIsInstance(ProxyModel._base_manager, CustomManager)
|
||||
|
||||
class MTIModel(PlainModel):
|
||||
class Meta:
|
||||
manager_inheritance_from_future = True
|
||||
pass
|
||||
|
||||
self.assertIsInstance(MTIModel._base_manager, CustomManager)
|
||||
|
||||
|
@ -301,342 +288,3 @@ class TestManagerInheritance(TestCase):
|
|||
|
||||
self.assertEqual(TestModel._meta.managers, (TestModel.custom_manager,))
|
||||
self.assertEqual(TestModel._meta.managers_map, {'custom_manager': TestModel.custom_manager})
|
||||
|
||||
|
||||
@isolate_apps('managers_regress')
|
||||
class TestManagerDeprecations(TestCase):
|
||||
|
||||
def test_use_for_related_fields_for_base_manager(self):
|
||||
class MyManager(models.Manager):
|
||||
use_for_related_fields = True
|
||||
|
||||
class MyModel(models.Model):
|
||||
objects = MyManager()
|
||||
|
||||
with warnings.catch_warnings(record=True) as warns:
|
||||
warnings.simplefilter('always', RemovedInDjango20Warning)
|
||||
MyModel._base_manager
|
||||
self.assertEqual(len(warns), 1)
|
||||
self.assertEqual(
|
||||
str(warns[0].message),
|
||||
"use_for_related_fields is deprecated, "
|
||||
"instead set Meta.base_manager_name on "
|
||||
"'managers_regress.MyModel'.",
|
||||
)
|
||||
|
||||
# With the new base_manager_name API there shouldn't be any warnings.
|
||||
class MyModel2(models.Model):
|
||||
objects = MyManager()
|
||||
|
||||
class Meta:
|
||||
base_manager_name = 'objects'
|
||||
|
||||
with warnings.catch_warnings(record=True) as warns:
|
||||
warnings.simplefilter('always', RemovedInDjango20Warning)
|
||||
MyModel2._base_manager
|
||||
self.assertEqual(len(warns), 0)
|
||||
|
||||
def test_use_for_related_fields_for_many_to_one(self):
|
||||
# Common objects
|
||||
class MyManagerQuerySet(models.QuerySet):
|
||||
pass
|
||||
|
||||
class MyLegacyManagerQuerySet(models.QuerySet):
|
||||
pass
|
||||
|
||||
class MyManager(models.Manager):
|
||||
def get_queryset(self):
|
||||
return MyManagerQuerySet(model=self.model, using=self._db, hints=self._hints)
|
||||
|
||||
class MyLegacyManager(models.Manager):
|
||||
use_for_related_fields = True
|
||||
|
||||
def get_queryset(self):
|
||||
return MyLegacyManagerQuerySet(model=self.model, using=self._db, hints=self._hints)
|
||||
|
||||
# With legacy config there should be a deprecation warning
|
||||
class MyRelModel(models.Model):
|
||||
objects = MyLegacyManager()
|
||||
|
||||
class MyModel(models.Model):
|
||||
fk = models.ForeignKey(MyRelModel, on_delete=models.DO_NOTHING)
|
||||
|
||||
with warnings.catch_warnings(record=True) as warns:
|
||||
warnings.simplefilter('always', RemovedInDjango20Warning)
|
||||
try:
|
||||
MyModel(fk_id=42).fk
|
||||
except DatabaseError:
|
||||
pass
|
||||
self.assertEqual(len(warns), 1)
|
||||
self.assertEqual(
|
||||
str(warns[0].message),
|
||||
"use_for_related_fields is deprecated, "
|
||||
"instead set Meta.base_manager_name on "
|
||||
"'managers_regress.MyRelModel'.",
|
||||
)
|
||||
|
||||
# With the new base_manager_name API there shouldn't be any warnings.
|
||||
class MyRelModel2(models.Model):
|
||||
objects = MyManager()
|
||||
|
||||
class Meta:
|
||||
base_manager_name = 'objects'
|
||||
|
||||
class MyModel2(models.Model):
|
||||
fk = models.ForeignKey(MyRelModel2, on_delete=models.DO_NOTHING)
|
||||
|
||||
with warnings.catch_warnings(record=True) as warns:
|
||||
warnings.simplefilter('always', RemovedInDjango20Warning)
|
||||
try:
|
||||
MyModel2(fk_id=42).fk
|
||||
except DatabaseError:
|
||||
pass
|
||||
self.assertEqual(len(warns), 0)
|
||||
|
||||
# When mixing base_manager_name and use_for_related_fields, there
|
||||
# should be warnings.
|
||||
class MyRelModel3(models.Model):
|
||||
my_base_manager = MyManager()
|
||||
my_default_manager = MyLegacyManager()
|
||||
|
||||
class Meta:
|
||||
base_manager_name = 'my_base_manager'
|
||||
default_manager_name = 'my_default_manager'
|
||||
|
||||
class MyModel3(models.Model):
|
||||
fk = models.ForeignKey(MyRelModel3, on_delete=models.DO_NOTHING)
|
||||
|
||||
with warnings.catch_warnings(record=True) as warns:
|
||||
warnings.simplefilter('always', RemovedInDjango20Warning)
|
||||
try:
|
||||
MyModel3(fk_id=42).fk
|
||||
except DatabaseError:
|
||||
pass
|
||||
self.assertEqual(len(warns), 1)
|
||||
self.assertEqual(
|
||||
str(warns[0].message),
|
||||
"use_for_related_fields is deprecated, "
|
||||
"instead set Meta.base_manager_name on "
|
||||
"'managers_regress.MyRelModel3'.",
|
||||
)
|
||||
with warnings.catch_warnings(record=True):
|
||||
warnings.simplefilter('always', RemovedInDjango20Warning)
|
||||
self.assertIsInstance(MyModel3.fk.get_queryset(), MyLegacyManagerQuerySet)
|
||||
|
||||
def test_use_for_related_fields_for_one_to_one(self):
|
||||
# Common objects
|
||||
class MyManagerQuerySet(models.QuerySet):
|
||||
pass
|
||||
|
||||
class MyLegacyManagerQuerySet(models.QuerySet):
|
||||
pass
|
||||
|
||||
class MyManager(models.Manager):
|
||||
def get_queryset(self):
|
||||
return MyManagerQuerySet(model=self.model, using=self._db, hints=self._hints)
|
||||
|
||||
class MyLegacyManager(models.Manager):
|
||||
use_for_related_fields = True
|
||||
|
||||
def get_queryset(self):
|
||||
return MyLegacyManagerQuerySet(model=self.model, using=self._db, hints=self._hints)
|
||||
|
||||
# With legacy config there should be a deprecation warning
|
||||
class MyRelModel(models.Model):
|
||||
objects = MyLegacyManager()
|
||||
|
||||
class MyModel(models.Model):
|
||||
o2o = models.OneToOneField(MyRelModel, on_delete=models.DO_NOTHING)
|
||||
objects = MyLegacyManager()
|
||||
|
||||
with warnings.catch_warnings(record=True) as warns:
|
||||
warnings.simplefilter('always', RemovedInDjango20Warning)
|
||||
try:
|
||||
MyModel(o2o_id=42).o2o
|
||||
except DatabaseError:
|
||||
pass
|
||||
self.assertEqual(len(warns), 1)
|
||||
self.assertEqual(
|
||||
str(warns[0].message),
|
||||
"use_for_related_fields is deprecated, "
|
||||
"instead set Meta.base_manager_name on "
|
||||
"'managers_regress.MyRelModel'.",
|
||||
)
|
||||
|
||||
with warnings.catch_warnings(record=True) as warns:
|
||||
warnings.simplefilter('always', RemovedInDjango20Warning)
|
||||
try:
|
||||
MyRelModel(pk=42).mymodel
|
||||
except DatabaseError:
|
||||
pass
|
||||
self.assertEqual(len(warns), 1)
|
||||
self.assertEqual(
|
||||
str(warns[0].message),
|
||||
"use_for_related_fields is deprecated, "
|
||||
"instead set Meta.base_manager_name on "
|
||||
"'managers_regress.MyModel'.",
|
||||
)
|
||||
|
||||
# With the new base_manager_name API there shouldn't be any warnings.
|
||||
class MyRelModel2(models.Model):
|
||||
objects = MyManager()
|
||||
|
||||
class Meta:
|
||||
base_manager_name = 'objects'
|
||||
|
||||
class MyModel2(models.Model):
|
||||
o2o = models.OneToOneField(MyRelModel2, on_delete=models.DO_NOTHING)
|
||||
objects = MyManager()
|
||||
|
||||
class Meta:
|
||||
base_manager_name = 'objects'
|
||||
|
||||
with warnings.catch_warnings(record=True) as warns:
|
||||
warnings.simplefilter('always', RemovedInDjango20Warning)
|
||||
try:
|
||||
MyModel2(o2o_id=42).o2o
|
||||
except DatabaseError:
|
||||
pass
|
||||
try:
|
||||
MyRelModel2(pk=42).mymodel2
|
||||
except DatabaseError:
|
||||
pass
|
||||
self.assertEqual(len(warns), 0)
|
||||
|
||||
# When mixing base_manager_name and use_for_related_fields, there
|
||||
# should be warnings.
|
||||
class MyRelModel3(models.Model):
|
||||
my_base_manager = MyManager()
|
||||
my_default_manager = MyLegacyManager()
|
||||
|
||||
class Meta:
|
||||
base_manager_name = 'my_base_manager'
|
||||
default_manager_name = 'my_default_manager'
|
||||
|
||||
class MyModel3(models.Model):
|
||||
o2o = models.OneToOneField(MyRelModel3, on_delete=models.DO_NOTHING)
|
||||
|
||||
with warnings.catch_warnings(record=True) as warns:
|
||||
warnings.simplefilter('always', RemovedInDjango20Warning)
|
||||
try:
|
||||
MyModel3(o2o_id=42).o2o
|
||||
except DatabaseError:
|
||||
pass
|
||||
|
||||
self.assertEqual(len(warns), 1)
|
||||
self.assertEqual(
|
||||
str(warns[0].message),
|
||||
"use_for_related_fields is deprecated, "
|
||||
"instead set Meta.base_manager_name on "
|
||||
"'managers_regress.MyRelModel3'.",
|
||||
)
|
||||
with warnings.catch_warnings(record=True):
|
||||
warnings.simplefilter('always', RemovedInDjango20Warning)
|
||||
self.assertIsInstance(MyModel3.o2o.get_queryset(), MyLegacyManagerQuerySet)
|
||||
|
||||
def test_legacy_objects_is_created(self):
|
||||
class ConcreteParentWithoutManager(models.Model):
|
||||
pass
|
||||
|
||||
class ConcreteParentWithManager(models.Model):
|
||||
default = models.Manager()
|
||||
|
||||
class AbstractParent(models.Model):
|
||||
default = models.Manager()
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
# Shouldn't complain since the inherited manager
|
||||
# is basically the same that would have been created.
|
||||
with warnings.catch_warnings(record=True) as warns:
|
||||
warnings.simplefilter('always', RemovedInDjango20Warning)
|
||||
|
||||
class MyModel(ConcreteParentWithoutManager):
|
||||
pass
|
||||
self.assertEqual(len(warns), 0)
|
||||
|
||||
# Should create 'objects' (set as default) and warn that
|
||||
# it will no longer be the case in the future.
|
||||
with warnings.catch_warnings(record=True) as warns:
|
||||
warnings.simplefilter('always', RemovedInDjango20Warning)
|
||||
|
||||
class MyModel2(ConcreteParentWithManager):
|
||||
pass
|
||||
self.assertEqual(len(warns), 1)
|
||||
self.assertEqual(
|
||||
str(warns[0].message),
|
||||
"Managers from concrete parents will soon qualify as default "
|
||||
"managers. As a result, the 'objects' manager won't be created "
|
||||
"(or recreated) automatically anymore on "
|
||||
"'managers_regress.MyModel2' and 'default' declared on "
|
||||
"'managers_regress.ConcreteParentWithManager' will be promoted "
|
||||
"to default manager. You can declare explicitly "
|
||||
"`objects = models.Manager()` on 'MyModel2' to keep things the "
|
||||
"way they are or you can switch to the new behavior right away "
|
||||
"by setting `Meta.manager_inheritance_from_future` to `True`.",
|
||||
)
|
||||
|
||||
self.assertIs(MyModel2.objects, MyModel2._default_manager)
|
||||
|
||||
# When there is a local manager we shouldn't get any warning
|
||||
# and 'objects' shouldn't be created.
|
||||
class MyModel3(ConcreteParentWithManager):
|
||||
default = models.Manager()
|
||||
self.assertIs(MyModel3.default, MyModel3._default_manager)
|
||||
self.assertIsNone(getattr(MyModel3, 'objects', None))
|
||||
|
||||
# When there is an inherited manager we shouldn't get any warning
|
||||
# and 'objects' shouldn't be created.
|
||||
class MyModel4(AbstractParent, ConcreteParentWithManager):
|
||||
pass
|
||||
self.assertIs(MyModel4.default, MyModel4._default_manager)
|
||||
self.assertIsNone(getattr(MyModel4, 'objects', None))
|
||||
|
||||
# With `manager_inheritance_from_future = True` 'objects'
|
||||
# shouldn't be created.
|
||||
class MyModel5(ConcreteParentWithManager):
|
||||
class Meta:
|
||||
manager_inheritance_from_future = True
|
||||
self.assertIs(MyModel5.default, MyModel5._default_manager)
|
||||
self.assertIsNone(getattr(MyModel5, 'objects', None))
|
||||
|
||||
def test_legacy_default_manager_promotion(self):
|
||||
class ConcreteParent(models.Model):
|
||||
concrete = models.Manager()
|
||||
|
||||
class AbstractParent(models.Model):
|
||||
abstract = models.Manager()
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
with warnings.catch_warnings(record=True) as warns:
|
||||
warnings.simplefilter('always', RemovedInDjango20Warning)
|
||||
|
||||
class MyModel(ConcreteParent, AbstractParent):
|
||||
pass
|
||||
self.assertEqual(len(warns), 1)
|
||||
self.assertEqual(
|
||||
str(warns[0].message),
|
||||
"Managers from concrete parents will soon qualify as default "
|
||||
"managers if they appear before any other managers in the "
|
||||
"MRO. As a result, 'abstract' declared on "
|
||||
"'managers_regress.AbstractParent' will no longer be the "
|
||||
"default manager for 'managers_regress.MyModel' in favor of "
|
||||
"'concrete' declared on 'managers_regress.ConcreteParent'. "
|
||||
"You can redeclare 'abstract' on 'MyModel' to keep things the "
|
||||
"way they are or you can switch to the new behavior right "
|
||||
"away by setting `Meta.manager_inheritance_from_future` to "
|
||||
"`True`.",
|
||||
)
|
||||
self.assertIs(MyModel.abstract, MyModel._default_manager)
|
||||
|
||||
class MyModel2(ConcreteParent, AbstractParent):
|
||||
abstract = models.Manager()
|
||||
self.assertIs(MyModel2.abstract, MyModel2._default_manager)
|
||||
|
||||
class MyModel3(ConcreteParent, AbstractParent):
|
||||
class Meta:
|
||||
manager_inheritance_from_future = True
|
||||
self.assertIs(MyModel3.concrete, MyModel3._default_manager)
|
||||
|
|
|
@ -4,8 +4,7 @@ from copy import deepcopy
|
|||
from django.core.exceptions import FieldError, MultipleObjectsReturned
|
||||
from django.db import models, transaction
|
||||
from django.db.utils import IntegrityError
|
||||
from django.test import TestCase, ignore_warnings
|
||||
from django.utils.deprecation import RemovedInDjango20Warning
|
||||
from django.test import TestCase
|
||||
from django.utils.translation import ugettext_lazy
|
||||
|
||||
from .models import (
|
||||
|
@ -577,7 +576,6 @@ class ManyToOneTests(TestCase):
|
|||
with self.assertNumQueries(1):
|
||||
self.assertEqual(th.child_set.count(), 0)
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango20Warning) # for use_for_related_fields deprecation
|
||||
def test_related_object(self):
|
||||
public_school = School.objects.create(is_public=True)
|
||||
public_student = Student.objects.create(school=public_school)
|
||||
|
@ -595,17 +593,6 @@ class ManyToOneTests(TestCase):
|
|||
# allow it.
|
||||
self.assertEqual(private_student.school, private_school)
|
||||
|
||||
# If the manager is marked "use_for_related_fields", it'll get used instead
|
||||
# of the "bare" queryset. Usually you'd define this as a property on the class,
|
||||
# but this approximates that in a way that's easier in tests.
|
||||
School._default_manager.use_for_related_fields = True
|
||||
try:
|
||||
private_student = Student.objects.get(pk=private_student.pk)
|
||||
with self.assertRaises(School.DoesNotExist):
|
||||
private_student.school
|
||||
finally:
|
||||
School._default_manager.use_for_related_fields = False
|
||||
|
||||
School._meta.base_manager_name = 'objects'
|
||||
School._meta._expire_cache()
|
||||
try:
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import IntegrityError, connection, transaction
|
||||
from django.test import TestCase, ignore_warnings
|
||||
from django.utils.deprecation import RemovedInDjango20Warning
|
||||
from django.test import TestCase
|
||||
|
||||
from .models import (
|
||||
Bar, Director, Favorites, HiddenPointer, ManualPrimaryKey, MultiModel,
|
||||
|
@ -419,7 +418,6 @@ class OneToOneTests(TestCase):
|
|||
hasattr(Target, HiddenPointer._meta.get_field('target').remote_field.get_accessor_name())
|
||||
)
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango20Warning) # for use_for_related_fields deprecation
|
||||
def test_related_object(self):
|
||||
public_school = School.objects.create(is_public=True)
|
||||
public_director = Director.objects.create(school=public_school, is_temp=False)
|
||||
|
@ -452,25 +450,6 @@ class OneToOneTests(TestCase):
|
|||
# allow it.
|
||||
self.assertEqual(private_school.director, private_director)
|
||||
|
||||
# If the manager is marked "use_for_related_fields", it'll get used instead
|
||||
# of the "bare" queryset. Usually you'd define this as a property on the class,
|
||||
# but this approximates that in a way that's easier in tests.
|
||||
School._default_manager.use_for_related_fields = True
|
||||
try:
|
||||
private_director = Director._base_manager.get(pk=private_director.pk)
|
||||
with self.assertRaises(School.DoesNotExist):
|
||||
private_director.school
|
||||
finally:
|
||||
School._default_manager.use_for_related_fields = False
|
||||
|
||||
Director._default_manager.use_for_related_fields = True
|
||||
try:
|
||||
private_school = School._base_manager.get(pk=private_school.pk)
|
||||
with self.assertRaises(Director.DoesNotExist):
|
||||
private_school.director
|
||||
finally:
|
||||
Director._default_manager.use_for_related_fields = False
|
||||
|
||||
School._meta.base_manager_name = 'objects'
|
||||
School._meta._expire_cache()
|
||||
try:
|
||||
|
|
|
@ -17,6 +17,3 @@ class Parent(models.Model):
|
|||
|
||||
class Child(Parent):
|
||||
child_data = models.CharField(max_length=30, unique=True)
|
||||
|
||||
class Meta:
|
||||
manager_inheritance_from_future = True
|
||||
|
|
Loading…
Reference in New Issue