From 225328efd9814f2e922ee77fb48a3eea7428c397 Mon Sep 17 00:00:00 2001 From: Ryanwalker277 Date: Thu, 14 Sep 2023 17:40:20 +0530 Subject: [PATCH] Fixed #31558 -- Added support for boolean attribute on properties in ModelAdmin.list_display. --- django/contrib/admin/templatetags/admin_list.py | 3 +++ django/contrib/admin/utils.py | 2 ++ docs/ref/contrib/admin/index.txt | 6 ++++++ docs/releases/5.0.txt | 3 +++ tests/admin_views/admin.py | 1 + tests/admin_views/models.py | 6 ++++++ tests/admin_views/tests.py | 8 ++++++++ 7 files changed, 29 insertions(+) diff --git a/django/contrib/admin/templatetags/admin_list.py b/django/contrib/admin/templatetags/admin_list.py index 9bff84d501..2dcdf62afb 100644 --- a/django/contrib/admin/templatetags/admin_list.py +++ b/django/contrib/admin/templatetags/admin_list.py @@ -225,6 +225,9 @@ def items_for_result(cl, result, form): if field_name == "action_checkbox": row_classes = ["action-checkbox"] boolean = getattr(attr, "boolean", False) + # Set boolean for attr that is a property, if defined. + if isinstance(attr, property) and hasattr(attr, "fget"): + boolean = getattr(attr.fget, "boolean", False) result_repr = display_for_value(value, empty_value_display, boolean) if isinstance(value, (datetime.date, datetime.time)): row_classes.append("nowrap") diff --git a/django/contrib/admin/utils.py b/django/contrib/admin/utils.py index 92ef1639b4..d6c54dd440 100644 --- a/django/contrib/admin/utils.py +++ b/django/contrib/admin/utils.py @@ -302,6 +302,8 @@ def lookup_field(name, obj, model_admin=None): value = attr() else: value = attr + if hasattr(model_admin, "model") and hasattr(model_admin.model, name): + attr = getattr(model_admin.model, name) f = None else: attr = None diff --git a/docs/ref/contrib/admin/index.txt b/docs/ref/contrib/admin/index.txt index aa30c413fa..79345ea3d1 100644 --- a/docs/ref/contrib/admin/index.txt +++ b/docs/ref/contrib/admin/index.txt @@ -796,6 +796,7 @@ subclass:: @admin.display( ordering="last_name", description="Full name of the person", + boolean=False, ) def full_name(self): return self.first_name + " " + self.last_name @@ -816,9 +817,14 @@ subclass:: my_property.short_description = "Full name of the person" my_property.admin_order_field = "last_name" + my_property.boolean = False full_name = property(my_property) + .. versionchanged:: 5.0 + + Support for ``boolean`` attribute on properties was added. + * The field names in ``list_display`` will also appear as CSS classes in the HTML output, in the form of ``column-`` on each ```` element. This can be used to set column widths in a CSS file for example. diff --git a/docs/releases/5.0.txt b/docs/releases/5.0.txt index 1c17cbfcf5..ac0dda9feb 100644 --- a/docs/releases/5.0.txt +++ b/docs/releases/5.0.txt @@ -211,6 +211,9 @@ Minor features * The new :meth:`.AdminSite.get_model_admin` method returns an admin class for the given model class. +* Properties in :attr:`.ModelAdmin.list_display` now support ``boolean`` + attribute. + :mod:`django.contrib.admindocs` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/tests/admin_views/admin.py b/tests/admin_views/admin.py index 389e1e8370..c157e70505 100644 --- a/tests/admin_views/admin.py +++ b/tests/admin_views/admin.py @@ -216,6 +216,7 @@ class ArticleAdmin(ArticleAdminWithExtraUrl): "model_month", "order_by_f_expression", "order_by_orderby_expression", + "model_property_is_from_past", ) list_editable = ("section",) list_filter = ("date", "section") diff --git a/tests/admin_views/models.py b/tests/admin_views/models.py index de16796e85..67d3ec4c86 100644 --- a/tests/admin_views/models.py +++ b/tests/admin_views/models.py @@ -9,6 +9,7 @@ from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ValidationError from django.core.files.storage import FileSystemStorage from django.db import models +from django.utils import timezone class Section(models.Model): @@ -66,6 +67,11 @@ class Article(models.Model): def model_month(self): return self.date.month + @property + @admin.display(description="Is from past?", boolean=True) + def model_property_is_from_past(self): + return self.date < timezone.now() + class Book(models.Model): """ diff --git a/tests/admin_views/tests.py b/tests/admin_views/tests.py index 164de1d01c..4ea261b347 100644 --- a/tests/admin_views/tests.py +++ b/tests/admin_views/tests.py @@ -486,6 +486,14 @@ class AdminViewBasicTest(AdminViewBasicTestCase): "Results of sorting on callable are out of order.", ) + def test_change_list_boolean_display_property(self): + response = self.client.get(reverse("admin:admin_views_article_changelist")) + self.assertContains( + response, + '' + 'True', + ) + def test_change_list_sorting_property(self): """ Sort on a list_display field that is a property (column 10 is