【问题标题】:Cannot edit fields of django's formets empty_form in views无法在视图中编辑 django 表单 empty_form 的字段
【发布时间】:2021-09-12 02:46:38
【问题描述】:

我正在使用 Django 的 BaseFormset 中的 empty_forms 来动态地将内联表单附加到父级。适用于编辑/创建视图。

但是现在我需要从本质上实现一个 DuplicateView。我基本上使用的是 CreateView,在 get_context_data() 中对其进行调整,以使用要复制的对象填充它。像这样的:

def get_context_data(self, **kwargs):
    ctx = super().get_context_data(**kwargs)
    self.object = self.model.objects.get(pk=self.kwargs["pk"])
    logger.info(f"ProduitDuplicateView.get_context_data - object id/code: {self.object.pk} {self.object.no_prod}")
    if self.request.POST:
        # code
    else:
        ctx["form"] = ProduitForm(instance=self.object)
        fourprodfrmset = FourProdFormSet(instance=self.object)
        casefrmset = CaseFormSet(instance=self.object)

我确实需要将实例设置为 self.object,因为我想填充现有的内联表单,以便使用相关数据复制基础对象。但是,该内联表单包含一个指向父对象的外键,默认设置为父对象的 pk 值。对于表单实例,我将其设置为 none,如下所示:

    for f in formset:
        try:
            f.initial.pop("fk_produit")
            f.fields["fk_produit"].initial = None
        except KeyError as ex:
            logger.info(f"There was no fk_produit in form.initial for this form of the formset")

这适用于表单实例。但是,我还需要对 empty_form 执行相同操作 - 否则,当我将 emtpy_form 附加到我的内联表单集时,它会设置为基础对象的 pk。这意味着以这种方式保存新的内联表单会导致错误(类似于“内联表单的 id 与父表单的 id 不同”)。

所以我尝试这样设置:

for formset in [fourprodfrmset, casefrmset]:
    try:
        formset.empty_form.fields["fk_produit"].initial = None
    except KeyError as ex:
        logger.info(f"Couldn't remove fk_produit initial value in formset empty_form")

但是,由于某种原因,它没有任何效果 - 如果我在方法结束时调试它,formset 的 emtpy_form 字段“fk_produit”仍然有它的基础值(例如基础对象的值) )。

那么.....我如何修改 empty_form 字段的值?最好在视图中,因为那是我处理所有这些恶作剧的地方。

我想我当然可以按模板来做,但这需要更多的工作......我真的更热衷于在视图中处理它。有什么想法吗?

【问题讨论】:

    标签: django forms view


    【解决方案1】:

    事实证明,问题的症结在于这个问题有些误导 - 要实现重复,有更好的方法。有关详细信息,请参阅django forums 上的此帖子。

    本质上,您的 DuplicateView 可以从您的 CreateView 继承(甚至可能使用相同的模板)。那么关键位是这样的:

    myformset.management_form.initial["INITIAL_FORMS"] = 0     # otherwise, django saves the loaded ones in-place in the DB instead of creating new fouprods for this one
    

    基本上,django 对待 INITIAL_FORMS 的方式与您在保存它们时通过 ajax 动态添加的任何表单有所不同。它尝试使用初始对象更新数据库中的对象,同时为较新的对象创建一些对象。因此,我本质上是用基础对象中的表单填充第一个表单(例如复制内联表单),但是我用这些行告诉 django 它们都是新表单。因此,它将它们保存为实际实例,并按应有的方式引用新创建对象的 PK

    至于狭隘的问题(以防有人真的需要这样做),没有好的 django 方法。 empty_form 是一堆无法直接编辑的访问器和属性。如果您真的想这样做,我想您需要重新编写渲染器的部分内容(以便最终的 html 更改)。我不会碰那个。

    更好的解决方案是在模板中 - 类似于:

     {% if field.auto-id=="id_mymodel-__prefix__-fk_fieldname" %}
        <input type="hidden" name="mymodel-__prefix__-fk_fieldname" id="id_mymodel-__prefix__-fk_fieldname">
    {% else %}     
        # regular code    
    {% endif %}
    

    所以本质上,找到这个foreign_key对应的字段,然后手动写html标签,省略value=""部分。

    【讨论】:

      猜你喜欢
      • 2021-08-04
      • 2018-10-06
      • 2018-02-17
      • 1970-01-01
      • 1970-01-01
      • 2011-02-22
      • 2018-12-06
      • 1970-01-01
      • 2019-09-08
      相关资源
      最近更新 更多