动态填充表单集中的字段

Posted

技术标签:

【中文标题】动态填充表单集中的字段【英文标题】:dynamically populating fields in a formset 【发布时间】:2010-11-04 11:20:57 【问题描述】:

我有两个看起来像这样的模型:

class RouteBase(models.Model):
    base        =   models.ForeignKey("Base")
    route       =   models.ForeignKey("Route")
    sequence    =   models.IntegerField()

class Route(models.Model):
    bases       =   models.ManyToManyField("Base", through="RouteBase", blank=True)
    description =   models.TextField(blank=True)
    #and a few other attributes omitted for brevity

...然后是一个看起来像这样的模型:

class RouteBaseForm(ModelForm):
    base = forms.ModelChoiceField(queryset=Base.objects.all(), widget=forms.TextInput)
    sequence = forms.IntegerField(widget=forms.HiddenInput)

    class Meta:
        model = RouteBase

如您所见,序列小部件是隐藏的,因为我希望该字段由 django 自动处理。我希望用户只需通过文本框输入 Base 即可。顺序由文本框的顺序推断。

我已经使用此表单创建了一个表单集,用于创建/编辑路线中的所有基础:

RouteBaseFormset = inlineformset_factory(Route, RouteBase, form=RouteBaseForm, extra=5, )

创建此表单集时,序列字段为空。在保存表单集之前,我需要用值填充它(否则它不会验证)。我可以想到大约 4 种方法来解决这个问题

    就在我将表单集发送到模板之前,我运行了以下代码:
我=1 对于 formset.forms 中的表单: form.fields["sequence"].initial = i 我 += 1

这工作正常,除了一个问题。当表单集被提交回视图进行保存时,所有使用该表单集创建的 5 个额外字段将填充一个序列值。当用户只想向路线添加 2 或 3 个碱基时,这会导致问题。验证错误弹出,因为该表单的必填字段“base”为空。我可以在表单集发布后运行一些代码,检查是否存在碱基,如果不存在,则删除序列,但如果我要这样做,我可能会嗯……

    在 POST 表单集时运行一些代码,检查是否输入了 Base,如果是,则添加一个序列,如果没有,则将该字段留空。这样,当您尝试.save() 表单集时,空值确保该特定表单不会放入数据库中。唯一的问题是,在我运行 .save(commit=False) 之前我无法对表单做任何事情,因为表单集没有验证,所以我不能这样做。但我可以...

    通过复制request.POST 变量并手动设置序列来添加序列值,但这看起来非常老套。

    我也可以从我的RouteBase 字段之一中删除blank=True,但我真的不想这样做。

那我该怎么办呢?

【问题讨论】:

【参考方案1】:
newPOST = request.POST.copy()
i=1
for index in range(0, int(request.POST["routebase_set-TOTAL_FORMS"])-1):
    if request.POST["routebase_set-" + str(index) + "-base"]:
        newPOST["routebase_set-" + str(index) + "-sequence"] = i
        i += 1
    else:
        newPOST["routebase_set-" + str(index) + "-sequence"] = ""

老实说,这似乎比任何搞砸表单验证都要好。它也没有我想象的那么 hacky...

【讨论】:

-1 这很丑。表单验证方法更简单、更清晰。【参考方案2】:

如果您从不打算让用户编辑序列字段并计划始终在后端计算其值,您可以exclude it from the form,而不是隐藏它。

然后您可以使用 commit=False 并根据需要处理您的序列字段的计算。

【讨论】:

这似乎不起作用。我排除哪些字段并不重要,如果没有序列,表单将不会验证,因此不会.save(commit=False) 您需要在模型中为该字段设置 blank=True。由于您负责自己(而不是用户)生成该值,因此您不需要对其进行表单验证。

以上是关于动态填充表单集中的字段的主要内容,如果未能解决你的问题,请参考以下文章

表单未预先填充Angular 8

Django 表单集中每个表单的不同初始数据

使用来自 javascript 的返回值自动填充隐藏的表单字段

为啥 Chrome 不缓存我的动态表单字段?

如何使laravel中的动态表单字段可填写

Rails 4 - 根据嵌套形式的第一个选择菜单中的选择动态填充第二个选择菜单