Django:设置multiplechoicefield的初始值仅适用于第一次

时间:2017-02-06 21:39:12

标签: python django forms django-forms

我在Django中动态生成表单。

forms.py

class ActiveSignalForm(forms.Form):
    choices = forms.MultipleChoiceField(
        label = 'Alter Archiver Registry',
        choices = ((sig.id, sig.signal)
            for sig in registry.objects.order_by('first_registered')),
        widget = forms.CheckboxSelectMultiple,
        initial = [
            sig.id for sig in registry.objects.order_by('first_registered')
            if sig.archival_active],
    )

views.py

def index(request):
    latest_signal_list = registry.objects.order_by('first_registered')
    form = ActiveSignalForm()
    context = {'latest_signal_list': latest_signal_list, 'form': form}
    return render(request, 'archiver/index.html', context)

提交表单后,处理表单的视图使用HttpResponseRedirect将用户发送回托管表单的页面。

表单完成了我想要的工作(也就是说,它在数据库中进行了适当的更改),但是初始值仍然停留在服务器启动时从数据库中获取的任何值。

您能否提供一种技巧,以确保每次加载页面时确保表单上的初始值与数据库中的初始值相匹配?

感谢。

2 个答案:

答案 0 :(得分:1)

要了解正在发生的事情,请考虑游戏对象的性质:

  1. ActiveSignalForm是一个班级。它在模块中定义,这意味着当模块加载到解释器中时,构造类对象。

  2. ActiveSignalForm.choices是一个类属性。因此,在创建该类的实例之前,它可用于加载ActiveSignalForm类的任何代码。换句话说,您可以ActiveSignalForm.choices访问它,而无需先使用ActiveSignalForm()创建实例。

  3. 在这种特殊情况下,定义涉及作业 - ActiveSignalForm.choices将设置为通过调用forms.MultipleChoiceField()提供的返回值。

  4. 最后,ModelChoiceField的两个调用参数涉及理解表达式。

  5. 通过所有这些信息,您可以开始了解事件链的图片:

    1. 加载包含该类的模块。这启动了ActiveSignalForm类的构建。

    2. 解释器遇到一个赋值表达式来定义ActiveSignalForm.choices

    3. 评估表达式的右侧,包括调用MultipleChoiceField()可调用的。

    4. 为了做到这一点,必须解决choicesinitial调用参数,这涉及评估两个理解表达式。

    5. 所以你看,步骤1到4是嵌套的,这导致你看到的行为 - 服务器启动,模块加载,值计算一次,然后再也不会。

      Django文档包含有关initialchoices字段的重要信息:

        

      您也可以传递任何可调用的,而不是常量。只有在显示未绑定的表单时才会计算callable,而不是在定义它时。

      因此,为了在每次创建不同的ActiveSignalForm 实例时重新计算这些字段,我们需要将它们定义为callables。

      为了做到这一点,我相信你需要做的就是在你的理解表达式前加上lambda:,以便创建一个简单的可调用:

      choices = lambda: ((sig.id, sig.signal)
                         for sig
                         in registry.objects.order_by('first_registered')),
      initial = lambda: [sig.id
                         for sig
                         in registry.objects.order_by('first_registered')
                         if sig.archival_active],
      

      这是做什么的,它将上面的步骤(4)分成两部分。

      4A。现在,在定义类时,在解析initial=的{​​{1}}和choices=参数时,唯一需要评估的是lambda语句。这创建了一个微小的函数,在调用时将评估其中的理解表达式。这允许嵌套解析(即步骤4a返回步骤3的可调用,返回结果作为步骤2中的类属性,然后允许其余的类定义在步骤1中继续)。

      4b中。 (很多)之后,当Django渲染MultipleChoiceField字段时,它遇到我们在(4a)中创建的可调用对象并执行它们以获得适当的迭代。

答案 1 :(得分:0)

没有理由拥有这些列表理解。您正在过滤查询集中的值,因此您应该使用ModelMultipleChoiceField以及实际的查询集。

choices = forms.ModelMultipleChoiceField(
    label='Alter Archiver Registry',
    queryset=registry.objects.order_by('first_registered')),
    initial=registry.objects.order_by('first_registered').filter(archival_active=True)
)