Django modelformset_factory删除标记为删除的模型

时间:2012-03-05 20:43:49

标签: django django-forms

使用modelformset_factory时如何从数据库中删除在表单中标记为删除的对象?

我像这样创建我的modelformset_factory:

ItemFormset = modelformset_factory(Item, ItemModelForm, extra=1, can_delete=True)
qset = Item.objects.filter(pr=pr)
formset = ItemFormset(queryset=qset)

当表单集在POST中返回时,我得到如下数据:

if request.method == "POST":
    formset = ItemFormset(request.POST,queryset=qset)
    if  formset.is_valid():
        marked_for_delete = formset.deleted_forms
        instances = formset.save(commit=False)
        for item in instances:
            item.pr = pr
            item.save()

当formset返回时,我可以使用formset.deleted_forms获取标记为要删除的所有对象,但我无法弄清楚如何实际删除它们。我已尝试循环遍历每个并单独删除每个但我收到错误:Item object can't be deleted because its id attribute is set to None.

在模板中,我包含{{form.id}},因此每个对象都会在POST中传回它的ID。

致电instances = formset.save(commit=False)后,我可以致电formset.deleted_objects,但这只是一个空列表:[]

任何人都可以看到我做错了会使对象无法从数据库中删除吗?

2 个答案:

答案 0 :(得分:6)

让您感到困惑的是formset.save(commit=False)没有按照您的想法行事。

虽然设置了commit=False,但编辑的对象不是save() d,令人困惑的是,已删除的对象会被删除。

因此,当您在调用marked_for_delete后循环save(commit=False)时,您将获得已被删除的对象,因此None为其ID。

你的自我回答是更好,更恰当的Django发生了;一般情况下,应该只调用formset.save()并将其默认为commit=Truecommit=False案例相对罕见和废弃的事实可能就是没有人修复删除对象的(IMO,buggy)行为的原因。

(顺便说一句,我只在非事务性/ AutoCommit数据库环境中观察到这种行为;它可能是commit=False并且启用了事务,您可以获得更强大的删除行为。)

P.S。 - 这种行为在Django 1.7中已经更改

  

“如果你调用formset.save(commit = False),对象将不会被自动删除。你需要在每个formset.deleted_object上调用delete()来实际删除它们。”

答案 1 :(得分:3)

通过在ItemModelForm中包含Item模型中的所有字段,我能够调用formset.save()并且表单中标记为删除的所有模型都将被删除,并且修改或添加的任何模型都会得到更新或保存。我将字段'pr'(外键)包含为HiddenInput并通过扩展ItemModelForm来初始化它,如下所示:

class EnhancedItemForm(ItemModelForm):
    def __init__(self, *args, **kwargs):
        super(EnhancedItemForm, self).__init__(*args, **kwargs)
        self.fields['pr'].widget = forms.HiddenInput()
        self.fields['pr'].initial = pr
ItemFormset = modelformset_factory(Item, EnhancedItemForm, extra=extra_forms, can_delete=True)
formset = ItemFormset(queryset=qset)

然后我能够像这样处理帖子:

if request.method=="POST":
    formset = ItemFormset(request.POST)
    if formset.is_valid():
        # Save, delete, update ..everything you need in one command:
        instances = formset.save()

        for instance in instances:
            # Make sure the assigned pr hasn't changed
            if instance.pr != pr:
                instance.pr = pr 
                instance.save()

由于modelformset_factory接受ModelForm类而不是modelform的实例,因此我不得不在视图中扩展ItemModelForm,在那里我知道我想要将pr初始化为什么。