内联 formset returns 保存时为空列表?

Inline formset returns empty list on save?

当我尝试保存我的内联表单集时,它只是 returns 一个空列表,数据库中没有反映任何更改。我试过不使用选项和 commit=False 来做,但它们都有相同的结果。我知道有数据,因为我将表单集打印为 table,并且我知道它是有效的,因为 属性 is_valid() 方法 returns 为真。这是代码:

def edit(request):
    if request.method == 'POST':
        print(request.POST)
        form = TombstoneForm(request.POST)
        print(form.is_valid())
        t = form.save(commit=False)
        t.edit_date = datetime.now()
        t.user_editor = request.user
        t.save()
        print(t)
        formset_construct = inlineformset_factory(Tombstone, Tank, form=TombstoneForm)
        formset = formset_construct(request.POST)
        print("Passed the inline formset")
        print(formset.as_table())
        print(formset.is_valid())
        l = formset.save()
        print(l)
    return render(request, 'main.html')

所以我相信我已经找到问题的根源和解决方法。此方法中的 BaseModelFormSet class 中出现问题:

    def save_existing_objects(self, commit=True):
        self.changed_objects = []
        self.deleted_objects = []
        if not self.initial_forms:
            return []

        saved_instances = []
        forms_to_delete = self.deleted_forms
        for form in self.initial_forms:
            obj = form.instance
            # If the pk is None, it means either:
            # 1. The object is an unexpected empty model, created by invalid
            #    POST data such as an object outside the formset's queryset.
            # 2. The object was already deleted from the database.
            if obj.pk is None:
                continue
            if form in forms_to_delete:
                self.deleted_objects.append(obj)
                self.delete_existing(obj, commit=commit)
            elif form.has_changed():
                self.changed_objects.append((obj, form.changed_data))
                saved_instances.append(self.save_existing(form, obj, commit=commit))
                if not commit:
                    self.saved_forms.append(form)
        return saved_instances

问题发生在:

if obj.pk is None:
    continue

它总是点击继续,所以我的解决方案是保存单个表单数据而不是表单集数据:

        for form in formset:
            val = form.save(commit=False)
            val.Vessel = t
            val.save()

为了帮助其他人,他们在 formset save 返回空列表时遇到类似问题,SO 上没有太多其他内容:

根据 Django 文档:

After calling save(), your model formset will have three new attributes containing the formset’s changes:

models.BaseModelFormSet.changed_objects
models.BaseModelFormSet.deleted_objects
models.BaseModelFormSet.new_objects

new_objects 只是新 obj 的列表,即

[obj1, obj2]

changed_objects 是一个元组列表,即

[
    (obj1, [list of field names changed]),
    (obj2, [list of field names changed]),
    ...
]

我遇到了 deleted_objects 总是 [] 的问题。

首先确保您的表单中有所需的隐藏字段:

{% for form in formset %}
    {{ form.id }} # <- have you got this?
    {{ form.DELETE }}
    ...
    {{ form.foo }}
{% endfor %}

其次,当用户选中删除复选框时,我想到了禁用所有字段的好主意。禁用的项目不会发布,因此要删除的项目不会是 PK,如 OP 上面提到的,如果 obj.pk 为空白,则不会将其添加到(.deleted_objects 在这种情况下)列表.解决方案是使用 readonly,在 JavaSript 中使用 .readOnly = true 和 css :read-only.