kur*_*zak 3 python django types class
我想这更像是一个python问题而不是django问题,但是我无法在其他地方复制这种行为,所以我将使用不能按预期工作的确切代码.
当我找到这个工厂函数片段时,我正在研究django中的一些动态表单:
def get_employee_form(employee):
"""Return the form for a specific Board."""
employee_fields = EmployeeFieldModel.objects.filter(employee = employee).order_by ('order')
class EmployeeForm(forms.Form):
def __init__(self, *args, **kwargs):
forms.Form.__init__(self, *args, **kwargs)
self.employee = employee
def save(self):
"Do the save"
for field in employee_fields:
setattr(EmployeeForm, field.name, copy(type_mapping[field.type]))
return type('EmployeeForm', (forms.Form, ), dict(EmployeeForm.__dict__))
Run Code Online (Sandbox Code Playgroud)
[来自:http://uswaretech.com/blog/2008/10/dynamic-forms-with-django/ ]
有一点我不明白,为什么返回修改后的EmployeeForm不能解决问题? 我的意思是这样的:
def get_employee_form(employee):
#[...]same function body as before
for field in employee_fields:
setattr(EmployeeForm, field.name, copy(type_mapping[field.type]))
return EmployeeForm
Run Code Online (Sandbox Code Playgroud)
当我尝试返回修改后的类时,django忽略了我的附加字段,但返回type()的结果完美无缺.
Lennart的假设是正确的:元类确实是罪魁祸首.无需猜测,只需查看源代码:元类DeclarativeFieldsMetaclass当前位于该文件的第53行,并添加属性,base_fields并可能media基于类在创建时具有的属性.在329行,你看到:
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.
__metaclass__ = DeclarativeFieldsMetaclass
Run Code Online (Sandbox Code Playgroud)
这意味着在创建一个带有基础的新类时会有一些脆弱性type- 提供的黑魔法可能会或可能不会通过!一种更可靠的方法是使用其类型EmployeeForm将获取可能涉及的任何元类 - 即:
return type(EmployeeForm)('EmployeeForm', (forms.Form, ), EmployeeForm.__dict__)
Run Code Online (Sandbox Code Playgroud)
(不需要复制__dict__,顺便说一下).区别是微妙但重要的:type我们使用1-arg形式来获取表单类的类型(即元类),然后在3-args中调用THAT元类,而不是直接使用3-args形式.形成.
确实是黑暗神奇的,但那时框架的缺点就是使用"纯粹用于语义糖的花哨的元类东西"&c:只要你想要完全支持框架支持,你就可以使用三叶草,但要离开甚至一点点的支持可能需要反补贴的魔法(这在某种程度上解释了为什么我宁愿使用轻量级,透明的设置,如werkzeug,而不是像Rails或Django那样对我施加魔法的框架:我对深黑魔法的掌握并不意味着我很乐意在普通的生产代码中使用它......但是,这是另一个讨论;-).