Loading django/db/models/deletion.py +2 −5 Original line number Diff line number Diff line Loading @@ -231,12 +231,9 @@ class Collector(object): field.remote_field.on_delete(self, field, sub_objs, self.using) for field in model._meta.virtual_fields: if hasattr(field, 'bulk_related_objects'): # Its something like generic foreign key. # It's something like generic foreign key. sub_objs = field.bulk_related_objects(new_objs, self.using) self.collect(sub_objs, source=model, source_attr=field.remote_field.related_name, nullable=True) self.collect(sub_objs, source=model, nullable=True) def related_objects(self, related, objs): """ Loading tests/admin_views/admin.py +4 −3 Original line number Diff line number Diff line Loading @@ -24,9 +24,9 @@ from django.utils.six import StringIO from .models import ( Actor, AdminOrderedAdminMethod, AdminOrderedCallable, AdminOrderedField, AdminOrderedModelMethod, Album, Answer, Article, BarAccount, Book, Category, Chapter, ChapterXtra1, Child, ChildOfReferer, Choice, City, Collector, Color, Color2, ComplexSortedPerson, CoverLetter, CustomArticle, CyclicOne, CyclicTwo, DependentChild, DooHickey, EmptyModel, Bookmark, Category, Chapter, ChapterXtra1, Child, ChildOfReferer, Choice, City, Collector, Color, Color2, ComplexSortedPerson, CoverLetter, CustomArticle, CyclicOne, CyclicTwo, DependentChild, DooHickey, EmptyModel, EmptyModelHidden, EmptyModelMixin, EmptyModelVisible, ExplicitlyProvidedPK, ExternalSubscriber, Fabric, FancyDoodad, FieldOverridePost, FilteredManager, FooAccount, FoodDelivery, FunkyTag, Gadget, Gallery, Loading Loading @@ -912,6 +912,7 @@ site.register(Villain) site.register(SuperVillain) site.register(Plot) site.register(PlotDetails) site.register(Bookmark) site.register(CyclicOne) site.register(CyclicTwo) site.register(WorkHour, WorkHourAdmin) Loading tests/admin_views/models.py +9 −0 Original line number Diff line number Diff line Loading @@ -556,6 +556,15 @@ class SuperSecretHideout(models.Model): return self.location @python_2_unicode_compatible class Bookmark(models.Model): name = models.CharField(max_length=60) tag = GenericRelation(FunkyTag, related_query_name='bookmark') def __str__(self): return self.name @python_2_unicode_compatible class CyclicOne(models.Model): name = models.CharField(max_length=25) Loading tests/admin_views/tests.py +28 −15 Original line number Diff line number Diff line Loading @@ -43,21 +43,21 @@ from . import customadmin from .admin import CityAdmin, site, site2 from .models import ( Actor, AdminOrderedAdminMethod, AdminOrderedCallable, AdminOrderedField, AdminOrderedModelMethod, Answer, Article, BarAccount, Book, Category, Chapter, ChapterXtra1, ChapterXtra2, Character, Child, Choice, City, Collector, Color, Color2, ComplexSortedPerson, CoverLetter, CustomArticle, CyclicOne, CyclicTwo, DooHickey, Employee, EmptyModel, ExternalSubscriber, Fabric, FancyDoodad, FieldOverridePost, FilteredManager, FooAccount, FoodDelivery, FunkyTag, Gallery, Grommet, Inquisition, Language, MainPrepopulated, ModelWithStringPrimaryKey, OtherStory, Paper, Parent, ParentWithDependentChildren, Person, Persona, Picture, Pizza, Plot, PlotDetails, PluggableSearchPerson, Podcast, Post, PrePopulatedPost, Promo, Question, Recommendation, Recommender, RelatedPrepopulated, Report, Restaurant, RowLevelChangePermissionModel, SecretHideout, Section, ShortMessage, Simple, State, Story, Subscriber, SuperSecretHideout, SuperVillain, Telegram, TitleTranslation, Topping, UnchangeableObject, UndeletableObject, UnorderedObject, Villain, Vodcast, Whatsit, Widget, Worker, WorkHour, AdminOrderedModelMethod, Answer, Article, BarAccount, Book, Bookmark, Category, Chapter, ChapterXtra1, ChapterXtra2, Character, Child, Choice, City, Collector, Color, Color2, ComplexSortedPerson, CoverLetter, CustomArticle, CyclicOne, CyclicTwo, DooHickey, Employee, EmptyModel, ExternalSubscriber, Fabric, FancyDoodad, FieldOverridePost, FilteredManager, FooAccount, FoodDelivery, FunkyTag, Gallery, Grommet, Inquisition, Language, MainPrepopulated, ModelWithStringPrimaryKey, OtherStory, Paper, Parent, ParentWithDependentChildren, Person, Persona, Picture, Pizza, Plot, PlotDetails, PluggableSearchPerson, Podcast, Post, PrePopulatedPost, Promo, Question, Recommendation, Recommender, RelatedPrepopulated, Report, Restaurant, RowLevelChangePermissionModel, SecretHideout, Section, ShortMessage, Simple, State, Story, Subscriber, SuperSecretHideout, SuperVillain, Telegram, TitleTranslation, Topping, UnchangeableObject, UndeletableObject, UnorderedObject, Villain, Vodcast, Whatsit, Widget, Worker, WorkHour, ) Loading Loading @@ -2232,6 +2232,19 @@ class AdminViewDeletedObjectsTest(TestCase): response = self.client.get(reverse('admin:admin_views_plot_delete', args=(plot.pk,))) self.assertContains(response, should_contain) def test_generic_relations_with_related_query_name(self): """ If a deleted object has GenericForeignKey with GenericRelation(related_query_name='...') pointing to it, those objects should be listed for deletion. """ bookmark = Bookmark.objects.create(name='djangoproject') tag = FunkyTag.objects.create(content_object=bookmark, name='django') tag_url = reverse('admin:admin_views_funkytag_change', args=(tag.id,)) should_contain = '<li>Funky tag: <a href="%s">django' % tag_url response = self.client.get(reverse('admin:admin_views_bookmark_delete', args=(bookmark.pk,))) self.assertContains(response, should_contain) @override_settings(PASSWORD_HASHERS=['django.contrib.auth.hashers.SHA1PasswordHasher'], ROOT_URLCONF="admin_views.urls") Loading Loading
django/db/models/deletion.py +2 −5 Original line number Diff line number Diff line Loading @@ -231,12 +231,9 @@ class Collector(object): field.remote_field.on_delete(self, field, sub_objs, self.using) for field in model._meta.virtual_fields: if hasattr(field, 'bulk_related_objects'): # Its something like generic foreign key. # It's something like generic foreign key. sub_objs = field.bulk_related_objects(new_objs, self.using) self.collect(sub_objs, source=model, source_attr=field.remote_field.related_name, nullable=True) self.collect(sub_objs, source=model, nullable=True) def related_objects(self, related, objs): """ Loading
tests/admin_views/admin.py +4 −3 Original line number Diff line number Diff line Loading @@ -24,9 +24,9 @@ from django.utils.six import StringIO from .models import ( Actor, AdminOrderedAdminMethod, AdminOrderedCallable, AdminOrderedField, AdminOrderedModelMethod, Album, Answer, Article, BarAccount, Book, Category, Chapter, ChapterXtra1, Child, ChildOfReferer, Choice, City, Collector, Color, Color2, ComplexSortedPerson, CoverLetter, CustomArticle, CyclicOne, CyclicTwo, DependentChild, DooHickey, EmptyModel, Bookmark, Category, Chapter, ChapterXtra1, Child, ChildOfReferer, Choice, City, Collector, Color, Color2, ComplexSortedPerson, CoverLetter, CustomArticle, CyclicOne, CyclicTwo, DependentChild, DooHickey, EmptyModel, EmptyModelHidden, EmptyModelMixin, EmptyModelVisible, ExplicitlyProvidedPK, ExternalSubscriber, Fabric, FancyDoodad, FieldOverridePost, FilteredManager, FooAccount, FoodDelivery, FunkyTag, Gadget, Gallery, Loading Loading @@ -912,6 +912,7 @@ site.register(Villain) site.register(SuperVillain) site.register(Plot) site.register(PlotDetails) site.register(Bookmark) site.register(CyclicOne) site.register(CyclicTwo) site.register(WorkHour, WorkHourAdmin) Loading
tests/admin_views/models.py +9 −0 Original line number Diff line number Diff line Loading @@ -556,6 +556,15 @@ class SuperSecretHideout(models.Model): return self.location @python_2_unicode_compatible class Bookmark(models.Model): name = models.CharField(max_length=60) tag = GenericRelation(FunkyTag, related_query_name='bookmark') def __str__(self): return self.name @python_2_unicode_compatible class CyclicOne(models.Model): name = models.CharField(max_length=25) Loading
tests/admin_views/tests.py +28 −15 Original line number Diff line number Diff line Loading @@ -43,21 +43,21 @@ from . import customadmin from .admin import CityAdmin, site, site2 from .models import ( Actor, AdminOrderedAdminMethod, AdminOrderedCallable, AdminOrderedField, AdminOrderedModelMethod, Answer, Article, BarAccount, Book, Category, Chapter, ChapterXtra1, ChapterXtra2, Character, Child, Choice, City, Collector, Color, Color2, ComplexSortedPerson, CoverLetter, CustomArticle, CyclicOne, CyclicTwo, DooHickey, Employee, EmptyModel, ExternalSubscriber, Fabric, FancyDoodad, FieldOverridePost, FilteredManager, FooAccount, FoodDelivery, FunkyTag, Gallery, Grommet, Inquisition, Language, MainPrepopulated, ModelWithStringPrimaryKey, OtherStory, Paper, Parent, ParentWithDependentChildren, Person, Persona, Picture, Pizza, Plot, PlotDetails, PluggableSearchPerson, Podcast, Post, PrePopulatedPost, Promo, Question, Recommendation, Recommender, RelatedPrepopulated, Report, Restaurant, RowLevelChangePermissionModel, SecretHideout, Section, ShortMessage, Simple, State, Story, Subscriber, SuperSecretHideout, SuperVillain, Telegram, TitleTranslation, Topping, UnchangeableObject, UndeletableObject, UnorderedObject, Villain, Vodcast, Whatsit, Widget, Worker, WorkHour, AdminOrderedModelMethod, Answer, Article, BarAccount, Book, Bookmark, Category, Chapter, ChapterXtra1, ChapterXtra2, Character, Child, Choice, City, Collector, Color, Color2, ComplexSortedPerson, CoverLetter, CustomArticle, CyclicOne, CyclicTwo, DooHickey, Employee, EmptyModel, ExternalSubscriber, Fabric, FancyDoodad, FieldOverridePost, FilteredManager, FooAccount, FoodDelivery, FunkyTag, Gallery, Grommet, Inquisition, Language, MainPrepopulated, ModelWithStringPrimaryKey, OtherStory, Paper, Parent, ParentWithDependentChildren, Person, Persona, Picture, Pizza, Plot, PlotDetails, PluggableSearchPerson, Podcast, Post, PrePopulatedPost, Promo, Question, Recommendation, Recommender, RelatedPrepopulated, Report, Restaurant, RowLevelChangePermissionModel, SecretHideout, Section, ShortMessage, Simple, State, Story, Subscriber, SuperSecretHideout, SuperVillain, Telegram, TitleTranslation, Topping, UnchangeableObject, UndeletableObject, UnorderedObject, Villain, Vodcast, Whatsit, Widget, Worker, WorkHour, ) Loading Loading @@ -2232,6 +2232,19 @@ class AdminViewDeletedObjectsTest(TestCase): response = self.client.get(reverse('admin:admin_views_plot_delete', args=(plot.pk,))) self.assertContains(response, should_contain) def test_generic_relations_with_related_query_name(self): """ If a deleted object has GenericForeignKey with GenericRelation(related_query_name='...') pointing to it, those objects should be listed for deletion. """ bookmark = Bookmark.objects.create(name='djangoproject') tag = FunkyTag.objects.create(content_object=bookmark, name='django') tag_url = reverse('admin:admin_views_funkytag_change', args=(tag.id,)) should_contain = '<li>Funky tag: <a href="%s">django' % tag_url response = self.client.get(reverse('admin:admin_views_bookmark_delete', args=(bookmark.pk,))) self.assertContains(response, should_contain) @override_settings(PASSWORD_HASHERS=['django.contrib.auth.hashers.SHA1PasswordHasher'], ROOT_URLCONF="admin_views.urls") Loading