diff --git a/django/contrib/admin/templates/admin/change_list_results.html b/django/contrib/admin/templates/admin/change_list_results.html
index 3e38978..29cf265 100644
a
|
b
|
|
16 | 16 | </thead> |
17 | 17 | <tbody> |
18 | 18 | {% for result in results %} |
19 | | <tr class="{% cycle 'row1' 'row2' %}">{% for item in result %}{{ item }}{% endfor %}</tr> |
| 19 | {% if result.form.non_field_errors %} |
| 20 | <tr><td colspan="{{ result.row|length }}">{{ result.form.non_field_errors }}</td></tr> |
| 21 | {% endif %} |
| 22 | <tr class="{% cycle 'row1' 'row2' %}">{% for item in result.row %}{{ item }}{% endfor %}</tr> |
20 | 23 | {% endfor %} |
21 | 24 | </tbody> |
22 | 25 | </table> |
diff --git a/django/contrib/admin/templatetags/admin_list.py b/django/contrib/admin/templatetags/admin_list.py
index 806be24..0e8d0b5 100644
a
|
b
|
def items_for_result(cl, result, form):
|
198 | 198 | def results(cl): |
199 | 199 | if cl.formset: |
200 | 200 | for res, form in zip(cl.result_list, cl.formset.forms): |
201 | | yield list(items_for_result(cl, res, form)) |
| 201 | yield {'row': list(items_for_result(cl, res, form)), 'form': form} |
202 | 202 | else: |
203 | 203 | for res in cl.result_list: |
204 | | yield list(items_for_result(cl, res, None)) |
| 204 | yield {'row': list(items_for_result(cl, res, None)), 'form': None} |
205 | 205 | |
206 | 206 | def result_hidden_fields(cl): |
207 | 207 | if cl.formset: |
diff --git a/tests/regressiontests/admin_views/models.py b/tests/regressiontests/admin_views/models.py
index 60319ea..e3f0cb5 100644
a
|
b
|
class Answer(models.Model):
|
669 | 669 | class Reservation(models.Model): |
670 | 670 | start_date = models.DateTimeField() |
671 | 671 | price = models.IntegerField() |
| 672 | |
| 673 | |
| 674 | DRIVER_CHOICES = ( |
| 675 | (u'bill', 'Bill G'), |
| 676 | (u'steve', 'Steve J'), |
| 677 | ) |
| 678 | |
| 679 | RESTAURANT_CHOICES = ( |
| 680 | (u'indian', u'A Taste of India'), |
| 681 | (u'thai', u'Thai Pography'), |
| 682 | ) |
| 683 | |
| 684 | class TakeAwayDelivery(models.Model): |
| 685 | reference = models.CharField(max_length=100) |
| 686 | driver = models.CharField(max_length=100, choices=DRIVER_CHOICES, blank=True) |
| 687 | restaurant = models.CharField(max_length=100, choices=RESTAURANT_CHOICES, blank=True) |
| 688 | |
| 689 | class Meta: |
| 690 | unique_together = (("driver", "restaurant"),) |
672 | 691 | |
673 | 692 | admin.site.register(Article, ArticleAdmin) |
674 | 693 | admin.site.register(CustomArticle, CustomArticleAdmin) |
… |
… |
admin.site.register(CyclicOne)
|
706 | 725 | admin.site.register(CyclicTwo) |
707 | 726 | admin.site.register(WorkHour, WorkHourAdmin) |
708 | 727 | admin.site.register(Reservation) |
| 728 | admin.site.register(TakeAwayDelivery, list_display=('reference', 'driver', 'restaurant'), list_editable = ('driver', 'restaurant')) |
709 | 729 | |
710 | 730 | # We intentionally register Promo and ChapterXtra1 but not Chapter nor ChapterXtra2. |
711 | 731 | # That way we cover all four cases: |
diff --git a/tests/regressiontests/admin_views/tests.py b/tests/regressiontests/admin_views/tests.py
index acbbbfc..4a198c7 100644
a
|
b
|
from models import (Article, BarAccount, CustomArticle, EmptyModel,
|
35 | 35 | Person, Persona, Picture, Podcast, Section, Subscriber, Vodcast, |
36 | 36 | Language, Collector, Widget, Grommet, DooHickey, FancyDoodad, Whatsit, |
37 | 37 | Category, Post, Plot, FunkyTag, Chapter, Book, Promo, WorkHour, Employee, |
38 | | Question, Answer, Inquisition, Actor) |
| 38 | Question, Answer, Inquisition, Actor, TakeAwayDelivery) |
39 | 39 | |
40 | 40 | |
41 | 41 | class AdminViewBasicTest(TestCase): |
… |
… |
class AdminViewListEditable(TestCase):
|
1420 | 1420 | |
1421 | 1421 | self.assertEqual(Person.objects.get(name="John Mauchly").alive, False) |
1422 | 1422 | |
| 1423 | def test_non_field_errors(self): |
| 1424 | ''' Ensure that non field errors are displayed for each of the |
| 1425 | forms in the changelist's formset. Refs #13126. |
| 1426 | ''' |
| 1427 | TakeAwayDelivery.objects.create(reference='123', driver='bill', restaurant='thai') |
| 1428 | TakeAwayDelivery.objects.create(reference='456', driver='bill', restaurant='india') |
| 1429 | |
| 1430 | data = { |
| 1431 | "form-TOTAL_FORMS": "2", |
| 1432 | "form-INITIAL_FORMS": "2", |
| 1433 | "form-MAX_NUM_FORMS": "0", |
| 1434 | |
| 1435 | "form-0-id": "1", |
| 1436 | "form-0-reference": "123", |
| 1437 | "form-0-driver": "bill", |
| 1438 | "form-0-restaurant": "thai", |
| 1439 | |
| 1440 | # Same data as above: Forbidden because of unique_together! |
| 1441 | "form-1-id": "2", |
| 1442 | "form-1-reference": "456", |
| 1443 | "form-1-driver": "bill", |
| 1444 | "form-1-restaurant": "thai", |
| 1445 | |
| 1446 | "_save": "Save", |
| 1447 | } |
| 1448 | response = self.client.post('/test_admin/admin/admin_views/takeawaydelivery/', data) |
| 1449 | self.assertContains(response, '<tr><td colspan="4"><ul class="errorlist"><li>Take away delivery with this Driver and Restaurant already exists.</li></ul></td></tr>', 1) |
| 1450 | |
1423 | 1451 | def test_non_form_errors(self): |
1424 | 1452 | # test if non-form errors are handled; ticket #12716 |
1425 | 1453 | data = { |