Loading django/contrib/admin/util.py +8 −2 Original line number Diff line number Diff line Loading @@ -269,8 +269,9 @@ def lookup_field(name, obj, model_admin=None): def label_for_field(name, model, model_admin=None, return_attr=False): """ Returns a sensible label for a field name. The name can be a callable or the name of an object attributes, as well as a genuine fields. If return_attr is Returns a sensible label for a field name. The name can be a callable, property (but not created with @property decorator) or the name of an object's attribute, as well as a genuine fields. If return_attr is True, the resolved attribute (which could be a callable) is also returned. This will be None if (and only if) the name refers to a field. """ Loading Loading @@ -303,6 +304,10 @@ def label_for_field(name, model, model_admin=None, return_attr=False): if hasattr(attr, "short_description"): label = attr.short_description elif (isinstance(attr, property) and hasattr(attr, "fget") and hasattr(attr.fget, "short_description")): label = attr.fget.short_description elif callable(attr): if attr.__name__ == "<lambda>": label = "--" Loading @@ -315,6 +320,7 @@ def label_for_field(name, model, model_admin=None, return_attr=False): else: return label def help_text_for_field(name, model): try: help_text = model._meta.get_field_by_name(name)[0].help_text Loading docs/ref/contrib/admin/index.txt +22 −1 Original line number Diff line number Diff line Loading @@ -589,6 +589,27 @@ subclass:: The above will tell Django to order by the ``first_name`` field when trying to sort by ``colored_first_name`` in the admin. * Elements of ``list_display`` can also be properties. Please note however, that due to the way properties work in Python, setting ``short_description`` on a property is only possible when using the ``property()`` function and **not** with the ``@property`` decorator. For example:: class Person(object): first_name = models.CharField(max_length=50) last_name = models.CharField(max_length=50) def my_property(self): return self.first_name + ' ' + self.last_name my_property.short_description = "Full name of the person" full_name = property(my_property) class PersonAdmin(admin.ModelAdmin): list_display = ('full_name',) * .. versionadded:: 1.6 The field names in ``list_display`` will also appear as CSS classes in Loading tests/admin_util/tests.py +14 −0 Original line number Diff line number Diff line Loading @@ -236,6 +236,20 @@ class UtilTests(unittest.TestCase): ("not Really the Model", MockModelAdmin.test_from_model) ) def test_label_for_property(self): # NOTE: cannot use @property decorator, because of # AttributeError: 'property' object has no attribute 'short_description' class MockModelAdmin(object): def my_property(self): return "this if from property" my_property.short_description = 'property short description' test_from_property = property(my_property) self.assertEqual( label_for_field("test_from_property", Article, model_admin=MockModelAdmin), 'property short description' ) def test_related_name(self): """ Regression test for #13963 Loading Loading
django/contrib/admin/util.py +8 −2 Original line number Diff line number Diff line Loading @@ -269,8 +269,9 @@ def lookup_field(name, obj, model_admin=None): def label_for_field(name, model, model_admin=None, return_attr=False): """ Returns a sensible label for a field name. The name can be a callable or the name of an object attributes, as well as a genuine fields. If return_attr is Returns a sensible label for a field name. The name can be a callable, property (but not created with @property decorator) or the name of an object's attribute, as well as a genuine fields. If return_attr is True, the resolved attribute (which could be a callable) is also returned. This will be None if (and only if) the name refers to a field. """ Loading Loading @@ -303,6 +304,10 @@ def label_for_field(name, model, model_admin=None, return_attr=False): if hasattr(attr, "short_description"): label = attr.short_description elif (isinstance(attr, property) and hasattr(attr, "fget") and hasattr(attr.fget, "short_description")): label = attr.fget.short_description elif callable(attr): if attr.__name__ == "<lambda>": label = "--" Loading @@ -315,6 +320,7 @@ def label_for_field(name, model, model_admin=None, return_attr=False): else: return label def help_text_for_field(name, model): try: help_text = model._meta.get_field_by_name(name)[0].help_text Loading
docs/ref/contrib/admin/index.txt +22 −1 Original line number Diff line number Diff line Loading @@ -589,6 +589,27 @@ subclass:: The above will tell Django to order by the ``first_name`` field when trying to sort by ``colored_first_name`` in the admin. * Elements of ``list_display`` can also be properties. Please note however, that due to the way properties work in Python, setting ``short_description`` on a property is only possible when using the ``property()`` function and **not** with the ``@property`` decorator. For example:: class Person(object): first_name = models.CharField(max_length=50) last_name = models.CharField(max_length=50) def my_property(self): return self.first_name + ' ' + self.last_name my_property.short_description = "Full name of the person" full_name = property(my_property) class PersonAdmin(admin.ModelAdmin): list_display = ('full_name',) * .. versionadded:: 1.6 The field names in ``list_display`` will also appear as CSS classes in Loading
tests/admin_util/tests.py +14 −0 Original line number Diff line number Diff line Loading @@ -236,6 +236,20 @@ class UtilTests(unittest.TestCase): ("not Really the Model", MockModelAdmin.test_from_model) ) def test_label_for_property(self): # NOTE: cannot use @property decorator, because of # AttributeError: 'property' object has no attribute 'short_description' class MockModelAdmin(object): def my_property(self): return "this if from property" my_property.short_description = 'property short description' test_from_property = property(my_property) self.assertEqual( label_for_field("test_from_property", Article, model_admin=MockModelAdmin), 'property short description' ) def test_related_name(self): """ Regression test for #13963 Loading