[1.2.X] Fixed #13126 -- Ensured that individual form errors are displayed when errors occur on a list-editable changelist. Thanks to slafs for the report, and to Julien Phalip for the patch.

Backport of r15580 from trunk.

git-svn-id: http://code.djangoproject.com/svn/django/branches/releases/1.2.X@15581 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Russell Keith-Magee 2011-02-19 11:52:33 +00:00
parent c9949103df
commit da4dea5834
4 changed files with 100 additions and 9 deletions

View File

@ -15,7 +15,10 @@
</thead>
<tbody>
{% for result in results %}
<tr class="{% cycle 'row1' 'row2' %}">{% for item in result %}{{ item }}{% endfor %}</tr>
{% if result.form.non_field_errors %}
<tr><td colspan="{{ result.row|length }}">{{ result.form.non_field_errors }}</td></tr>
{% endif %}
<tr class="{% cycle 'row1' 'row2' %}">{% for item in result.row %}{{ item }}{% endfor %}</tr>
{% endfor %}
</tbody>
</table>

View File

@ -199,10 +199,10 @@ def items_for_result(cl, result, form):
def results(cl):
if cl.formset:
for res, form in zip(cl.result_list, cl.formset.forms):
yield list(items_for_result(cl, res, form))
yield {'row': list(items_for_result(cl, res, form)), 'form': form}
else:
for res in cl.result_list:
yield list(items_for_result(cl, res, None))
yield {'row': list(items_for_result(cl, res, None)), 'form': None}
def result_hidden_fields(cl):
if cl.formset:

View File

@ -633,6 +633,31 @@ class Reservation(models.Model):
start_date = models.DateTimeField()
price = models.IntegerField()
DRIVER_CHOICES = (
(u'bill', 'Bill G'),
(u'steve', 'Steve J'),
)
RESTAURANT_CHOICES = (
(u'indian', u'A Taste of India'),
(u'thai', u'Thai Pography'),
(u'pizza', u'Pizza Mama'),
)
class FoodDelivery(models.Model):
reference = models.CharField(max_length=100)
driver = models.CharField(max_length=100, choices=DRIVER_CHOICES, blank=True)
restaurant = models.CharField(max_length=100, choices=RESTAURANT_CHOICES, blank=True)
class Meta:
unique_together = (("driver", "restaurant"),)
class FoodDeliveryAdmin(admin.ModelAdmin):
list_display=('reference', 'driver', 'restaurant')
list_editable = ('driver', 'restaurant')
admin.site.register(Article, ArticleAdmin)
admin.site.register(CustomArticle, CustomArticleAdmin)
admin.site.register(Section, save_as=True, inlines=[ArticleInline])
@ -669,6 +694,7 @@ admin.site.register(CyclicOne)
admin.site.register(CyclicTwo)
admin.site.register(WorkHour, WorkHourAdmin)
admin.site.register(Reservation)
admin.site.register(FoodDelivery, FoodDeliveryAdmin)
# We intentionally register Promo and ChapterXtra1 but not Chapter nor ChapterXtra2.
# That way we cover all four cases:

View File

@ -26,11 +26,12 @@ from django.utils.translation import activate, deactivate
import django.template.context
# local test models
from models import Article, BarAccount, CustomArticle, EmptyModel, \
FooAccount, Gallery, ModelWithStringPrimaryKey, \
Person, Persona, Picture, Podcast, Section, Subscriber, Vodcast, \
Language, Collector, Widget, Grommet, DooHickey, FancyDoodad, Whatsit, \
Category, Post, Plot, FunkyTag, WorkHour, Employee, Inquisition, Actor
from models import (Article, BarAccount, CustomArticle, EmptyModel,
FooAccount, Gallery, ModelWithStringPrimaryKey,
Person, Persona, Picture, Podcast, Section, Subscriber, Vodcast,
Language, Collector, Widget, Grommet, DooHickey, FancyDoodad, Whatsit,
Category, Post, Plot, FunkyTag, WorkHour, Employee, Inquisition,
Actor, FoodDelivery)
class AdminViewBasicTest(TestCase):
@ -1287,6 +1288,67 @@ class AdminViewListEditable(TestCase):
self.assertEqual(Person.objects.get(name="John Mauchly").alive, False)
def test_non_field_errors(self):
''' Ensure that non field errors are displayed for each of the
forms in the changelist's formset. Refs #13126.
'''
FoodDelivery.objects.create(reference='123', driver='bill', restaurant='thai')
FoodDelivery.objects.create(reference='456', driver='bill', restaurant='india')
FoodDelivery.objects.create(reference='789', driver='bill', restaurant='pizza')
data = {
"form-TOTAL_FORMS": "3",
"form-INITIAL_FORMS": "3",
"form-MAX_NUM_FORMS": "0",
"form-0-id": "1",
"form-0-reference": "123",
"form-0-driver": "bill",
"form-0-restaurant": "thai",
# Same data as above: Forbidden because of unique_together!
"form-1-id": "2",
"form-1-reference": "456",
"form-1-driver": "bill",
"form-1-restaurant": "thai",
"form-2-id": "3",
"form-2-reference": "789",
"form-2-driver": "bill",
"form-2-restaurant": "pizza",
"_save": "Save",
}
response = self.client.post('/test_admin/admin/admin_views/fooddelivery/', data)
self.assertContains(response, '<tr><td colspan="4"><ul class="errorlist"><li>Food delivery with this Driver and Restaurant already exists.</li></ul></td></tr>', 1)
data = {
"form-TOTAL_FORMS": "3",
"form-INITIAL_FORMS": "3",
"form-MAX_NUM_FORMS": "0",
"form-0-id": "1",
"form-0-reference": "123",
"form-0-driver": "bill",
"form-0-restaurant": "thai",
# Same data as above: Forbidden because of unique_together!
"form-1-id": "2",
"form-1-reference": "456",
"form-1-driver": "bill",
"form-1-restaurant": "thai",
# Same data also.
"form-2-id": "3",
"form-2-reference": "789",
"form-2-driver": "bill",
"form-2-restaurant": "thai",
"_save": "Save",
}
response = self.client.post('/test_admin/admin/admin_views/fooddelivery/', data)
self.assertContains(response, '<tr><td colspan="4"><ul class="errorlist"><li>Food delivery with this Driver and Restaurant already exists.</li></ul></td></tr>', 2)
def test_non_form_errors(self):
# test if non-form errors are handled; ticket #12716
data = {