2011-04-20 14 views
17

Soy un principiante en Django y Python, y recientemente encontré varios métodos en documentos de Django, como Model.get_FOO_display(). La página de ayuda dice que puede sustituir FOO por el nombre de un campo. He estado tratando de descubrir cómo es posible esto en Python y busqué en la clase 'Modelo'. Allí me encontré con esto:¿Cómo funciona get_FIELD_display (en django)?

def _get_FIELD_display(self, field): 
     value = getattr(self, field.attname) 
     return force_unicode(dict(field.flatchoices).get(value, value), strings_only=True) 

No puedo entender cómo es posible que en Python a: 1) a escribir este

class Person(models.Model): 
    gender = models.CharField(max_length=1, choices=GENDER_CHOICES) 
p = Person(name='John', gender='M') 

p.get_gender_display() 

Así que, ¿cómo funciona el 'cambio' Python campo (o FOO) en el género? ¿Es algún tipo de notación "malvada" de Python? (Lo siento, no puedo preguntar más claramente) ¿Coud apuntas a alguna página man de Python?

2) ¿por qué la fuente de la clase Model declara _get_FIELD_display() con el subrayado inicial, pero el extracto de Python doc desde arriba escribe "p.get_gender_display()" sin el guión bajo? Nuevamente, ¿podría dar una página de hombre de Python para esto?

Respuesta

22

Todo esto se gestiona a través de la metaclase; en la fuente verá que la clase Model define un atributo __metaclass__, que se establece en ModelBase. La metaclase es para la clase como una clase para una instancia.

Entonces se llama a la metaclase cuando una clase Django es definida. La metaclase luego ejecuta varios códigos que determinan las propiedades de la clase de modelo. Por lo tanto, recorre los campos que están declarados en la clase de modelo y asigna cada uno como un atributo de instancia, así es como funciona la sintaxis declarativa de Django. Luego llama al método de cada campo contribute_to_class, que agrega cualquier método específico de campo a la clase en sí, y uno de esos métodos es el método _get_FOO_display. Puede ver la fuente para esto en django/db/models/fields/__init__.py.

Para cambiar _get_FIELD_display a get_myfieldname_display, utiliza una técnica llamada "currying", lo que significa que define una nueva función que aplica el método original con un parámetro definido, en este caso, el nombre del campo.

Si te interesa todo esto, el libro Pro Django de Marty Alchin tiene una excelente explicación.

2

El método mágico __getattr__ en las clases se puede utilizar para implementar este tipo de funcionalidad. Se llama a __getattr__ para cada obj.attribute donde attribute no existe en obj, y la implementación puede devolver lo que desee.

Cuestiones relacionadas