问题描述: 我正在构建一个表单集,以显示我的模型中的所有数据并进行编辑。我的视图已正确渲染,并显示了保存在模型中的正确数据。但是在POST上,我遇到一个异常,指出“ ManagementForm数据丢失或已被篡改”。我想知道为什么会这样。完整的代码和跟踪信息如下。
我的模型:
class ProcedureTemplate(models.Model):
templid = models.AutoField(primary_key=True, unique=True)
title = models.CharField(max_length=200)
description = models.CharField(max_length=5000, default='', blank=True)
clinic = models.ForeignKey(Clinic, on_delete=models.CASCADE)
def __str__(self):
return f'{self.description}'
class SectionHeading(models.Model):
procid = models.AutoField(primary_key=True, unique=True)
name = models.CharField(max_length=200)
default = models.CharField(max_length=1000)
sortorder = models.IntegerField(default=1000)
fieldtype_choice = (
('heading1', 'Heading1'),
('heading2', 'Heading2'),
)
fieldtype = models.CharField(
choices=fieldtype_choice, max_length=100, default='heading1')
template = models.ForeignKey(ProcedureTemplate, on_delete=models.CASCADE, null=False)
def __str__(self):
return f'{self.name} [{self.procid}]'
我的表单:
class ProcedureCrMetaForm(ModelForm):
class Meta:
model = SectionHeading
fields = [
'name',
'default',
'sortorder',
'fieldtype'
]
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['name'].widget.attrs.update({'class': 'form-control'})
self.fields['default'].widget.attrs.update({'class': 'form-control'})
self.fields['sortorder'].widget.attrs.update({'class': 'form-control'})
self.fields['fieldtype'].widget.attrs.update({'class': 'form-control'})
ProcedureCreationFormset = formset_factory(ProcedureCrMetaForm, extra=3)
ProcedureModificationFormset = modelformset_factory(SectionHeading, ProcedureCrMetaForm,
fields=('name', 'default', 'sortorder','fieldtype'),
# widgets={"name": Textarea()}
)
我的观点:
def procedure_template_modification_alt(request, cliniclabel, template_id):
msg = ''
clinicobj = Clinic.objects.get(label=cliniclabel)
template_id = int(template_id)
template= ProcedureTemplate.objects.get(templid = template_id)
formset = ProcedureModificationFormset(queryset=SectionHeading.objects.filter(template = template))
if request.method == 'POST':
print(request.POST.get)
# Create a formset instance with POST data.
formset = ProcedureModificationFormset(request.POST)
if formset.is_valid():
print("Form is valid")
else:
print("Form is invalid")
# Assuming all is valid, save the data.
instances = formset.save()
print(instances)
template= ProcedureTemplate.objects.get(templid = template_id)
headings = SectionHeading.objects.filter(template = template)
return render(request, 'procedures/create_procedure_formset_alt.html',
{
'template': template,
'formset': formset,
'headings': headings,
'msg': msg,
'rnd_num': randomnumber(),
})
我的模板:
{% block content %}
{% load widget_tweaks %}
<div class="container">
{% if user.is_authenticated %}
<div class="row my-1">
<div class="col-sm-2">Name</div>
<div class="col-sm-22">
<input type="text" name="procedurename" class="form-control" placeholder="Enter name of procedure (E.g. DNE)" value="{{ template.title }}" />
</div>
</div>
<div class="row my-1">
<div class="col-sm-2">Description</div>
<div class="col-sm-22">
<input type="text" name="proceduredesc" class="form-control" placeholder="Enter description of procedure (E.g. Diagnostic Nasal Endoscopy)" value="{{ template.description }}" />
</div>
</div>
<form action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
<div class="row mt-3">
<div class="col-sm-1">Select</div>
<div class="col-sm-6">Heading</div>
<div class="col-sm-8">Default (Normal description)</div>
<div class="col-sm-2">Sort Order</div>
<div class="col-sm-4">Type</div>
<div class="col-sm-2">Action</div>
</div>
{% for form in formset %}
<div class="col-sm-6">
{{ form.name }}
</div>
<div class="col-sm-8">
<div class="input-group">
{{ form.default }}
</div>
</div>
<div class="col-sm-2">
<div class="input-group">
{{ form.sortorder }}
</div>
</div>
<div class="col-sm-4">
<div class="input-group">
{{ form.fieldtype }}
</div>
</div>
<div class="col-sm-2">
<div class="input-group">
<div class="input-group-append">
<button id="add{{ forloop.counter0 }}" class="btn btn-success add-row">+</button>
</div>
<div class="input-group-append">
<button id="del{{ forloop.counter0 }}" class="btn btn-danger del-row">-</button>
</div>
</div>
</div>
</div>
{% endfor %}
{% endif %}
<div class="row my-3">
<div class="col-sm-8"></div>
<div class="col-sm-8">
<div class="input-group">
<div class="input-group-append mx-1">
<button id="save_report" type="submit" class="btn btn-success"><i class="fal fa-shield-check"></i> Save Report Format</button>
</div>
<div class="input-group-append mx-1">
<button id="save_report" type="button" class="btn btn-danger"><i class="fal fa-times-hexagon"></i> Cancel</button>
</div>
</div>
</div>
<div class="col-sm-8"></div>
</div>
</form>
</div>
{% endblock %}
完整跟踪:
[02/Feb/2019 22:59:16] "POST /clinic/joelent/procedures/template/modify/3 HTTP/1.1" 500 99735
[02/Feb/2019 22:59:17] "GET /favicon.ico/ HTTP/1.1" 200 14
<bound method MultiValueDict.get of <QueryDict: {'csrfmiddlewaretoken': ['7G5XVYRwt3LsrL9oXr9yOeaIU6HLYwu9cJtE8UpVB3R67Lb7oU8QXQ5kzfBJDJSP'], 'form-0-name': ['External ear canal'], 'form-0-default': ['Bilateral external ear canals appear normal. No discharge.'], 'form-0-sortorder': ['100'], 'form-0-fieldtype': ['heading1'], 'form-1-name': ['Tympanic membrane'], 'form-1-default': ['Tympanic membrane appears normal. Mobility not assessed.'], 'form-1-sortorder': ['500'], 'form-1-fieldtype': ['heading1'], 'form-2-name': [''], 'form-2-default': [''], 'form-2-sortorder': ['1000'], 'form-2-fieldtype': ['heading1']}>>
2019-02-02 23:04:03,415 django.request ERROR Internal Server Error: /clinic/joelent/procedures/template/modify/3
Traceback (most recent call last):
File "/home/joel/.local/lib/python3.6/site-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File "/home/joel/.local/lib/python3.6/site-packages/django/core/handlers/base.py", line 126, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/home/joel/.local/lib/python3.6/site-packages/django/core/handlers/base.py", line 124, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/joel/myappointments/clinic/views.py", line 5664, in procedure_template_modification_alt
if formset.is_valid():
File "/home/joel/.local/lib/python3.6/site-packages/django/forms/formsets.py", line 301, in is_valid
self.errors
File "/home/joel/.local/lib/python3.6/site-packages/django/forms/formsets.py", line 281, in errors
self.full_clean()
File "/home/joel/.local/lib/python3.6/site-packages/django/forms/formsets.py", line 322, in full_clean
for i in range(0, self.total_form_count()):
File "/home/joel/.local/lib/python3.6/site-packages/django/forms/formsets.py", line 110, in total_form_count
return min(self.management_form.cleaned_data[TOTAL_FORM_COUNT], self.absolute_max)
File "/home/joel/.local/lib/python3.6/site-packages/django/utils/functional.py", line 37, in __get__
res = instance.__dict__[self.name] = self.func(instance)
File "/home/joel/.local/lib/python3.6/site-packages/django/forms/formsets.py", line 92, in management_form
code='missing_management_form',
django.core.exceptions.ValidationError: ['ManagementForm data is missing or has been tampered with']
答案 0 :(得分:1)
表单集的问题在于您不知道表单集将包含多少个表单。表单集通常附带一些Javascript,以允许添加新表单或删除旧表单。需要管理表格来跟踪这些更改。
如果您未包含管理表单或该表单与POST数据不匹配,则将引发您遇到的异常。要解决此问题,只需提供管理表格即可。
管理表单可用作表单集的属性 本身。在模板中呈现表单集时,可以包括所有 通过呈现 {{my_formset.management_form}} 来管理数据 (替换为您的表单集的名称)。
因此,在您的模板中只需添加管理表单即可:
<form action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ formset.management_form }}
{# Your formset rendering... #}
</form>