summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRamiro Morales <cramm0@gmail.com>2011-02-22 03:07:57 +0000
committerRamiro Morales <cramm0@gmail.com>2011-02-22 03:07:57 +0000
commit337d102b8612503bb9dc712bfbf07432a9a96302 (patch)
treeda1bd4db4345a0549affb4cc99124fd398de6fb7
parent00fb22d83600a1e3ca162257a46e4a2a5004ef2b (diff)
Fixed #13510 -- Corrected colspan of non-field-specific error messages in admin app tabular inlines so it isn't greater than the actual number of field cells. Thanks KyleMac for the report and Julien Phalip for the patch fixing the issue.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@15626 bcc190cf-cafb-0310-a4f2-bffc1f526a37
-rw-r--r--django/contrib/admin/templates/admin/edit_inline/tabular.html4
-rw-r--r--django/contrib/admin/templatetags/admin_modify.py18
-rw-r--r--tests/regressiontests/admin_inlines/models.py28
-rw-r--r--tests/regressiontests/admin_inlines/tests.py17
4 files changed, 63 insertions, 4 deletions
diff --git a/django/contrib/admin/templates/admin/edit_inline/tabular.html b/django/contrib/admin/templates/admin/edit_inline/tabular.html
index a5b1a899f5..7f6c34ad36 100644
--- a/django/contrib/admin/templates/admin/edit_inline/tabular.html
+++ b/django/contrib/admin/templates/admin/edit_inline/tabular.html
@@ -1,4 +1,4 @@
-{% load i18n adminmedia %}
+{% load i18n adminmedia admin_modify %}
<div class="inline-group" id="{{ inline_admin_formset.formset.prefix }}-group">
<div class="tabular inline-related {% if forloop.last %}last-related{% endif %}">
{{ inline_admin_formset.formset.management_form }}
@@ -18,7 +18,7 @@
<tbody>
{% for inline_admin_form in inline_admin_formset %}
{% if inline_admin_form.form.non_field_errors %}
- <tr><td colspan="{{ inline_admin_form.field_count }}">{{ inline_admin_form.form.non_field_errors }}</td></tr>
+ <tr><td colspan="{{ inline_admin_form|cell_count }}">{{ inline_admin_form.form.non_field_errors }}</td></tr>
{% endif %}
<tr class="{% cycle "row1" "row2" %} {% if inline_admin_form.original or inline_admin_form.show_url %}has_original{% endif %}{% if forloop.last %} empty-form{% endif %}"
id="{{ inline_admin_formset.formset.prefix }}-{% if not forloop.last %}{{ forloop.counter0 }}{% else %}empty{% endif %}">
diff --git a/django/contrib/admin/templatetags/admin_modify.py b/django/contrib/admin/templatetags/admin_modify.py
index fe88043c9f..8e6f0ab5ce 100644
--- a/django/contrib/admin/templatetags/admin_modify.py
+++ b/django/contrib/admin/templatetags/admin_modify.py
@@ -21,7 +21,7 @@ prepopulated_fields_js = register.inclusion_tag('admin/prepopulated_fields_js.ht
def submit_row(context):
"""
- Displays the row of buttons for delete and save.
+ Displays the row of buttons for delete and save.
"""
opts = context['opts']
change = context['change']
@@ -33,10 +33,24 @@ def submit_row(context):
'show_delete_link': (not is_popup and context['has_delete_permission']
and (change or context['show_delete'])),
'show_save_as_new': not is_popup and change and save_as,
- 'show_save_and_add_another': context['has_add_permission'] and
+ 'show_save_and_add_another': context['has_add_permission'] and
not is_popup and (not save_as or context['add']),
'show_save_and_continue': not is_popup and context['has_change_permission'],
'is_popup': is_popup,
'show_save': True
}
submit_row = register.inclusion_tag('admin/submit_line.html', takes_context=True)(submit_row)
+
+def cell_count(inline_admin_form):
+ """Returns the number of cells used in a tabular inline"""
+ count = 1 # Hidden cell with hidden 'id' field
+ for fieldset in inline_admin_form:
+ # Loop through all the fields (one per cell)
+ for line in fieldset:
+ for field in line:
+ count += 1
+ if inline_admin_form.formset.can_delete:
+ # Delete checkbox
+ count += 1
+ return count
+cell_count = register.filter(cell_count)
diff --git a/tests/regressiontests/admin_inlines/models.py b/tests/regressiontests/admin_inlines/models.py
index 4e5c4e3ae3..bb299f32b8 100644
--- a/tests/regressiontests/admin_inlines/models.py
+++ b/tests/regressiontests/admin_inlines/models.py
@@ -6,6 +6,7 @@ from django.db import models
from django.contrib import admin
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
+from django import forms
class Parent(models.Model):
name = models.CharField(max_length=50)
@@ -123,3 +124,30 @@ class InlineWeakness(admin.TabularInline):
extra = 1
admin.site.register(Fashionista, inlines=[InlineWeakness])
+
+# Models for #13510
+
+class TitleCollection(models.Model):
+ pass
+
+class Title(models.Model):
+ collection = models.ForeignKey(TitleCollection, blank=True, null=True)
+ title1 = models.CharField(max_length=100)
+ title2 = models.CharField(max_length=100)
+
+class TitleForm(forms.ModelForm):
+
+ def clean(self):
+ cleaned_data = self.cleaned_data
+ title1 = cleaned_data.get("title1")
+ title2 = cleaned_data.get("title2")
+ if title1 != title2:
+ raise forms.ValidationError("The two titles must be the same")
+ return cleaned_data
+
+class TitleInline(admin.TabularInline):
+ model = Title
+ form = TitleForm
+ extra = 1
+
+admin.site.register(TitleCollection, inlines=[TitleInline])
diff --git a/tests/regressiontests/admin_inlines/tests.py b/tests/regressiontests/admin_inlines/tests.py
index b10474d001..915c6fac8d 100644
--- a/tests/regressiontests/admin_inlines/tests.py
+++ b/tests/regressiontests/admin_inlines/tests.py
@@ -67,6 +67,23 @@ class TestInline(TestCase):
self.assertEqual(response.status_code, 302)
self.assertEqual(len(Fashionista.objects.filter(person__firstname='Imelda')), 1)
+ def test_tabular_non_field_errors(self):
+ """
+ Ensure that non_field_errors are displayed correctly, including the
+ right value for colspan. Refs #13510.
+ """
+ data = {
+ 'title_set-TOTAL_FORMS': 1,
+ 'title_set-INITIAL_FORMS': 0,
+ 'title_set-MAX_NUM_FORMS': 0,
+ '_save': u'Save',
+ 'title_set-0-title1': 'a title',
+ 'title_set-0-title2': 'a different title',
+ }
+ response = self.client.post('/test_admin/admin/admin_inlines/titlecollection/add/', data)
+ # Here colspan is "4": two fields (title1 and title2), one hidden field and the delete checkbock.
+ self.assertContains(response, '<tr><td colspan="4"><ul class="errorlist"><li>The two titles must be the same</li></ul></td></tr>')
+
class TestInlineMedia(TestCase):
fixtures = ['admin-views-users.xml']