summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Graham <timograham@gmail.com>2016-12-31 09:04:09 -0500
committerTim Graham <timograham@gmail.com>2017-01-17 20:52:01 -0500
commited251246cc6a22561217f38f7cf96598b22ff0fe (patch)
tree6e17d1affdbf331b3f1437491ba7d9bdb677c8a0
parente0910dcc9283cd8f782cb97836c291f6f395f3f0 (diff)
Refs #25550 -- Removed support for direct assignment to the reverse side of a related set.
-rw-r--r--django/db/models/fields/related_descriptors.py22
-rw-r--r--docs/ref/models/relations.txt23
-rw-r--r--docs/releases/2.0.txt3
-rw-r--r--tests/many_to_many/tests.py38
-rw-r--r--tests/many_to_one/tests.py5
5 files changed, 17 insertions, 74 deletions
diff --git a/django/db/models/fields/related_descriptors.py b/django/db/models/fields/related_descriptors.py
index af6fdc3e25..19b465b8ad 100644
--- a/django/db/models/fields/related_descriptors.py
+++ b/django/db/models/fields/related_descriptors.py
@@ -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,
)
diff --git a/docs/ref/models/relations.txt b/docs/ref/models/relations.txt
index c34d3104b2..9cb61d14ed 100644
--- a/docs/ref/models/relations.txt
+++ b/docs/ref/models/relations.txt
@@ -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.
diff --git a/docs/releases/2.0.txt b/docs/releases/2.0.txt
index 4c9347d554..1d46067405 100644
--- a/docs/releases/2.0.txt
+++ b/docs/releases/2.0.txt
@@ -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.
diff --git a/tests/many_to_many/tests.py b/tests/many_to_many/tests.py
index 2917214471..e5bc51be47 100644
--- a/tests/many_to_many/tests.py
+++ b/tests/many_to_many/tests.py
@@ -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])
diff --git a/tests/many_to_one/tests.py b/tests/many_to_one/tests.py
index e29c485baa..c0dd316f79 100644
--- a/tests/many_to_one/tests.py
+++ b/tests/many_to_one/tests.py
@@ -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):