代码之家  ›  专栏  ›  技术社区  ›  kurczak

返回修改后的类和使用type()之间的区别

  •  3
  • kurczak  · 技术社区  · 17 年前

    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__))
    

    http://uswaretech.com/blog/2008/10/dynamic-forms-with-django/ ]

    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
    

    当我尝试返回修改过的类时,django忽略了我的其他字段,但返回type()的结果效果很好。

    3 回复  |  直到 17 年前
        1
  •  5
  •   Alex Martelli    17 年前

    the sources :元类是 DeclarativeFieldsMetaclass base_fields 而且可能 media

    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
    

    这意味着使用base创建新类存在一些脆弱性 type --提供的黑魔法可能会也可能不会持续下去!更可靠的方法是使用以下类型 EmployeeForm 它将拾取可能涉及的任何元类,即:

    return type(EmployeeForm)('EmployeeForm', (forms.Form, ), EmployeeForm.__dict__)
    

    __dict__ 类型 的3-args形式,我们使用1-arg形式来获取表单类的类型(即元类),然后以3-args的形式调用THAT元类。

    确实很神奇,但这就是框架的缺点,这些框架使用“纯粹是为了语义糖的花哨元类”;c: 只要你想做框架支持的事情,你就很幸运,但要摆脱这种支持,即使只是一点点,也可能需要抵消魔法(这在一定程度上解释了为什么我更喜欢使用轻量级、透明的设置,比如werkzeug,而不是像Rails或Django那样给我施魔法的框架:我对深黑魔法的掌握并不意味着我很乐意在普通生产代码中使用它……但是,这是另一个讨论;-)。

        2
  •  3
  •   Lennart Regebro    17 年前

    在这种情况下(尽管我不是100%确定),问题在于Form类在类创建过程中做了什么。我认为它有一个元类,这个元类将在类创建期间完成表单初始化。这意味着您在类创建后添加的任何字段都将被忽略。

    因此,您需要创建一个新类,就像使用type()语句一样,这样就涉及到了元类的类创建代码,现在是新字段。

        3
  •  1
  •   Carl Meyer    16 年前

    值得注意的是,这段代码片段是达到预期目的的一种非常糟糕的方法,并且涉及到对Django Form对象的一个常见误解——Form对象应该与HTML表单一一映射。做这样的事情的正确方法(不需要任何元类魔法)是使用多个Form对象和 inline formset .

    或者,如果出于某种奇怪的原因,你真的想把东西保存在一个Form对象中,只需在Form的__init__方法中操纵self.fields。