开发者

Why does Django use a BaseForm?

开发者 https://www.devze.com 2023-01-06 05:09 出处:网络
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 st

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.

0

精彩评论

暂无评论...
验证码 换一张
取 消