mirror of
https://github.com/django/django.git
synced 2025-06-05 11:39:13 +00:00
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.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@15580 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
de161fbf21
commit
791ecb4be4
@ -16,7 +16,10 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for result in results %}
|
{% 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 %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
@ -198,10 +198,10 @@ def items_for_result(cl, result, form):
|
|||||||
def results(cl):
|
def results(cl):
|
||||||
if cl.formset:
|
if cl.formset:
|
||||||
for res, form in zip(cl.result_list, cl.formset.forms):
|
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:
|
else:
|
||||||
for res in cl.result_list:
|
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):
|
def result_hidden_fields(cl):
|
||||||
if cl.formset:
|
if cl.formset:
|
||||||
|
@ -669,7 +669,32 @@ class Answer(models.Model):
|
|||||||
class Reservation(models.Model):
|
class Reservation(models.Model):
|
||||||
start_date = models.DateTimeField()
|
start_date = models.DateTimeField()
|
||||||
price = models.IntegerField()
|
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(Article, ArticleAdmin)
|
||||||
admin.site.register(CustomArticle, CustomArticleAdmin)
|
admin.site.register(CustomArticle, CustomArticleAdmin)
|
||||||
admin.site.register(Section, save_as=True, inlines=[ArticleInline])
|
admin.site.register(Section, save_as=True, inlines=[ArticleInline])
|
||||||
@ -706,6 +731,7 @@ admin.site.register(CyclicOne)
|
|||||||
admin.site.register(CyclicTwo)
|
admin.site.register(CyclicTwo)
|
||||||
admin.site.register(WorkHour, WorkHourAdmin)
|
admin.site.register(WorkHour, WorkHourAdmin)
|
||||||
admin.site.register(Reservation)
|
admin.site.register(Reservation)
|
||||||
|
admin.site.register(FoodDelivery, FoodDeliveryAdmin)
|
||||||
|
|
||||||
# We intentionally register Promo and ChapterXtra1 but not Chapter nor ChapterXtra2.
|
# We intentionally register Promo and ChapterXtra1 but not Chapter nor ChapterXtra2.
|
||||||
# That way we cover all four cases:
|
# That way we cover all four cases:
|
||||||
|
@ -35,7 +35,7 @@ from models import (Article, BarAccount, CustomArticle, EmptyModel,
|
|||||||
Person, Persona, Picture, Podcast, Section, Subscriber, Vodcast,
|
Person, Persona, Picture, Podcast, Section, Subscriber, Vodcast,
|
||||||
Language, Collector, Widget, Grommet, DooHickey, FancyDoodad, Whatsit,
|
Language, Collector, Widget, Grommet, DooHickey, FancyDoodad, Whatsit,
|
||||||
Category, Post, Plot, FunkyTag, Chapter, Book, Promo, WorkHour, Employee,
|
Category, Post, Plot, FunkyTag, Chapter, Book, Promo, WorkHour, Employee,
|
||||||
Question, Answer, Inquisition, Actor)
|
Question, Answer, Inquisition, Actor, FoodDelivery)
|
||||||
|
|
||||||
|
|
||||||
class AdminViewBasicTest(TestCase):
|
class AdminViewBasicTest(TestCase):
|
||||||
@ -1420,6 +1420,67 @@ class AdminViewListEditable(TestCase):
|
|||||||
|
|
||||||
self.assertEqual(Person.objects.get(name="John Mauchly").alive, False)
|
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):
|
def test_non_form_errors(self):
|
||||||
# test if non-form errors are handled; ticket #12716
|
# test if non-form errors are handled; ticket #12716
|
||||||
data = {
|
data = {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user