【问题标题】:Pre-fill a Django ChoiceField inside a formset在表单集中预填充 Django ChoiceField
【发布时间】:2025-11-24 10:35:02
【问题描述】:

我有一个带有Runner 字段的表单集,该字段应该具有来自Runner 模型的一些值。 我使用select2 小部件来填充这个值:当用户键入内容时,我使用 Ajax 从数据库中查询相应的行。

我现在想保留这个字段在我提交表单集时存储的值,以防出现一些错误,我必须再次显示这个表单。

如果我将此字段定义为ChoiceFieldchoices=[],打开表单并选择一些runner(例如id=123),然后在我发送POST 请求并尝试初始化我的表单集FormsetResult(data=request.POST),我收到一个错误,即提供的值未显示在 choices 列表中,这是真的。

我尝试在表单构造函数中将此值添加到choices

def __init__(self, *args, **kwargs):
  runner_id = None
  if self.fields['runner'].initial:
    runner_id = kwargs['initial'].get('runner')
    runner = models.Runner.objects.filter(pk=runner_id).first()
    if runner:
      self.fields['runner'].choices = [('', ''), (runner_id, runner.get_name())]

,但是在我提交表单后这仍然不起作用:initial 值现在是空的,并且在表单集的情况下,POST 字典具有丑陋的字段名称,例如 form-0-runner,这使得难以提取我需要的价值。

另一种选择是在模板中编写一些技巧,从数据库中加载我需要的值:

<select name="form-{{ forloop.counter0 }}-runner" id="id_form-{{ forloop.counter0 }}-runner">
    {% if form.instance.runner %}
        <option value="{{ form.instance.runner.id }}" selected>{{ form.instance.runner.get_name }}</option>
    {% endif %}
</select>

,但这也不漂亮。

也许您可以找到更好的方法来实现这一目标? 也许Django-Select2 app 会帮我解决这个问题?

【问题讨论】:

    标签: django formset


    【解决方案1】:

    您需要覆盖表单中的__init__ 方法

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
    
        #if form input is empty
        self.fields['runner'].queryset = Runner.objects.none()
    
        # if user typed something
        if 'runner' in self.data:
            self.fields['runner'].queryset = Runner.objects.all()
    
        # if object exists it will set the value of field to previously saved one
        elif self.instance.pk:
            self.fields['runner'].queryset = Runner.objects.all().filter(pk=self.instance.runner.pk)
    

    【讨论】: