Browse Source

Refs #31282 -- Clarified M2O add/remove/set with PK behaviour.

Improved error message for remove() and added tests.
Carlton Gibson 5 years ago
parent
commit
a34cb5a6d4
2 changed files with 15 additions and 0 deletions
  1. 4 0
      django/db/models/fields/related_descriptors.py
  2. 11 0
      tests/many_to_one/tests.py

+ 4 - 0
django/db/models/fields/related_descriptors.py

@@ -697,6 +697,10 @@ def create_reverse_many_to_one_manager(superclass, rel):
                 val = self.field.get_foreign_related_value(self.instance)
                 old_ids = set()
                 for obj in objs:
+                    if not isinstance(obj, self.model):
+                        raise TypeError("'%s' instance expected, got %r" % (
+                            self.model._meta.object_name, obj,
+                        ))
                     # Is obj actually part of this descriptor set?
                     if self.field.get_local_related_value(obj) == val:
                         old_ids.add(obj.pk)

+ 11 - 0
tests/many_to_one/tests.py

@@ -733,3 +733,14 @@ class ManyToOneTests(TestCase):
         child = parent.to_field_children.get()
         with self.assertNumQueries(0):
             self.assertIs(child.parent, parent)
+
+    def test_add_remove_set_by_pk_raises(self):
+        usa = Country.objects.create(name='United States')
+        chicago = City.objects.create(name='Chicago')
+        msg = "'City' instance expected, got %s" % chicago.pk
+        with self.assertRaisesMessage(TypeError, msg):
+            usa.cities.add(chicago.pk)
+        with self.assertRaisesMessage(TypeError, msg):
+            usa.cities.remove(chicago.pk)
+        with self.assertRaisesMessage(TypeError, msg):
+            usa.cities.set([chicago.pk])