class Form(BaseForm, metaclass=DeclarativeFieldsMetaclass):Form 中指定了基类 BaseForm 和元类 DeclarativeFieldsMetaclass。BaseForm 中定义了生成 HTML 与字段值校验的方法,而 DeclarativeFieldsMetaclass 则定义了创建 Form 对象的过程。DeclarativeFieldsMetaclass 在 Django 中的源码实现如下所示:
class DeclarativeFieldsMetaclass(MediaDefiningClass): def __new__(mcs, name, bases, attrs): # 收集基类中声明的字段。 current_fields = [] #遍历当前类中定义的属性 for key, value in list(attrs.items()): #只添加field类型的实例 if isinstance(value, Field): current_fields.append((key, value)) attrs.pop(key) attrs['declared_fields'] = OrderedDict(current_fields) #调用父类的new方法创建类对象 new_class = super(DeclarativeFieldsMetaclass, mcs).__new__(mcs, name, bases, attrs) # Walk through the MRO. declared_fields = OrderedDict() for base in reversed(new_class.__mro__): # 继承父类的字段定义 if hasattr(base, 'declared_fields'): declared_fields.update(base.declared_fields) for attr, value in base.__dict__.items(): if value is None and attr in declared_fields: declared_fields.pop(attr) #在这里创建的类对象添加了base_fields和declared_fields两个属性 new_class.base_fields = declared_fields new_class.declared_fields = declared_fields return new_classDeclarativeFieldsMetaclass 继承自 MediaDefiningClass,并调用了它的 new 方法创建了类对象。MediaDefiningClass 的实现如下:
class MediaDefiningClass(type): "元类用于具有媒体定义的类。" def __new__(mcs, name, bases, attrs): new_class = super(MediaDefiningClass, mcs).__new__(mcs, name, bases, attrs) #如果属性中没有media,则通过media_property if 'media' not in attrs: new_class.media = media_property(new_class) return new_classMediaDefiningClass 中并没有做太多的工作,只是给类对象添加了 media 属性,当我们使用 JavaScript 和 CSS 的时候。这个 media 属性起到引用的作用。最后在类对象返回之前,给它附加了两个属性,且都指向了 declared_fields,它是一个 OrderedDict 类型的实例,存储了表单中定义的 Field。例如,可以查看 TitleSearch 的 base_fields 属性:
In [1]: from index.forms import TitleSearch In [2]: TitleSearch.base_fields Out[2]: OrderedDict([('title', <django.forms.fields.CharField at 0x87f9a30>)])
def __str__(self): return self.as_table()其中只是调用了 as_table 方法,它的实现如下:
def as_table(self): "得到一张HTML table格式" return self._html_output( normal_row='<tr%(html_class_attr)s><th>%(label)s</th><td>%(errors)s%(field)s%(help_text)s</td></tr>', error_row='<tr><td colspan="2">%s</td></tr>', row_ender='</td></tr>', help_text_html='<br><span class="helptext">%s</span>', errors_on_separate_row=False, )代码中的 _html_output 方法实现表单对象到 HTML 的转换,除了 as_table 外,as_url 和 as_p 的实现同样也使用了该方法。
Copyright © 广州京杭网络科技有限公司 2005-2025 版权所有 粤ICP备16019765号
广州京杭网络科技有限公司 版权所有