【问题标题】:Inline formset returns empty list on save?内联表单集在保存时返回空列表?
【发布时间】:2018-11-27 08:09:43
【问题描述】:

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

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')

【问题讨论】:

    标签: django django-forms formset inline-formset


    【解决方案1】:

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

        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()
    

    【讨论】:

      【解决方案2】:

      为了帮助其他人,他们在 formset 遇到类似问题的地方保存返回空列表,并且在 SO 上没有太多其他内容:

      根据 Django 文档:

      在调用 save() 之后,您的模型表单集将具有三个包含表单集更改的新属性:

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

      new_objects 只是新objs 的列表,即

      [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

      【讨论】:

        猜你喜欢
        • 2016-08-25
        • 2019-09-02
        • 1970-01-01
        • 2020-09-26
        • 1970-01-01
        • 2015-11-01
        • 2016-01-01
        • 1970-01-01
        • 2010-09-30
        相关资源
        最近更新 更多