Fixed #31124 -- Fixed setting of get_FOO_display() when overriding inherited choices.

Regression in 2d38eb0ab9
This commit is contained in:
Carlton Gibson 2020-01-07 11:52:09 +01:00 committed by Carlton Gibson
parent d202846ced
commit 29c126bb34
4 changed files with 31 additions and 1 deletions

View File

@ -764,7 +764,11 @@ class Field(RegisterLookupMixin):
if not getattr(cls, self.attname, None):
setattr(cls, self.attname, self.descriptor_class(self))
if self.choices is not None:
if not hasattr(cls, 'get_%s_display' % self.name):
# Don't override a get_FOO_display() method defined explicitly on
# this class, but don't check methods derived from inheritance, to
# allow overriding inherited choices. For more complex inheritance
# structures users should override contribute_to_class().
if 'get_%s_display' % self.name not in cls.__dict__:
setattr(
cls,
'get_%s_display' % self.name,

View File

@ -834,6 +834,15 @@ Note that in the case of identical date values, these methods will use the
primary key as a tie-breaker. This guarantees that no records are skipped or
duplicated. That also means you cannot use those methods on unsaved objects.
.. admonition:: Overriding extra instance methods
In most cases overriding or inheriting ``get_FOO_display()``,
``get_next_by_FOO()``, and ``get_previous_by_FOO()` should work as
expected. Since they are added by the metaclass however, it is not
practical to account for all possible inheritance structures. In more
complex cases you should override ``Field.contribute_to_class()`` to set
the methods you need.
Other attributes
================

View File

@ -31,3 +31,7 @@ Bugfixes
:class:`~django.contrib.postgres.aggregates.ArrayAgg` and
:class:`~django.contrib.postgres.aggregates.StringAgg` with ``filter``
argument when used in a ``Subquery`` (:ticket:`31097`).
* Fixed a regression in Django 2.2.7 that caused
:meth:`~django.db.models.Model.get_FOO_display` to work incorrectly when
overriding inherited choices (:ticket:`31124`).

View File

@ -178,6 +178,19 @@ class GetFieldDisplayTests(SimpleTestCase):
f = FooBar(foo_bar=1)
self.assertEqual(f.get_foo_bar_display(), 'something')
def test_overriding_inherited_FIELD_display(self):
class Base(models.Model):
foo = models.CharField(max_length=254, choices=[('A', 'Base A')])
class Meta:
abstract = True
class Child(Base):
foo = models.CharField(max_length=254, choices=[('A', 'Child A'), ('B', 'Child B')])
self.assertEqual(Child(foo='A').get_foo_display(), 'Child A')
self.assertEqual(Child(foo='B').get_foo_display(), 'Child B')
def test_iterator_choices(self):
"""
get_choices() works with Iterators.