为什么Django使用BaseForm?
我想我终于明白了,他们需要使用这个 DeclarativeFieldsMetaclass
(这个东西可以把类的字段变成实例变量,并且保持它们的顺序,使用一个有序的字典)。不过,我还是不太明白他们为什么选择用 BaseForm
,而不是直接在 Form
类里实现所有功能呢?
他们在这里 留下了一个评论,
class Form(BaseForm):
"A collection of Fields, plus their associated data."
# This is a separate class from BaseForm in order to abstract the way
# self.fields is specified. This class (Form) is the one that does the
# fancy metaclass stuff purely for the semantic sugar -- it allows one
# to define a form using declarative syntax.
# BaseForm itself has no way of designating self.fields.
但是我真的不太理解。评论里说“为了抽象化 self.fields 的指定方式”——可是 Python 在调用 DeclarativeFieldsMetaclass.__new__
之前就会调用 Form.__init__
,所以他们本来可以直接在 Form.__init__
里充分利用 self.fields
;那为什么还需要多一层抽象呢?
2 个回答
我觉得原因很简单,单靠 BaseForm
是无法用声明式语法来定义字段的,也就是说,不能直接用一种简单的方式来写字段。
class MyForm(Form):
field_xxx = form.TextField(...)
field_nnn _ form.IntegerField(...)
要实现这样的功能,就需要一个名为 DeclarativeFieldsMetaclass
的元类,这个元类只在表单中设置。他们这样做是因为
这是一个与 BaseForm 分开的类, 目的是为了抽象化, self.fields 的具体定义方式。
所以现在你可以写一个 WierdForm 类,在这个类中可以用一些奇怪的方式来定义字段,比如给类对象传参数。关键是所有的 API 都在 BaseForm
中,而 Form
类只是提供了一种简单的方式来定义字段。
总结:在我看来,Django 更倾向于引入另一层,这样如果需要的话,可以实现不同类型的字段声明,至少它把表单的非核心功能分开了。
来源:
class MetaForm(type):
def __new__(cls, name, bases, attrs):
print "%s: %s" % (name, attrs)
return type.__new__(cls, name, bases, attrs)
class BaseForm(object):
my_attr = 1
def __init__(self):
print "BaseForm.__init__"
class Form(BaseForm):
__metaclass__ = MetaForm
def __init__(self):
print "Form.__init__"
class CustomForm(Form):
my_field = 2
def __init__(self):
print "CustomForm.__init__"
f = CustomForm()
输出:
Form: {'__module__': '__main__', '__metaclass__': <class '__main__.MetaForm'>, '__init__':<function __init__ at 0x0227E0F0>}
CustomForm: {'__module__': '__main__', 'my_field': 2, '__init__': <function __init__ at 0x0227E170>}
CustomForm.__init__
看起来 MetaForm.__new__
被调用了两次。一次是为了 Form
,另一次是为了 CustomForm
,但从来没有为 BaseForm
调用过。通过保持一个干净(空的) Form
类,就不会有多余的属性需要遍历。这也意味着你可以在 BaseForm
中定义一些 Fields
,这些字段可以用于内部使用,但不会被渲染出来。