diff --git a/django/contrib/admin/templatetags/admin_list.py b/django/contrib/admin/templatetags/admin_list.py index 55fba4f90c..e602133ca2 100644 --- a/django/contrib/admin/templatetags/admin_list.py +++ b/django/contrib/admin/templatetags/admin_list.py @@ -200,7 +200,7 @@ def items_for_result(cl, result, form): except ObjectDoesNotExist: result_repr = EMPTY_CHANGELIST_VALUE else: - if f is None: + if f is None or f.auto_created: if field_name == 'action_checkbox': row_classes = ['action-checkbox'] allow_tags = getattr(attr, 'allow_tags', False) diff --git a/django/contrib/admin/views/main.py b/django/contrib/admin/views/main.py index c0e59f9a5f..68c787871a 100644 --- a/django/contrib/admin/views/main.py +++ b/django/contrib/admin/views/main.py @@ -383,7 +383,7 @@ class ChangeList(object): except FieldDoesNotExist: pass else: - if isinstance(field.rel, models.ManyToOneRel): + if hasattr(field, 'rel') and isinstance(field.rel, models.ManyToOneRel): return True return False diff --git a/docs/releases/1.8.3.txt b/docs/releases/1.8.3.txt index 3bc13a2656..860191db1b 100644 --- a/docs/releases/1.8.3.txt +++ b/docs/releases/1.8.3.txt @@ -28,3 +28,6 @@ Bugfixes * Prevented the loss of ``null``/``not null`` column properties during field renaming of MySQL databases (:ticket:`24817`). + +* Fixed a crash when using a reverse one-to-one relation in + ``ModelAdmin.list_display`` (:ticket:`24851`). diff --git a/tests/admin_changelist/admin.py b/tests/admin_changelist/admin.py index 926a45d518..a31cd84c1c 100644 --- a/tests/admin_changelist/admin.py +++ b/tests/admin_changelist/admin.py @@ -102,7 +102,7 @@ site.register(Parent, NoListDisplayLinksParentAdmin) class SwallowAdmin(admin.ModelAdmin): actions = None # prevent ['action_checkbox'] + list(list_display) - list_display = ('origin', 'load', 'speed') + list_display = ('origin', 'load', 'speed', 'swallowonetoone') site.register(Swallow, SwallowAdmin) diff --git a/tests/admin_changelist/models.py b/tests/admin_changelist/models.py index 76249b2cd3..c01bf32062 100644 --- a/tests/admin_changelist/models.py +++ b/tests/admin_changelist/models.py @@ -78,6 +78,10 @@ class Swallow(models.Model): ordering = ('speed', 'load') +class SwallowOneToOne(models.Model): + swallow = models.OneToOneField(Swallow) + + class UnorderedObject(models.Model): """ Model without any defined `Meta.ordering`. diff --git a/tests/admin_changelist/tests.py b/tests/admin_changelist/tests.py index c69b6712ef..8d5b966572 100644 --- a/tests/admin_changelist/tests.py +++ b/tests/admin_changelist/tests.py @@ -25,7 +25,7 @@ from .admin import ( from .models import ( Band, Child, ChordsBand, ChordsMusician, CustomIdUser, Event, Genre, Group, Invitation, Membership, Musician, OrderedObject, Parent, Quartet, Swallow, - UnorderedObject, + SwallowOneToOne, UnorderedObject, ) @@ -478,8 +478,10 @@ class ChangeListTests(TestCase): Regression test for #17128 (ChangeList failing under Python 2.5 after r16319) """ - swallow = Swallow.objects.create( - origin='Africa', load='12.34', speed='22.2') + swallow = Swallow.objects.create(origin='Africa', load='12.34', speed='22.2') + swallow2 = Swallow.objects.create(origin='Africa', load='12.34', speed='22.2') + swallow_o2o = SwallowOneToOne.objects.create(swallow=swallow2) + model_admin = SwallowAdmin(Swallow, admin.site) superuser = self._create_superuser('superuser') request = self._mocked_authenticated_request('/swallow/', superuser) @@ -488,6 +490,9 @@ class ChangeListTests(TestCase): self.assertContains(response, six.text_type(swallow.origin)) self.assertContains(response, six.text_type(swallow.load)) self.assertContains(response, six.text_type(swallow.speed)) + # Reverse one-to-one relations should work. + self.assertContains(response, '(None)') + self.assertContains(response, '%s' % swallow_o2o) def test_deterministic_order_for_unordered_model(self): """