From 572885729e028eae2f2b823ef87543b7c66bdb10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anssi=20K=C3=A4=C3=A4ri=C3=A4inen?= Date: Mon, 14 Jul 2014 12:50:41 -0400 Subject: [PATCH] [1.7.x] Fixed #22994 -- regression with generic FK + admin list_view The reason for the regression was that the GenericForeignKey field isn't something meta.get_field_by_name() should return. The reason is that a couple of places in Django expects get_field_by_name() to work this way. It could make sense to return GFKs from get_field_by_name(), but that should likely be done as part of meta refactoring or virtual fields refactoring patches. Thanks to glicerinu@gmail.com for the report and to Tim for working on the issue. --- django/db/models/options.py | 4 +++- tests/admin_views/admin.py | 7 ++++++- tests/admin_views/tests.py | 17 ++++++++++++++++- 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/django/db/models/options.py b/django/db/models/options.py index 05715bcecd..31f8c6f745 100644 --- a/django/db/models/options.py +++ b/django/db/models/options.py @@ -451,7 +451,9 @@ class Options(object): for f, model in self.get_fields_with_model(): cache[f.name] = cache[f.attname] = (f, model, True, False) for f in self.virtual_fields: - cache[f.name] = (f, None if f.model == self.model else f.model, True, False) + if hasattr(f, 'related'): + cache[f.name] = cache[f.attname] = ( + f, None if f.model == self.model else f.model, True, False) if apps.ready: self._name_map = cache return cache diff --git a/tests/admin_views/admin.py b/tests/admin_views/admin.py index caae88dac5..cb72d1b35b 100644 --- a/tests/admin_views/admin.py +++ b/tests/admin_views/admin.py @@ -35,7 +35,7 @@ from .models import (Article, Chapter, Child, Parent, Picture, Widget, UnchangeableObject, UserMessenger, Simple, Choice, ShortMessage, Telegram, FilteredManager, EmptyModelHidden, EmptyModelVisible, EmptyModelMixin, State, City, Restaurant, Worker, ParentWithDependentChildren, - DependentChild, StumpJoke, FieldOverridePost) + DependentChild, StumpJoke, FieldOverridePost, FunkyTag) def callable_year(dt_value): @@ -821,6 +821,10 @@ class RestaurantAdmin(admin.ModelAdmin): return {'name': 'overridden_value'} +class FunkyTagAdmin(admin.ModelAdmin): + list_display = ('name', 'content_object') + + site = admin.AdminSite(name="admin") site.register(Article, ArticleAdmin) site.register(CustomArticle, CustomArticleAdmin) @@ -876,6 +880,7 @@ site.register(State, StateAdmin) site.register(City, CityAdmin) site.register(Restaurant, RestaurantAdmin) site.register(Worker, WorkerAdmin) +site.register(FunkyTag, FunkyTagAdmin) # We intentionally register Promo and ChapterXtra1 but not Chapter nor ChapterXtra2. # That way we cover all four cases: diff --git a/tests/admin_views/tests.py b/tests/admin_views/tests.py index f5b6180e4c..9c56e7bd41 100644 --- a/tests/admin_views/tests.py +++ b/tests/admin_views/tests.py @@ -1655,11 +1655,26 @@ class AdminViewDeletedObjectsTest(TestCase): """ plot = Plot.objects.get(pk=3) FunkyTag.objects.create(content_object=plot, name='hott') - should_contain = """
  • Funky tag: hott""" + should_contain = """
  • Funky tag: hott""" response = self.client.get('/test_admin/admin/admin_views/plot/%s/delete/' % quote(3)) self.assertContains(response, should_contain) +@override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',)) +class TestGenericRelations(TestCase): + urls = "admin_views.urls" + fixtures = ['admin-views-users.xml', 'deleted-objects.xml'] + + def setUp(self): + self.client.login(username='super', password='secret') + + def test_generic_content_object_in_list_display(self): + plot = Plot.objects.get(pk=3) + FunkyTag.objects.create(content_object=plot, name='hott') + response = self.client.get('/test_admin/admin/admin_views/funkytag/') + self.assertContains(response, "%s" % plot) + + @override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',)) class AdminViewStringPrimaryKeyTest(TestCase): urls = "admin_views.urls"