summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorÉtienne Loks <etienne.loks@iggdrasil.net>2018-01-13 12:23:48 +0100
committerTim Graham <timograham@gmail.com>2018-01-13 10:33:24 -0500
commit419705bbe84e27c3d5be85f198a0352a6724927e (patch)
tree3b3d46b263d2336e4e79f7aadfa8f1596accd92d
parentfb56038723950d9230a7e5fce4d3ee96954b80e8 (diff)
[1.11.x] Fixed #29016 -- Fixed incorrect foreign key nullification on related instance deletion.
Backport of 9a621edf624a4eb1f1645fca628a9e432f0de776 from master
-rw-r--r--django/db/models/deletion.py2
-rw-r--r--docs/releases/1.11.10.txt3
-rw-r--r--tests/delete_regress/models.py2
-rw-r--r--tests/delete_regress/tests.py28
4 files changed, 31 insertions, 4 deletions
diff --git a/django/db/models/deletion.py b/django/db/models/deletion.py
index 26073be3ba..590d5a2298 100644
--- a/django/db/models/deletion.py
+++ b/django/db/models/deletion.py
@@ -286,8 +286,8 @@ class Collector(object):
# update fields
for model, instances_for_fieldvalues in six.iteritems(self.field_updates):
- query = sql.UpdateQuery(model)
for (field, value), instances in six.iteritems(instances_for_fieldvalues):
+ query = sql.UpdateQuery(model)
query.update_batch([obj.pk for obj in instances],
{field.name: value}, self.using)
diff --git a/docs/releases/1.11.10.txt b/docs/releases/1.11.10.txt
index d078959357..49e19614a5 100644
--- a/docs/releases/1.11.10.txt
+++ b/docs/releases/1.11.10.txt
@@ -9,4 +9,5 @@ Django 1.11.10 fixes several bugs in 1.11.9.
Bugfixes
========
-* ...
+* Fixed incorrect foreign key nullification if a model has two foreign keys to
+ the same model and a target model is deleted (:ticket:`29016`).
diff --git a/tests/delete_regress/models.py b/tests/delete_regress/models.py
index f0145de65b..90eae1ba1c 100644
--- a/tests/delete_regress/models.py
+++ b/tests/delete_regress/models.py
@@ -56,6 +56,8 @@ class Email(Contact):
class Researcher(models.Model):
contacts = models.ManyToManyField(Contact, related_name="research_contacts")
+ primary_contact = models.ForeignKey(Contact, models.SET_NULL, null=True, related_name='primary_contacts')
+ secondary_contact = models.ForeignKey(Contact, models.SET_NULL, null=True, related_name='secondary_contacts')
class Food(models.Model):
diff --git a/tests/delete_regress/tests.py b/tests/delete_regress/tests.py
index 2128733798..dac5182436 100644
--- a/tests/delete_regress/tests.py
+++ b/tests/delete_regress/tests.py
@@ -6,7 +6,7 @@ from django.db import connection, models, transaction
from django.test import TestCase, TransactionTestCase, skipUnlessDBFeature
from .models import (
- Award, AwardNote, Book, Child, Eaten, Email, File, Food, FooFile,
+ Award, AwardNote, Book, Child, Contact, Eaten, Email, File, Food, FooFile,
FooFileProxy, FooImage, FooPhoto, House, Image, Item, Location, Login,
OrderedPerson, OrgUnit, Person, Photo, PlayedWith, PlayedWithNote, Policy,
Researcher, Toy, Version,
@@ -335,7 +335,7 @@ class Ticket19102Tests(TestCase):
self.assertTrue(Login.objects.filter(pk=self.l2.pk).exists())
-class OrderedDeleteTests(TestCase):
+class DeleteTests(TestCase):
def test_meta_ordered_delete(self):
# When a subquery is performed by deletion code, the subquery must be
# cleared of all ordering. There was a but that caused _meta ordering
@@ -345,3 +345,27 @@ class OrderedDeleteTests(TestCase):
OrderedPerson.objects.create(name='Bob', lives_in=h)
OrderedPerson.objects.filter(lives_in__address='Foo').delete()
self.assertEqual(OrderedPerson.objects.count(), 0)
+
+ def test_foreign_key_delete_nullifies_correct_columns(self):
+ """
+ With a model (Researcher) that has two foreign keys pointing to the
+ same model (Contact), deleting an instance of the target model
+ (contact1) nullifies the correct fields of Researcher.
+ """
+ contact1 = Contact.objects.create(label='Contact 1')
+ contact2 = Contact.objects.create(label='Contact 2')
+ researcher1 = Researcher.objects.create(
+ primary_contact=contact1,
+ secondary_contact=contact2,
+ )
+ researcher2 = Researcher.objects.create(
+ primary_contact=contact2,
+ secondary_contact=contact1,
+ )
+ contact1.delete()
+ researcher1.refresh_from_db()
+ researcher2.refresh_from_db()
+ self.assertIsNone(researcher1.primary_contact)
+ self.assertEqual(researcher1.secondary_contact, contact2)
+ self.assertEqual(researcher2.primary_contact, contact2)
+ self.assertIsNone(researcher2.secondary_contact)