Refs #25550 -- Removed support for direct assignment to the reverse side of a related set.
This commit is contained in:
parent
e0910dcc92
commit
ed251246cc
|
@ -510,28 +510,16 @@ class ReverseManyToOneDescriptor(object):
|
|||
return self.related_manager_cls(instance)
|
||||
|
||||
def _get_set_deprecation_msg_params(self):
|
||||
return ( # RemovedInDjango20Warning
|
||||
return (
|
||||
'reverse side of a related set',
|
||||
self.rel.get_accessor_name(),
|
||||
)
|
||||
|
||||
def __set__(self, instance, value):
|
||||
"""
|
||||
Set the related objects through the reverse relation.
|
||||
|
||||
With the example above, when setting ``parent.children = children``:
|
||||
|
||||
- ``self`` is the descriptor managing the ``children`` attribute
|
||||
- ``instance`` is the ``parent`` instance
|
||||
- ``value`` is the ``children`` sequence on the right of the equal sign
|
||||
"""
|
||||
warnings.warn(
|
||||
'Direct assignment to the %s is deprecated due to the implicit '
|
||||
'save() that happens. Use %s.set() instead.' % self._get_set_deprecation_msg_params(),
|
||||
RemovedInDjango20Warning, stacklevel=2,
|
||||
raise TypeError(
|
||||
'Direct assignment to the %s is prohibited. Use %s.set() instead.'
|
||||
% self._get_set_deprecation_msg_params(),
|
||||
)
|
||||
manager = self.__get__(instance)
|
||||
manager.set(value)
|
||||
|
||||
|
||||
def create_reverse_many_to_one_manager(superclass, rel):
|
||||
|
@ -772,7 +760,7 @@ class ManyToManyDescriptor(ReverseManyToOneDescriptor):
|
|||
)
|
||||
|
||||
def _get_set_deprecation_msg_params(self):
|
||||
return ( # RemovedInDjango20Warning
|
||||
return (
|
||||
'%s side of a many-to-many set' % ('reverse' if self.reverse else 'forward'),
|
||||
self.rel.get_accessor_name() if self.reverse else self.field.name,
|
||||
)
|
||||
|
|
|
@ -177,26 +177,3 @@ Related objects reference
|
|||
.. versionchanged:: 1.11
|
||||
|
||||
The clearing of the prefetched cache described above was added.
|
||||
|
||||
Direct Assignment
|
||||
=================
|
||||
|
||||
A related object set can be replaced in bulk with one operation by assigning a
|
||||
new iterable of objects to it::
|
||||
|
||||
>>> new_list = [obj1, obj2, obj3]
|
||||
>>> e.related_set = new_list
|
||||
|
||||
If the foreign key relationship has ``null=True``, then the related manager
|
||||
will first disassociate any existing objects in the related set before adding
|
||||
the contents of ``new_list``. Otherwise the objects in ``new_list`` will be
|
||||
added to the existing related object set.
|
||||
|
||||
.. deprecated:: 1.10
|
||||
|
||||
Direct assignment is deprecated in favor of the
|
||||
:meth:`~django.db.models.fields.related.RelatedManager.set` method::
|
||||
|
||||
>>> e.related_set.set([obj1, obj2, obj3])
|
||||
|
||||
This prevents confusion about an assignment resulting in an implicit save.
|
||||
|
|
|
@ -321,3 +321,6 @@ these features.
|
|||
``django.template.base.Origin`` are removed.
|
||||
|
||||
* The ``makemigrations --exit`` option is removed.
|
||||
|
||||
* Support for direct assignment to a reverse foreign key or many-to-many
|
||||
relation is removed.
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import transaction
|
||||
from django.test import TestCase, ignore_warnings
|
||||
from django.utils.deprecation import RemovedInDjango20Warning
|
||||
from django.test import TestCase
|
||||
|
||||
from .models import Article, InheritedArticleA, InheritedArticleB, Publication
|
||||
|
||||
|
@ -400,45 +399,22 @@ class ManyToManyTests(TestCase):
|
|||
self.a4.publications.set([], clear=True)
|
||||
self.assertQuerysetEqual(self.a4.publications.all(), [])
|
||||
|
||||
def test_assign_forward_deprecation(self):
|
||||
def test_assign_forward(self):
|
||||
msg = (
|
||||
"Direct assignment to the reverse side of a many-to-many set is "
|
||||
"deprecated due to the implicit save() that happens. Use "
|
||||
"article_set.set() instead."
|
||||
"prohibited. Use article_set.set() instead."
|
||||
)
|
||||
with self.assertRaisesMessage(RemovedInDjango20Warning, msg):
|
||||
with self.assertRaisesMessage(TypeError, msg):
|
||||
self.p2.article_set = [self.a4, self.a3]
|
||||
|
||||
def test_assign_reverse_deprecation(self):
|
||||
def test_assign_reverse(self):
|
||||
msg = (
|
||||
"Direct assignment to the forward side of a many-to-many "
|
||||
"set is deprecated due to the implicit save() that happens. Use "
|
||||
"publications.set() instead."
|
||||
"set is prohibited. Use publications.set() instead."
|
||||
)
|
||||
with self.assertRaisesMessage(RemovedInDjango20Warning, msg):
|
||||
with self.assertRaisesMessage(TypeError, msg):
|
||||
self.a1.publications = [self.p1, self.p2]
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango20Warning)
|
||||
def test_assign_deprecated(self):
|
||||
self.p2.article_set = [self.a4, self.a3]
|
||||
self.assertQuerysetEqual(
|
||||
self.p2.article_set.all(),
|
||||
[
|
||||
'<Article: NASA finds intelligent life on Earth>',
|
||||
'<Article: Oxygen-free diet works wonders>',
|
||||
]
|
||||
)
|
||||
self.assertQuerysetEqual(self.a4.publications.all(), ['<Publication: Science News>'])
|
||||
self.a4.publications = [self.p3.id]
|
||||
self.assertQuerysetEqual(self.p2.article_set.all(), ['<Article: NASA finds intelligent life on Earth>'])
|
||||
self.assertQuerysetEqual(self.a4.publications.all(), ['<Publication: Science Weekly>'])
|
||||
|
||||
# An alternate to calling clear() is to assign the empty set
|
||||
self.p2.article_set = []
|
||||
self.assertQuerysetEqual(self.p2.article_set.all(), [])
|
||||
self.a4.publications = []
|
||||
self.assertQuerysetEqual(self.a4.publications.all(), [])
|
||||
|
||||
def test_assign(self):
|
||||
# Relation sets can be assigned using set().
|
||||
self.p2.article_set.set([self.a4, self.a3])
|
||||
|
|
|
@ -115,10 +115,9 @@ class ManyToOneTests(TestCase):
|
|||
def test_reverse_assignment_deprecation(self):
|
||||
msg = (
|
||||
"Direct assignment to the reverse side of a related set is "
|
||||
"deprecated due to the implicit save() that happens. Use "
|
||||
"article_set.set() instead."
|
||||
"prohibited. Use article_set.set() instead."
|
||||
)
|
||||
with self.assertRaisesMessage(RemovedInDjango20Warning, msg):
|
||||
with self.assertRaisesMessage(TypeError, msg):
|
||||
self.r2.article_set = []
|
||||
|
||||
def test_assign(self):
|
||||
|
|
Loading…
Reference in New Issue