From b921f1bac090cecd87e0b99b4c7c2d7581bcf2da Mon Sep 17 00:00:00 2001 From: Jannis Leidel Date: Thu, 3 Mar 2011 13:20:45 +0000 Subject: [PATCH] Fixed #12475 -- Fixed an edge case with hidden fields in ModelAdmin changelists when used in conjunction with list_display_links or list_editable. Thanks, Simon Meers, Julien Phalip, Karen and master. git-svn-id: http://code.djangoproject.com/svn/django/trunk@15722 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- .../templates/admin/change_list_results.html | 2 +- .../contrib/admin/templatetags/admin_list.py | 4 ++- tests/regressiontests/admin_views/models.py | 24 ++++++++++++++ tests/regressiontests/admin_views/tests.py | 32 ++++++++++++++++++- 4 files changed, 59 insertions(+), 3 deletions(-) diff --git a/django/contrib/admin/templates/admin/change_list_results.html b/django/contrib/admin/templates/admin/change_list_results.html index 6cfd9aff8e..891268faba 100644 --- a/django/contrib/admin/templates/admin/change_list_results.html +++ b/django/contrib/admin/templates/admin/change_list_results.html @@ -1,5 +1,5 @@ {% if result_hidden_fields %} -
{# DIV for HTML validation #} +
{# DIV for HTML validation #} {% for item in result_hidden_fields %}{{ item }}{% endfor %}
{% endif %} diff --git a/django/contrib/admin/templatetags/admin_list.py b/django/contrib/admin/templatetags/admin_list.py index 371b6a2b5a..fdf082be70 100644 --- a/django/contrib/admin/templatetags/admin_list.py +++ b/django/contrib/admin/templatetags/admin_list.py @@ -188,7 +188,9 @@ def items_for_result(cl, result, form): # By default the fields come from ModelAdmin.list_editable, but if we pull # the fields out of the form instead of list_editable custom admins # can provide fields on a per request basis - if form and field_name in form.fields: + if (form and field_name in form.fields and not ( + field_name == cl.model._meta.pk.name and + form[cl.model._meta.pk.name].is_hidden)): bf = form[field_name] result_repr = mark_safe(force_unicode(bf.errors) + force_unicode(bf)) else: diff --git a/tests/regressiontests/admin_views/models.py b/tests/regressiontests/admin_views/models.py index 3b44f94d8b..4c4e2907d7 100644 --- a/tests/regressiontests/admin_views/models.py +++ b/tests/regressiontests/admin_views/models.py @@ -735,6 +735,28 @@ class CoverLetterAdmin(admin.ModelAdmin): #return super(CoverLetterAdmin, self).queryset(request).only('author') return super(CoverLetterAdmin, self).queryset(request).defer('date') +class Story(models.Model): + title = models.CharField(max_length=100) + content = models.TextField() + +class StoryForm(forms.ModelForm): + class Meta: + widgets = {'title': forms.HiddenInput} + +class StoryAdmin(admin.ModelAdmin): + list_display = ('id', 'title', 'content') + list_display_links = ('title',) # 'id' not in list_display_links + list_editable = ('content', ) + form = StoryForm + +class OtherStory(models.Model): + title = models.CharField(max_length=100) + content = models.TextField() + +class OtherStoryAdmin(admin.ModelAdmin): + list_display = ('id', 'title', 'content') + list_display_links = ('title', 'id') # 'id' in list_display_links + list_editable = ('content', ) admin.site.register(Article, ArticleAdmin) admin.site.register(CustomArticle, CustomArticleAdmin) @@ -776,6 +798,8 @@ admin.site.register(FoodDelivery, FoodDeliveryAdmin) admin.site.register(RowLevelChangePermissionModel, RowLevelChangePermissionModelAdmin) admin.site.register(Paper, PaperAdmin) admin.site.register(CoverLetter, CoverLetterAdmin) +admin.site.register(Story, StoryAdmin) +admin.site.register(OtherStory, OtherStoryAdmin) # We intentionally register Promo and ChapterXtra1 but not Chapter nor ChapterXtra2. # That way we cover all four cases: diff --git a/tests/regressiontests/admin_views/tests.py b/tests/regressiontests/admin_views/tests.py index ff97acd878..eca8adedc9 100644 --- a/tests/regressiontests/admin_views/tests.py +++ b/tests/regressiontests/admin_views/tests.py @@ -36,7 +36,7 @@ from models import (Article, BarAccount, CustomArticle, EmptyModel, Language, Collector, Widget, Grommet, DooHickey, FancyDoodad, Whatsit, Category, Post, Plot, FunkyTag, Chapter, Book, Promo, WorkHour, Employee, Question, Answer, Inquisition, Actor, FoodDelivery, - RowLevelChangePermissionModel, Paper, CoverLetter) + RowLevelChangePermissionModel, Paper, CoverLetter, Story, OtherStory) class AdminViewBasicTest(TestCase): @@ -1678,6 +1678,36 @@ class AdminViewListEditable(TestCase): response = self.client.get('/test_admin/admin/admin_views/person/?%s' % IS_POPUP_VAR) self.assertEqual(response.context['cl'].list_editable, ()) + def test_pk_hidden_fields(self): + """ Ensure that hidden pk fields aren't displayed in the table body and + that their corresponding human-readable value is displayed instead. + Note that the hidden pk fields are in fact be displayed but + separately (not in the table), and only once. + Refs #12475. + """ + Story.objects.create(title='The adventures of Guido', content='Once upon a time in Djangoland...') + Story.objects.create(title='Crouching Tiger, Hidden Python', content='The Python was sneaking into...') + response = self.client.get('/test_admin/admin/admin_views/story/') + self.assertContains(response, 'id="id_form-0-id"', 1) # Only one hidden field, in a separate place than the table. + self.assertContains(response, 'id="id_form-1-id"', 1) + self.assertContains(response, '
\n\n
') + self.assertContains(response, '1', 1) + self.assertContains(response, '2', 1) + + def test_pk_hidden_fields_with_list_display_links(self): + """ Similarly as test_pk_hidden_fields, but when the hidden pk fields are + referenced in list_display_links. + Refs #12475. + """ + OtherStory.objects.create(title='The adventures of Guido', content='Once upon a time in Djangoland...') + OtherStory.objects.create(title='Crouching Tiger, Hidden Python', content='The Python was sneaking into...') + response = self.client.get('/test_admin/admin/admin_views/otherstory/') + self.assertContains(response, 'id="id_form-0-id"', 1) # Only one hidden field, in a separate place than the table. + self.assertContains(response, 'id="id_form-1-id"', 1) + self.assertContains(response, '
\n\n
') + self.assertContains(response, '1', 1) + self.assertContains(response, '2', 1) + class AdminSearchTest(TestCase): fixtures = ['admin-views-users', 'multiple-child-classes',