Why does Django use a BaseForm?
I think I finally figured out they need to use this DeclarativeFieldsMetaclass
(to turn the class fields into instance variables and maintain their order with an ordered/sorted dict). However, I'm still not quite sure why they opted to use a BaseForm
rather than implementing everything directly within the Form
class?
They left a comment,
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.
But I don't really understand it. "In order to abstract the way self.fields is specified" -- but Python calls DeclarativeFieldsMetaclass.__new__
before Form.__init__
, so they could have take开发者_如何学Cn full advantage of self.fields
inside Form.__init__
as is; why do they need an extra layer of abstraction?
I think reason is simpl,e with BaseForm
alone you can't define fields using a decalrative syntax i.e.
class MyForm(Form):
field_xxx = form.TextField(...)
field_nnn _ form.IntegerField(...)
For such thing to work for should have a metaclass DeclarativeFieldsMetaclass
which is set in Form only, they did that because
This is a separate class from BaseForm in order to abstract the way, self.fields is specifie
so now you can write WierdForm class in which fields can be defined may be in some wierd way e.g. passing params to class object, point is all the API is in BaseForm
and Form
class just provides an easy to defined fields.
Summary: IMO django preferred to introduce another layer so that if needed different type of field declaration can be implemented, at-least it keeps the non core functionality of forms separate.
Source:
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()
Output:
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__
Looks like MetaForm.__new__
is called twice. Once for Form
and once for CustomForm
, but never for BaseForm
. By having a clean (empty) Form
class, there won't be any extraneous attributes to loop over. It also means that you can define Fields
inside the BaseForm
that could be used for internal use, but avoid rendering.
精彩评论