Django modelformset\u工厂删除标记为删除的模型表单
使用modelformset_factory时,如何从数据库中删除表单中标记为删除的对象 我创建的modelformset_工厂如下所示:Django modelformset\u工厂删除标记为删除的模型表单,django,django-forms,Django,Django Forms,使用modelformset_factory时,如何从数据库中删除表单中标记为删除的对象 我创建的modelformset_工厂如下所示: ItemFormset = modelformset_factory(Item, ItemModelForm, extra=1, can_delete=True) qset = Item.objects.filter(pr=pr) formset = ItemFormset(queryset=qset) if request.method=="POST":
ItemFormset = modelformset_factory(Item, ItemModelForm, extra=1, can_delete=True)
qset = Item.objects.filter(pr=pr)
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()
当表单集返回帖子时,我得到如下数据:
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.deleted\u forms
获取所有标记为删除的对象,但我不知道如何实际删除它们。我已尝试循环遍历每个对象并逐个删除每个对象,但出现错误:Item对象无法删除,因为其id属性设置为None。
在模板中,我包含了{{form.id}
,因此每个对象都有它的id,并在POST中传回
调用instances=formset.save(commit=False)
后,我可以调用formset.deleted\u objects
,但它只是一个空列表:[]
有人能看到我做错了什么,使对象无法从数据库中删除吗?通过将项目模型中的所有字段包含在ItemModelForm中,我可以调用
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)
然后我可以像这样处理这个帖子:
ItemFormset = modelformset_factory(Item, ItemModelForm, extra=1, can_delete=True)
qset = Item.objects.filter(pr=pr)
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_工厂接受ModelForm类而不是ModelForm的实例,因此我必须在视图中扩展ItemModelForm,在该视图中我知道要将pr初始化为什么 让您困惑的是
formset.save(commit=False)
并没有做您认为它能做的事情
虽然设置了commit=False
时,编辑的对象不会save()
d,但令人困惑的是,删除的对象会被删除
因此,在调用save(commit=False)
后,当您循环调用标记为_for _delete
的时,您得到的对象已经被删除,因此它们的id为None
你的自我回答会更好,更地道;通常,只需调用formset.save()
,并将其默认设置为commit=True
。事实上,commit=False
案例相对较少且被废弃,这可能是没有人修复删除对象的(IMO,bug)行为的原因
(顺便说一句,我只在非事务性/自动提交数据库环境中观察到了这种行为;这可能是由于启用了commit=False
和事务,您在删除方面获得了更健壮的行为。)
注意:这种行为在Django 1.7中已经发生了改变:
如果调用formset.save(commit=False),对象将不会自动删除。您需要对每个formset.deleted_对象调用delete(),才能真正删除它们
我想问题在于commit=False。“公关”是一个模型领域吗?如果是这样,您可以将它映射到HiddenInput,而不是excuding,确保它位于表单集的init()或save()上,尽管使用通常的committeing formset.save()ilvar,但我尝试在HiddenField中将pr添加到表单中,而不是将其排除,现在我可以调用formset.save()
但它只会保存提交的表单,而不会从数据库中删除标记为删除的表单。这也会导致每个未标记为删除的表单出现重复的数据库条目(它不会修改当前条目,它只会创建新条目,而不管对当前条目的修改如何,都会创建新条目)。好的,在隐藏字段中设置pr实际上起到了作用(我不得不从以前的工作中删除一些破坏它的旧javascript),但我不知道如何将pr分配给空表单或额外表单的初始值。当我尝试这样设置时:formset.initial=[{'pr':pr_pk,'quantity':0}]
quantity已初始化,但不是pr。在验证和保存之前,您需要修改formset.data,以避免有人更改隐藏字段值。因此,您根本不需要将其设置为initial(尽管无论小部件类型如何,它都应该工作),我想调用formset.save(commit=False)已经删除了标记为删除的项目。这就是为什么会出现“无”错误。我刚才实现了与您相同的用例,并且调用save(commit=False)并遍历实例,即使有标记为删除的项目,它们也不会导致任何类型的错误。请注意,此行为:如果调用formset.save(commit=False)
,对象将不会自动删除。您需要对每个formset.deleted\u对象调用delete()
,才能真正删除它们