Django Crispy 表单 - 更新视图的内联表单集“ManagementForm 数据”错误
Posted
技术标签:
【中文标题】Django Crispy 表单 - 更新视图的内联表单集“ManagementForm 数据”错误【英文标题】:Django Crispy forms - inline Formsets 'ManagementForm data' error with update view 【发布时间】:2019-04-22 02:53:17 【问题描述】:晚上好,
我在使用脆的表格 inlineformset 时遇到了问题。我按照以下指南进行操作:
https://github.com/timhughes/django-cbv-inline-formset/blob/master/music/views.py https://django-crispy-forms.readthedocs.io/en/latest/crispy_tag_formsets.html#formsets
编辑 我认为这个问题与双提交按钮有关。 devicemodel 表单有一个按钮,按下时会产生此错误。但也有一个保存按钮作为资源助手的一部分,当提交时我得到一个空模型表单错误。
我添加了当您操作每个按钮时发生的情况的屏幕截图
而且我收到错误时一定遗漏了一些东西:
['ManagementForm data is missing or has been tampered with']
这是我的更新视图:
class EditDeviceModel(PermissionRequiredMixin, SuccessMessageMixin, UpdateView):
model = DeviceModel
form_class = DeviceModelForm
template_name = "app_settings/base_formset.html"
permission_required = 'config.change_devicemodel'
success_message = 'Device Type "%(model)s" saved successfully'
def get_success_url(self, **kwargs):
return '#device_models'.format(reverse("config:config_settings"))
def get_success_message(self, cleaned_data):
return self.success_message % dict(
cleaned_data,
model=self.object.model,
)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['title']='Edit Device Model'
if self.request.POST:
context['formset'] = DeviceFormSet(self.request.POST, instance=self.object)
else:
context['formset'] = DeviceFormSet(instance=self.object)
context['helper'] = DeviceFormSetHelper()
return context
def form_valid(self, form):
context = self.get_context_data()
formset = context['formset']
if formset.is_valid():
self.object = form.save()
formset.instance = self.object
formset.save()
return redirect(self.success_url)
else:
return self.render_to_response(self.get_context_data(form=form))
这是我的表格:
class MonitoredResourceForm(forms.ModelForm):
class Meta:
model = MonitoredResource
fields = ['resource','model']
def __init__(self, *args, **kwargs):
self.is_add = kwargs.pop("is_add", False)
super(MonitoredResourceForm, self).__init__(*args, **kwargs)
self.helper = FormHelper(self)
self.helper.form_id = 'snmp_resource_form'
self.helper.form_method = 'POST'
self.helper.layout = Layout(
Div(
Div(
Field('model'),
Field('resource', placeholder="Resource"),
css_class='col-lg-3'
),
css_class='row'
),
Div(
Div(
HTML("""<input type="submit" name="submit" value="""),
HTML('"Add' if self.is_add else '"Update' ),
HTML(""" monitored resource" class="btn btn-primary"/>"""),
HTML("""<a href="% url 'config:config_settings' %#monitored_resources" class="btn btn-primary">Cancel</a>"""),
HTML("""% if object %
<a href="% url 'config:delete_monitoredresource' object.id %"
class="btn btn-danger">
Delete <i class="fa fa-trash-o" aria-hidden="true"></i></a>
% endif %"""),
css_class='col-lg-12'
),
css_class='row'
),
)
class DeviceModelForm(forms.ModelForm):
class Meta:
model = DeviceModel
fields = ['model','vendor','device_type','ports','uplink_speed']
def __init__(self, *args, **kwargs):
self.is_add = kwargs.pop("is_add", False)
super(DeviceModelForm, self).__init__(*args, **kwargs)
self.helper = FormHelper(self)
self.helper.form_id = 'device_type_form'
self.helper.form_method = 'POST'
self.helper.layout = Layout(
Div(
Div(
Field('model', placeholder="Model"),
Field('vendor',),
Field('device_type',),
Field('ports', placeholder="Ports"),
Field('uplink_speed', placeholder="Uplink Speed"),
css_class='col-lg-6'
),
css_class='row'
),
Div(
Div(
HTML("""<input type="submit" name="submit" value="""),
HTML('"Add' if self.is_add else '"Update' ),
HTML(""" Device Model" class="btn btn-primary"/>"""),
HTML("""<a href="% url 'config:config_settings' %#device_models" class="btn btn-primary">Cancel</a>"""),
HTML("""% if object %
<a href="% url 'config:delete_device_model' object.id %"
class="btn btn-danger">
Delete <i class="fa fa-trash-o" aria-hidden="true"></i></a>
% endif %"""),
css_class='col-lg-12'
),
css_class='row'
),
)
DeviceFormSet = inlineformset_factory(DeviceModel, MonitoredResource, form=MonitoredResourceForm, extra=1)
class DeviceFormSetHelper(FormHelper):
def __init__(self, *args, **kwargs):
super(DeviceFormSetHelper, self).__init__(*args, **kwargs)
self.form_method = 'post'
self.render_required_fields = True
self.form_id = 'snmp_resource_form'
self.form_method = 'POST'
self.add_input(Submit("submit", "Save"))
self.layout = Layout(
Div(
Div(
Field('model'),
Field('resource', placeholder="Resource"),
css_class='col-lg-6'
),
css_class='row'
),
)
在我渲染的模板中:
% block content %
% include "home/form_errors.html" %
<div class="col-lg-6">
% crispy form %
</div>
<div class="col-lg-6">
% crispy formset helper %
</div>
<!-- /.row -->
% endblock %
有人能看到我遗漏了什么吗?
【问题讨论】:
如果可以的话,在某个地方分享你的项目代码。 【参考方案1】:我遇到了同样的问题,在documentation找到了答案:
formset.management_form|crispy
% for form in formset %
% crispy form %
% endfor %
【讨论】:
【参考方案2】:您的问题是表单集中的每个表单都有自己的management_form
。我没有在脆皮中专门处理这个问题,但在一般的表格中,这就是我遇到的问题。您必须通过迭代或硬编码手动拼出表单集的每一部分,并确保每个部分都有其management_form
。
【讨论】:
【参考方案3】:我认为您必须在模板中呈现管理表单,explained here why you need that
表单集使用管理表单来管理表单集中包含的表单集合。如果您不提供此管理数据,则会引发异常
在视图 html 中添加这个
DeviceFormSet.management_form
【讨论】:
如何解决我当前的问题?我尝试将 formset.management_form 添加到模板中,但没有成功 我添加了我的 DeviceForm 和 MonitoredResourceForm,我认为这可能与它为每个模型创建单独的表单和提交有关? 能分享一下你使用的Django版本吗? 我使用的是 1.11.9 版本 @AlexW 你有没有像 DeviceFormSet.management_form 一样在模板中添加它?如果没有,请尝试根据更新答案添加它。【参考方案4】:你缺少一个标签,还有 format.management_form|crispy 我猜
【讨论】:
在父表单中包含一个带有 post 方法的表单标签总是很好的。管理表单是必须的 什么标签?根据我从脆皮文件中的理解,它是正确的吗? django-crispy-forms.readthedocs.io/en/latest/… 我添加了我的 DeviceForm 和 MonitoredResourceForm,我认为这可能与它为每个模型创建单独的表单和提交有关?以上是关于Django Crispy 表单 - 更新视图的内联表单集“ManagementForm 数据”错误的主要内容,如果未能解决你的问题,请参考以下文章
使用 Django 模型表单 + 表单向导 + Crispy - 不进行第二步
使用内联表单在 django-crispy-forms 中呈现字段错误