gpt4 book ai didi

python - Django 删除 UpdateView 中的内联表单集记录

转载 作者:行者123 更新时间:2023-11-30 23:01:10 25 4
gpt4 key购买 nike

我有一个 UpdateView,其中包含一个表单和一个与表单模型相关的 InlineFormetSet(我简化了下面的代码):

#models.py
class Note(Model):
content = models.TextField()

class Dialog(Model):
message = models.TextField()
note = modes.ForeignKey(Note)


#views.py
class NoteUpdateView(UpdateView):
model = Note
form_class = NoteForm

def get_context_data(self, **kwargs):
context = super(NoteUpdateView ,self).get_context_data(**kwargs)
self.object = self.get_object()
dialogFormset = inlineformset_factory(Note,
Dialog,
fields='__all__',
extra=0)
dialog = dialogFormset(instance=self.object)
context['dialog'] = dialog
return context

def post(self, request, *args, **kwargs):
form = self.get_form(self.get_form_class())
dialog_form = DialogFormset(self.request.POST, instance=Note.objects.get(id=self.kwargs['pk']))

if (form.is_valid() and dialog_form.is_valid()):
return self.form_valid(form, result_form, dialog_form)
else:
return self.form_invalid(form, result_form, dialog_form)

def form_valid(self, form, result_form, dialog_form):
self.object, created = Note.objects.update_or_create(pk=self.kwargs['pk'], defaults=form.cleaned_data)
dialog_form.save()
return HttpResponseRedirect(self.get_success_url())


def form_invalid(self, form, result_form, dialog_form):
return self.render_to_response(self.get_context_data(form=form,
result_form=result_form,
dialog_form=dialog_form))

NoteUpdateView的目的是渲染现有的NoteDialogGET请求发送至note/11 。用户可以删除现有的 Dialog ,上面的代码没有处理它。

要处理删除,我可以在 POST 上执行以下操作:

1) 获取与请求相关的所有对话记录 注意: 对话框 = Note.objects.filter(pk=self.kwargs['pk'])

2) 循环遍历 self.request.POST 并查看提交数据中包含的表单集是否也存在于 dialogs 中。上面创建的。

3) 如果一条记录是dialogs但未通过 POST 提交,则该对话框被视为已被用户删除。至此,执行删除操作。

我确信我可以实现这些步骤。但由于我对Django的formset不是很熟悉。我想知道是否应该使用任何内置类或方法来自动化这些步骤。执行我刚才描述的操作的 Django 方式 是什么?

最佳答案

好的,我知道问题出在哪里了。我遇到的问题是由于使用 django-crispy-forms 造成的。让我解释一下发生了什么:

Django 渲染时 InlineFormSet ,是 can_delete attribute设置为True automatically 。当此属性设置为 True 时,隐藏的输入字段将插入到呈现的 HTML 中:

<input type="hidden" name="dialog_set-0-DELETE" id="id_dialog_set-0-DELETE">

我用过django-crispy-forms渲染我的表单,使其样式为 bootstrap3 。使用 Cripy-Forms 渲染 inlineformset 时, FormHelper 需要定义。

这是因为当页面上有多个 inlineformset 表单时,您只需要一个 <form>标签包围它们,而不是为每个 inlineformset 提供它自己的形式 <form>标签。为此,我必须定义 FormHelper像这样:

#models.py
class Dialog(Model):
info1 = models.TextField()
info2 = models.TextField()

#forms.py
class DialogFormSetHelper(FormHelper):
def __init__(self, *args, **kwargs):
super(DialogFormSetHelper, self).__init__(*args, **kwargs)
self.form_tag = False # This line removes the '<form>' tag
self.disable_csrf = True # No need to insert the CSRF string with each inlineform
self.layout = Layout(
Field('info1', rows='3'), # make sure the name of the field matches the names defined in the corresponding model
Field('info2', rows='3')
)

我需要django-crispy-forms将文本区域标记的行号设置为 3。因此,我必须专门重新定义我的文本区域字段在 Layout 下的外观。 。使用 Layout 时我没有意识到什么就是您未在其中定义的任何内容都不会在 HTML 中呈现。

从代码的外观来看,我没有错过 Dialog 中定义的任何字段。模型。但是,我没有意识到,InlineFormSet 附带的隐藏字段不会在 HTML 中呈现,除非我在 Layout 对象和模板中专门定义它们。为了使表单集和内联表单集正常工作,您将需要以下隐藏输入:

  1. formset.manageform 。它们在 HTML 中看起来像这样:

    <input id="id_dialog_set-TOTAL_FORMS" name="dialog_set-TOTAL_FORMS" type="hidden" value="1">
    <input id="id_dialog_set-INITIAL_FORMS" name="dialog_set-INITIAL_FORMS" type="hidden" value="1">
    <input id="id_dialog_set-MIN_NUM_FORMS" name="dialog_set-MIN_NUM_FORMS" type="hidden" value="0">
    <input id="id_dialog_set-MAX_NUM_FORMS" name="dialog_set-MAX_NUM_FORMS" type="hidden" value="1000">
  2. The primary key that is associated with each inlineformset form, and a foreign key that the inlineformset refers to 。它们在 HTML 中看起来像这样:

    <input id="id_dialog_set-0-note" name="dialog_set-0-note" type="hidden" value="11">  <!-- This line identifies the foreign key`s id -->
    <input id="id_dialog_set-0-id" name="dialog_set-0-id" type="hidden" value="4"> <!-- This line identifies the inlineformset form`s id -->
  3. [can_delete 设置为 True 时删除隐藏字段] ( https://docs.djangoproject.com/en/1.9/topics/forms/formsets/#can-delete )。在 HTML 中看起来像这样:

    <input type="hidden" name="dialog_set-0-DELETE" id="id_dialog_set-0-DELETE"> 

在我的模板中,我涵盖了前两个:

<form method="post" action="{{ action }}" enctype="multipart/form-data" id="note_form">
{% crispy form %}

{# the management_form is covered here #}
{{ dialog.management_form }}

{% for form in dialog %}
<div class="formset-container">
<div class="dialog-title">
{% crispy form dialogHelper %}
</div>

{# the hidden fields are covered here #}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}

</div>
{% endfor %}
</form>

我没有的是DELETE隐藏输入。要将其添加到 HTML,我必须在 Layout 中以这种方式添加它:

#forms.py
class DialogFormSetHelper(FormHelper):
def __init__(self, *args, **kwargs):
super(DialogFormSetHelper, self).__init__(*args, **kwargs)
self.form_tag = False
self.disable_csrf = True
self.layout = Layout(
Field('info1', rows='3'),
Field('info2', rows='3'),
Field('DELETE') # <- ADD THIS LINE
)

现在一切正常

关于python - Django 删除 UpdateView 中的内联表单集记录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34992146/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com