使用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
,但这只是一个空列表:[]
任何人都可以看到我做错了会使对象无法从数据库中删除吗?
答案 0 :(得分:6)
让您感到困惑的是formset.save(commit=False)
没有按照您的想法行事。
虽然设置了commit=False
,但编辑的对象不是save()
d,令人困惑的是,已删除的对象会被删除。
因此,当您在调用marked_for_delete
后循环save(commit=False)
时,您将获得已被删除的对象,因此None
为其ID。
你的自我回答是更好,更恰当的Django发生了;一般情况下,应该只调用formset.save()
并将其默认为commit=True
。 commit=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初始化为什么。