環境:Python 2.7.5 + Django 1.6
使用Django,咱們能夠以聲明式的方式來定義一個Form,以下:
# -*- coding: utf-8 -*-
from django import forms
class SimpleForm(forms.Form):python
field_a = forms.CharField(max_length=100)
field_b = forms.CharField(max_length=100)
寫起來很舒服,可是問題來了,當我把這個Form初始化以後,好比:shell
from polls.forms import SimpleForm
sf = SimpleForm({'field_a':'value of field_a', 'field_b':'value of field_b'})
而後在python shell裏執行dir(sf),發現該實例並無field_a和field_b這兩個屬性,顯然咱們就不能像sf.field_a這麼來引用sf上的字段了。但是明明咱們能夠在template裏以{{ form_name.field_name }}的形式來引用form的字段,這是怎麼回事呢?django
一番調查以後發現背後的實現機制還比較曲折。首先,若是咱們要引用form裏的字段應該怎麼寫呢?應該這麼寫:sf['field_a']spa
爲何要這麼寫呢?上代碼,django.forms.BaseForm的__getitem__方法:orm
def __getitem__(self, name):
"Returns a BoundField with the given name."
try:
field = self.fields[name]
except KeyError:
raise KeyError('Key %r not found in Form' % name)
return BoundField(self, field, name)
#更多關於Django的內容,玩蛇網的Python培訓課程中會講解到。對象
這樣就把BaseForm變成一個像dict同樣的的容器了,因此能夠用上面的語法來引用form裏的字段。教程
新的問題又來了,爲何能夠在template裏以{{ form_name.field_name }}的形式來引用form的字段呢?見Django的官方文檔:https://docs.djangoproject.com/en/1.6/topics/templates/#variables。原來Django的模板引擎碰到{{ form_name.field_name }}這樣的表達式,會在form_name對象上運行字典查找,因此模板引擎對{{ sf.field_a }}求值時實際上運行了sf['field_a'],真相大白了。模板引擎
另外,上文中的SimpleForm的類型其實是django.forms.DeclarativeFieldsMetaclass。這個元類其實是把SimpleForm中以聲明式語法聲明的全部字段(還包括父類中的聲明式字段)經過get_declared_fields方法轉換成了一個dict,並將dict的值賦給了將要生成的類的base_fields屬性,而後基於SimpleForm生成了一個新的類。ip