Fixed #14896 -- Ensured that _meta.get_all_related_objects(include_hidden=True) also works correctly with model inheritance.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@15248 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
f399f8bd71
commit
e01cb07404
|
@ -371,7 +371,7 @@ class Options(object):
|
||||||
cache = SortedDict()
|
cache = SortedDict()
|
||||||
parent_list = self.get_parent_list()
|
parent_list = self.get_parent_list()
|
||||||
for parent in self.parents:
|
for parent in self.parents:
|
||||||
for obj, model in parent._meta.get_all_related_objects_with_model():
|
for obj, model in parent._meta.get_all_related_objects_with_model(include_hidden=True):
|
||||||
if (obj.field.creation_counter < 0 or obj.field.rel.parent_link) and obj.model not in parent_list:
|
if (obj.field.creation_counter < 0 or obj.field.rel.parent_link) and obj.model not in parent_list:
|
||||||
continue
|
continue
|
||||||
if not model:
|
if not model:
|
||||||
|
|
|
@ -35,3 +35,12 @@ class PlayedWith(models.Model):
|
||||||
class PlayedWithNote(models.Model):
|
class PlayedWithNote(models.Model):
|
||||||
played = models.ForeignKey(PlayedWith)
|
played = models.ForeignKey(PlayedWith)
|
||||||
note = models.TextField()
|
note = models.TextField()
|
||||||
|
|
||||||
|
class Contact(models.Model):
|
||||||
|
label = models.CharField(max_length=100)
|
||||||
|
|
||||||
|
class Email(Contact):
|
||||||
|
email_address = models.EmailField(max_length=100)
|
||||||
|
|
||||||
|
class Researcher(models.Model):
|
||||||
|
contacts = models.ManyToManyField(Contact, related_name="research_contacts")
|
||||||
|
|
|
@ -4,7 +4,8 @@ from django.conf import settings
|
||||||
from django.db import backend, connection, transaction, DEFAULT_DB_ALIAS
|
from django.db import backend, connection, transaction, DEFAULT_DB_ALIAS
|
||||||
from django.test import TestCase, TransactionTestCase, skipUnlessDBFeature
|
from django.test import TestCase, TransactionTestCase, skipUnlessDBFeature
|
||||||
|
|
||||||
from models import Book, Award, AwardNote, Person, Child, Toy, PlayedWith, PlayedWithNote
|
from models import (Book, Award, AwardNote, Person, Child, Toy, PlayedWith,
|
||||||
|
PlayedWithNote, Contact, Email, Researcher)
|
||||||
|
|
||||||
|
|
||||||
# Can't run this test under SQLite, because you can't
|
# Can't run this test under SQLite, because you can't
|
||||||
|
@ -62,17 +63,12 @@ class DeleteLockingTest(TransactionTestCase):
|
||||||
transaction.commit()
|
transaction.commit()
|
||||||
self.assertEqual(1, Book.objects.count())
|
self.assertEqual(1, Book.objects.count())
|
||||||
|
|
||||||
|
|
||||||
class DeleteCascadeTests(TestCase):
|
class DeleteCascadeTests(TestCase):
|
||||||
def test_generic_relation_cascade(self):
|
def test_generic_relation_cascade(self):
|
||||||
"""
|
"""
|
||||||
Test that Django cascades deletes through generic-related
|
Django cascades deletes through generic-related objects to their
|
||||||
objects to their reverse relations.
|
reverse relations.
|
||||||
|
|
||||||
This might falsely succeed if the database cascades deletes
|
|
||||||
itself immediately; the postgresql_psycopg2 backend does not
|
|
||||||
give such a false success because ForeignKeys are created with
|
|
||||||
DEFERRABLE INITIALLY DEFERRED, so its internal cascade is
|
|
||||||
delayed until transaction commit.
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
person = Person.objects.create(name='Nelson Mandela')
|
person = Person.objects.create(name='Nelson Mandela')
|
||||||
|
@ -87,13 +83,10 @@ class DeleteCascadeTests(TestCase):
|
||||||
|
|
||||||
def test_fk_to_m2m_through(self):
|
def test_fk_to_m2m_through(self):
|
||||||
"""
|
"""
|
||||||
Test that if a M2M relationship has an explicitly-specified
|
If an M2M relationship has an explicitly-specified through model, and
|
||||||
through model, and some other model has an FK to that through
|
some other model has an FK to that through model, deletion is cascaded
|
||||||
model, deletion is cascaded from one of the participants in
|
from one of the participants in the M2M, to the through model, to its
|
||||||
the M2M, to the through model, to its related model.
|
related model.
|
||||||
|
|
||||||
Like the above test, this could in theory falsely succeed if
|
|
||||||
the DB cascades deletes itself immediately.
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
juan = Child.objects.create(name='Juan')
|
juan = Child.objects.create(name='Juan')
|
||||||
|
@ -108,6 +101,24 @@ class DeleteCascadeTests(TestCase):
|
||||||
# first two asserts just sanity checks, this is the kicker:
|
# first two asserts just sanity checks, this is the kicker:
|
||||||
self.assertEquals(PlayedWithNote.objects.count(), 0)
|
self.assertEquals(PlayedWithNote.objects.count(), 0)
|
||||||
|
|
||||||
|
|
||||||
|
class DeleteCascadeTransactionTests(TransactionTestCase):
|
||||||
|
def test_inheritance(self):
|
||||||
|
"""
|
||||||
|
Auto-created many-to-many through tables referencing a parent model are
|
||||||
|
correctly found by the delete cascade when a child of that parent is
|
||||||
|
deleted.
|
||||||
|
|
||||||
|
Refs #14896.
|
||||||
|
"""
|
||||||
|
r = Researcher.objects.create()
|
||||||
|
email = Email.objects.create(
|
||||||
|
label="office-email", email_address="carl@science.edu"
|
||||||
|
)
|
||||||
|
r.contacts.add(email)
|
||||||
|
|
||||||
|
email.delete()
|
||||||
|
|
||||||
class LargeDeleteTests(TestCase):
|
class LargeDeleteTests(TestCase):
|
||||||
def test_large_deletes(self):
|
def test_large_deletes(self):
|
||||||
"Regression for #13309 -- if the number of objects > chunk size, deletion still occurs"
|
"Regression for #13309 -- if the number of objects > chunk size, deletion still occurs"
|
||||||
|
|
Loading…
Reference in New Issue