2011-04-20 59 views
17

我是Django和Python的新手,最近遇到了Django文檔中的一些方法,比如Model.get_FOO_display()。幫助頁面表示您可以用FOO代替字段的名稱。我一直在試圖弄清楚Python在Python中是如何實現的,並且研​​究了'Model'類的源碼。 在那裏,我遇到了這個:get_FIELD_display(在django中)如何工作?

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是怎樣「變」字段(或FOO)轉換爲性別?它是某種Python'邪惡'的符號嗎? (對不起,我不能更清楚地問)你是否指向Python手冊頁?

2)爲什麼來自Model類的源聲明_get_FIELD_display()帶有前導下劃線,但是上面的Python文檔提取沒有下劃線寫入「p.get_gender_display()」?再說一次,你可以給一個Python手冊頁嗎?

回答

22

這是通過元類進行管理的 - 您會在源代碼中看到Model類定義了__metaclass__屬性,該屬性設置爲ModelBase。元類是類,因爲類是一個實例。

因此,當Django類定義爲時調用元類。元類然後執行確定模型類屬性的各種代碼。因此,它遍歷模型類中聲明的字段,並將每個字段分配爲一個實例屬性 - 這就是Django的聲明性語法的工作原理。然後它調用每個字段的contribute_to_class方法,該方法將任何特定於字段的方法添加到類本身 - 其中一種方法是_get_FOO_display方法。你可以在django/db/models/fields/__init__.py看到這個源代碼。

爲了改變_get_FIELD_displayget_myfieldname_display,它使用一個稱爲「鑽營」技術,這意味着它定義了一個適用具有限定參數的原始方法的新功能 - 在這種情況下,字段的名稱。

如果你對這一切感興趣,Marty Alchin的書Pro Django有一個很好的解釋。

2

類的魔術__getattr__方法可用於實現這種功能。每調用一個obj.attribute就會調用__getattr__,其中attributeobj上不存在,並且該實現可以返回所需的任何內容。