Fix inability to override get_FIELD_display methods

Ensure custom get_FIELD_display() overrides are respected for model fields with choices.
This restores behavior present before Django 2.2.

Fixes # (referenced issue in description).
This commit is contained in:
utkarsh.arya@zomato.com 2025-11-15 22:57:29 +00:00
parent 8463390527
commit f23bce7ebf
3 changed files with 24 additions and 4 deletions

View file

@ -763,8 +763,10 @@ class Field(RegisterLookupMixin):
if not getattr(cls, self.attname, None):
setattr(cls, self.attname, self.descriptor_class(self))
if self.choices is not None:
setattr(cls, 'get_%s_display' % self.name,
partialmethod(cls._get_FIELD_display, field=self))
# Check that a get_FIELD_display method hasn't been manually defined.
if not hasattr(cls, 'get_%s_display' % self.name):
setattr(cls, 'get_%s_display' % self.name,
partialmethod(cls._get_FIELD_display, field=self))
def get_filter_kwargs_for_object(self, obj):
"""

View file

@ -405,3 +405,11 @@ class UUIDChild(PrimaryKeyUUIDModel):
class UUIDGrandchild(UUIDChild):
pass
class CustomGetDisplayModel(models.Model):
"""Test model for overriding get_FIELD_display()."""
foo_bar = models.CharField(max_length=10, choices=[(1, 'foo'), (2, 'bar')])
def get_foo_bar_display(self):
return "something"

View file

@ -7,8 +7,8 @@ from django.test import SimpleTestCase, TestCase
from django.utils.functional import lazy
from .models import (
Bar, Choiceful, Foo, RenamedField, VerboseNameField, Whiz, WhizDelayed,
WhizIter, WhizIterEmpty,
Bar, Choiceful, CustomGetDisplayModel, Foo, RenamedField, VerboseNameField,
Whiz, WhizDelayed, WhizIter, WhizIterEmpty,
)
@ -186,6 +186,16 @@ class GetFieldDisplayTests(SimpleTestCase):
self.assertIsNone(WhizIterEmpty(c=None).c) # Blank value
self.assertEqual(WhizIterEmpty(c='').c, '') # Empty value
def test_overriding_get_FIELD_display(self):
"""
Can override the get_FIELD_display() method.
"""
obj = CustomGetDisplayModel(foo_bar=1)
# Should use the overridden method which always returns "something"
self.assertEqual(obj.get_foo_bar_display(), 'something')
obj.foo_bar = 2
self.assertEqual(obj.get_foo_bar_display(), 'something')
class GetChoicesTests(SimpleTestCase):