mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	Fixed #30543 -- Fixed checks of ModelAdmin.list_display for fields accessible only via instance.
Co-Authored-By: Andrew Simons <andrewsimons@bubblegroup.com>
This commit is contained in:
		
				
					committed by
					
						 Mariusz Felisiak
						Mariusz Felisiak
					
				
			
			
				
	
			
			
			
						parent
						
							7991111af1
						
					
				
				
					commit
					ed668796f6
				
			| @@ -720,33 +720,33 @@ class ModelAdminChecks(BaseModelAdminChecks): | |||||||
|             return [] |             return [] | ||||||
|         elif hasattr(obj, item): |         elif hasattr(obj, item): | ||||||
|             return [] |             return [] | ||||||
|         elif hasattr(obj.model, item): |         try: | ||||||
|  |             field = obj.model._meta.get_field(item) | ||||||
|  |         except FieldDoesNotExist: | ||||||
|             try: |             try: | ||||||
|                 field = obj.model._meta.get_field(item) |                 field = getattr(obj.model, item) | ||||||
|             except FieldDoesNotExist: |             except AttributeError: | ||||||
|                 return [] |                 return [ | ||||||
|             else: |                     checks.Error( | ||||||
|                 if isinstance(field, models.ManyToManyField): |                         "The value of '%s' refers to '%s', which is not a " | ||||||
|                     return [ |                         "callable, an attribute of '%s', or an attribute or " | ||||||
|                         checks.Error( |                         "method on '%s.%s'." % ( | ||||||
|                             "The value of '%s' must not be a ManyToManyField." % label, |                             label, item, obj.__class__.__name__, | ||||||
|                             obj=obj.__class__, |                             obj.model._meta.app_label, obj.model._meta.object_name, | ||||||
|                             id='admin.E109', |                         ), | ||||||
|                         ) |                         obj=obj.__class__, | ||||||
|                     ] |                         id='admin.E108', | ||||||
|                 return [] |                     ) | ||||||
|         else: |                 ] | ||||||
|  |         if isinstance(field, models.ManyToManyField): | ||||||
|             return [ |             return [ | ||||||
|                 checks.Error( |                 checks.Error( | ||||||
|                     "The value of '%s' refers to '%s', which is not a callable, " |                     "The value of '%s' must not be a ManyToManyField." % label, | ||||||
|                     "an attribute of '%s', or an attribute or method on '%s.%s'." % ( |  | ||||||
|                         label, item, obj.__class__.__name__, |  | ||||||
|                         obj.model._meta.app_label, obj.model._meta.object_name, |  | ||||||
|                     ), |  | ||||||
|                     obj=obj.__class__, |                     obj=obj.__class__, | ||||||
|                     id='admin.E108', |                     id='admin.E109', | ||||||
|                 ) |                 ) | ||||||
|             ] |             ] | ||||||
|  |         return [] | ||||||
|  |  | ||||||
|     def _check_list_display_links(self, obj): |     def _check_list_display_links(self, obj): | ||||||
|         """ Check that list_display_links is a unique subset of list_display. |         """ Check that list_display_links is a unique subset of list_display. | ||||||
|   | |||||||
| @@ -3,7 +3,7 @@ from django.contrib.admin import BooleanFieldListFilter, SimpleListFilter | |||||||
| from django.contrib.admin.options import VERTICAL, ModelAdmin, TabularInline | from django.contrib.admin.options import VERTICAL, ModelAdmin, TabularInline | ||||||
| from django.contrib.admin.sites import AdminSite | from django.contrib.admin.sites import AdminSite | ||||||
| from django.core.checks import Error | from django.core.checks import Error | ||||||
| from django.db.models import F | from django.db.models import F, Field, Model | ||||||
| from django.db.models.functions import Upper | from django.db.models.functions import Upper | ||||||
| from django.forms.models import BaseModelFormSet | from django.forms.models import BaseModelFormSet | ||||||
| from django.test import SimpleTestCase | from django.test import SimpleTestCase | ||||||
| @@ -509,6 +509,25 @@ class ListDisplayTests(CheckTestCase): | |||||||
|  |  | ||||||
|         self.assertIsValid(TestModelAdmin, ValidationTestModel) |         self.assertIsValid(TestModelAdmin, ValidationTestModel) | ||||||
|  |  | ||||||
|  |     def test_valid_field_accessible_via_instance(self): | ||||||
|  |         class PositionField(Field): | ||||||
|  |             """Custom field accessible only via instance.""" | ||||||
|  |             def contribute_to_class(self, cls, name): | ||||||
|  |                 super().contribute_to_class(cls, name) | ||||||
|  |                 setattr(cls, self.name, self) | ||||||
|  |  | ||||||
|  |             def __get__(self, instance, owner): | ||||||
|  |                 if instance is None: | ||||||
|  |                     raise AttributeError() | ||||||
|  |  | ||||||
|  |         class TestModel(Model): | ||||||
|  |             field = PositionField() | ||||||
|  |  | ||||||
|  |         class TestModelAdmin(ModelAdmin): | ||||||
|  |             list_display = ('field',) | ||||||
|  |  | ||||||
|  |         self.assertIsValid(TestModelAdmin, TestModel) | ||||||
|  |  | ||||||
|  |  | ||||||
| class ListDisplayLinksCheckTests(CheckTestCase): | class ListDisplayLinksCheckTests(CheckTestCase): | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user