0

可以说我有这样的表格:

class ChangeParentCIForm(ModelForm):
    class Meta:
        model = CINodeInventory
        fields = ('parent',)
        widgets = {'parent': AutocompleteWidget('inventory.uuid'),}

问题是,在我的情况下,AutocompleteWidget 内容不仅必须与“父”字段值相关,还必须与用户会话信息相关(对我来说,是用户在另一个页面上选择的数据库版本号)

为此,我在基于类的视图中做了这样的事情:

class CompanyManageChangeParentCIView(CompanySelectedMixin,CIContextMixin,CompanyViewCIMixin,UpdateView):    
    template_name = 'inventory/browse_change_parent_ci.html'
    context_object_name = 'ci'
    form_class = ChangeParentCIForm

    def get_form(self,form_class):
        form = super(CompanyManageChangeParentCIView,self).get_form(form_class)
        form.base_fields['parent'].widget.url_params={'version':self.request.session['use_version']}
        return form

当然,我修改了 AutocompleteWidget 代码来处理这个 'url_params' 额外参数。

它可以工作,但是这段代码在我看来并不是很漂亮,因为它修改了在初始化时为一个也在初始化时生成的字段创建的小部件。换句话说,如果您创建了 2 个表单实例,它指向相同的字段和小部件,所以如果我这样做:

def get_form(self,form_class):
    form1 = super(CompanyManageChangeParentCIView,self).get_form(form_class)
    form2 = super(CompanyManageChangeParentCIView,self).get_form(form_class)
    form1.base_fields['parent'].widget.url_params="val1"
    form2.base_fields['parent'].widget.url_params="val2"
    print id(form1),id(form1.base_fields['parent'].widget)
    print id(form2),id(form2.base_fields['parent'].widget)

可以看到 form1 和 form2 指向不同的实例,但它们指向相同的小部件(如果打印它们的 id,它们指向相同的字段)。所以对我来说,如果我将 form1 和 form2 显示到同一个模板中,我将显示 2 个小部件“AutocompleteWidget”,但都是使用最新修改自定义的,即 url_parms="val2"

即使我显示一种形式,在我看来也很危险,如果 2 个线程正在执行具有 2 个不同“url_params”值的相同代码的同一个小部件,会发生什么?

所以这是我的问题:如何自定义一个带有上下文信息的 django 小部件渲染,而不仅仅是它的相关字段值?

4

1 回答 1

2

因为您正在更改form.base_fields,这是由该类的所有实例共享的。不要那样做, change form.fields,这是特定于实例的。

作为风格问题,我更喜欢在__init__表单本身的方法中执行此操作,并将 URL 参数作为表单 kwarg 传递 - 看起来您可以覆盖视图的get_form_kwargs方法来执行此操作,那么您不需要完全改变get_form

于 2013-03-28T09:49:10.263 回答