Как работает get_FIELD_display (в django)?
Я новичок в Django и Python и недавно наткнулся на ряд методов в документах Django, таких как Model.get_FOO_display(). На странице справки говорится, что вы можете заменить FOO на имя поля. Я пытался выяснить, как это возможно в Python и заглядывает в класс "Модель".
Там я натолкнулся на это:
def _get_FIELD_display(self, field):
value = getattr(self, field.attname)
return force_unicode(dict(field.flatchoices).get(value, value), strings_only=True)
Я не могу понять, как это возможно в Python:
1), чтобы написать это
class Person(models.Model):
gender = models.CharField(max_length=1, choices=GENDER_CHOICES)
p = Person(name='John', gender='M')
p.get_gender_display()
Итак, как Python "изменяет" FIELD (или FOO) на пол? Это какая-то "злая" нотация Питона? (Извините, я не могу спросить более четко) Coud вы указываете на какую-то страницу руководства Python?
2) почему источник из класса Model объявляет _get_FIELD_display() с лидирующим подчеркиванием, но извлечение извлечения из Python из вышеперечисленного записывает "p.get_gender_display()" без подчеркивания? Опять же, не могли бы вы дать для этого страницу руководства Python?
Ответы
Ответ 1
Все это управляется через метакласс - вы увидите в источнике, что класс Model определяет атрибут __metaclass__
, который установлен на ModelBase
. Метакласс относится к классу, так как класс относится к экземпляру.
Таким образом, метаклас вызывается, когда определен класс Django. Затем метаклас выполняет различный код, который определяет свойства класса модели. Таким образом, он выполняет итерацию через поля, объявленные в классе модели, и присваивает каждому атрибут экземпляра - таким образом работает декларативный синтаксис Django. Затем он вызывает каждый метод contribute_to_class
, который добавляет к самому классу любые специфичные для поля методы, и одним из этих методов является метод _get_FOO_display
. Вы можете увидеть источник для этого в django/db/models/fields/__init__.py
.
Чтобы изменить _get_FIELD_display
на get_myfieldname_display
, он использует метод, называемый "currying", что означает, что он определяет новую функцию, которая применяет оригинальный метод с определенным параметром - в этом случае имя поле.
Если вам интересно все это, книга Марти Алчина Pro Django имеет отличное объяснение.
Ответ 2
Магический метод __getattr__ для классов может использоваться для реализации такого рода функций. __getattr__
вызывается для каждого obj.attribute
, где attribute
не существует на obj
, и реализация может вернуть все, что пожелает.