django - Django:如何在一个模板中为通过外键连接的两个模型正确使用两个表单
问题描述
我有 2 个模型:Applicant
和Application
. Application
通过外键连接到Applicant
。对于任何申请人,都可以有许多申请。
models.py
class Applicant(models.Model):
first_name = models.CharField(max_length=150, null=False, blank=False)
last_name = models.CharField(max_length=150, null=False, blank=False)
email = models.EmailField(blank=False, null=True)
...
class Application(models.Model):
applicant = models.ForeignKey(Applicant, null=False, blank=False, on_delete=models.CASCADE)
...
我无法弄清楚如何让 2 个表单,对于 2 个模型,显示在 1 个模板中,以便在提交时两者Applicant
都Application
可以完全填充和保存。我尝试过 inlineformsets,但我不断收到本质上Application
必须有applicant
实例的错误。然后我尝试只使用两个单独的表单并分别保存它们,但我得到了同样的错误。我该如何纠正?
forms.py
class ApplicantForm(ModelForm):
veterinaryContactPermission = forms.BooleanField(widget=forms.CheckboxInput)
class Meta:
model= Applicant
fields = '__all__'
class ApplicationForm(ModelForm):
class Meta:
model = Application
fields = '__all__'
ApplicantFormset = inlineformset_factory(
Applicant, Application, form=ApplicationForm,
fields=['applicant'], can_delete=False
)
views.py
class ApplicantApplication(CreateView):
model = Applicant
# form1 = ApplicantForm
# form2 = ApplicationForm
form_class = ApplicantForm
template_name = 'animals/register.html'
success_url = reverse_lazy('animals:applicant_profile_complete')
def get_context_data(self, **kwargs):
data = super(ApplicantApplication, self).get_context_data(**kwargs)
data['form_applicant'] = ApplicantFormset()
if self.request.POST:
data['form_applicant'] = ApplicantFormset(self.request.POST, self.request.FILES)
# context = data
else:
data['form_applicant'] = ApplicantFormset()
# context = {'data':data, 'form1': self.form1, 'form2': self.form2}
return data
def form_valid(self, form):
context = self.get_context_data()
form_app = context['form_applicant']
with transaction.atomic():
self.object = form.save()
if form_app.is_valid():
form_app.instance = self.object
form_app.save()
return super(ApplicantApplication, self).form_valid(form)
ValidationError at /animals/register/
['ManagementForm data is missing or has been tampered with']
Request Method: POST
Request URL: http://127.0.0.1:8000/animals/register/
Django Version: 3.1.4
Exception Type: ValidationError
Exception Value:
['ManagementForm data is missing or has been tampered with']
Exception Location: /Users/zb/Desktop/animalDirectoryTemplate/.venv/lib/python3.7/site-packages/django/forms/formsets.py, line 94, in management_form
Python Executable: /Users/zb/Desktop/animalDirectoryTemplate/.venv/bin/python
Python Version: 3.7.1
Python Path:
['/Users/zb/Desktop/animalDirectoryTemplate',
'/Library/Frameworks/Python.framework/Versions/3.7/lib/python37.zip',
'/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7',
'/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/lib-dynload',
'/Users/zb/Desktop/animalDirectoryTemplate/.venv/lib/python3.7/site-packages',
'/Users/zb/Desktop/animalDirectoryTemplate/.venv/lib/python3.7/site-packages/setuptools-39.1.0-py3.7.egg',
'/Users/zb/Desktop/animalDirectoryTemplate/.venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg']
Server time: Mon, 18 Jan 2021 00:50:08 +0000
Traceback Switch to copy-and-paste view
/Users/zb/Desktop/animalDirectoryTemplate/.venv/lib/python3.7/site-packages/django/core/handlers/exception.py, line 47, in inner
response = await sync_to_async(response_for_exception, thread_sensitive=False)(request, exc)
return response
return inner
else:
@wraps(get_response)
def inner(request):
try:
response = get_response(request) …
except Exception as exc:
response = response_for_exception(request, exc)
return response
return inner
▶ Local vars
/Users/zb/Desktop/animalDirectoryTemplate/.venv/lib/python3.7/site-packages/django/core/handlers/base.py, line 179, in _get_response
if response is None:
wrapped_callback = self.make_view_atomic(callback)
# If it is an asynchronous view, run it in a subthread.
if asyncio.iscoroutinefunction(wrapped_callback):
wrapped_callback = async_to_sync(wrapped_callback)
try:
response = wrapped_callback(request, *callback_args, **callback_kwargs) …
except Exception as e:
response = self.process_exception_by_middleware(e, request)
if response is None:
raise
# Complain if the view returned None (a common error).
▶ Local vars
/Users/zb/Desktop/animalDirectoryTemplate/.venv/lib/python3.7/site-packages/django/views/generic/base.py, line 70, in view
return self.dispatch(request, *args, **kwargs) …
▶ Local vars
/Users/zb/Desktop/animalDirectoryTemplate/.venv/lib/python3.7/site-packages/django/views/generic/base.py, line 98, in dispatch
return handler(request, *args, **kwargs) …
▶ Local vars
/Users/zb/Desktop/animalDirectoryTemplate/.venv/lib/python3.7/site-packages/django/views/generic/edit.py, line 172, in post
return super().post(request, *args, **kwargs) …
▶ Local vars
/Users/zb/Desktop/animalDirectoryTemplate/.venv/lib/python3.7/site-packages/django/views/generic/edit.py, line 142, in post
return self.form_valid(form) …
▶ Local vars
/Users/zb/Desktop/animalDirectoryTemplate/animals/views.py, line 321, in form_valid
if form_app.is_valid(): …
▶ Local vars
/Users/zb/Desktop/animalDirectoryTemplate/.venv/lib/python3.7/site-packages/django/forms/formsets.py, line 308, in is_valid
self.errors …
▶ Local vars
/Users/zb/Desktop/animalDirectoryTemplate/.venv/lib/python3.7/site-packages/django/forms/formsets.py, line 288, in errors
self.full_clean() …
▶ Local vars
/Users/zb/Desktop/animalDirectoryTemplate/.venv/lib/python3.7/site-packages/django/forms/formsets.py, line 329, in full_clean
for i in range(0, self.total_form_count()): …
▶ Local vars
/Users/zb/Desktop/animalDirectoryTemplate/.venv/lib/python3.7/site-packages/django/forms/formsets.py, line 112, in total_form_count
return min(self.management_form.cleaned_data[TOTAL_FORM_COUNT], self.absolute_max) …
▶ Local vars
/Users/zb/Desktop/animalDirectoryTemplate/.venv/lib/python3.7/site-packages/django/utils/functional.py, line 48, in __get__
res = instance.__dict__[self.name] = self.func(instance) …
▶ Local vars
/Users/zb/Desktop/animalDirectoryTemplate/.venv/lib/python3.7/site-packages/django/forms/formsets.py, line 94, in management_form
code='missing_management_form', …
▶ Local vars
Request information
USER
zbrenner
GET
No GET data
POST
Variable Value
csrfmiddlewaretoken
'MoRtdL69wHGAiSL2cEX3sTu1ODUtspeH6z86bMMEtjjWr9SIanAkiuiNWdeU8DUk'
first_name
'Z'
last_name
'B'
phone
'644-777-2222'
email
'zbreadkwelkdak@gmail.com'
streetAddress
'8843 all ln'
city
'San Clemente'
state
'CA'
country
'United States'
age
'51'
job
'Physician'
kids
'0'
kidDeets
''
adults
'0'
adultDeets
''
cats
'1'
dogs
'2'
otherAnimals
'0'
animalDeets
''
veterinaryClinic
'Clinic'
veterinaryContactPermission
'on'
veterinaryPhone
'900-444-0000'
homeOwnership
'on'
landlordApproves
'on'
landlordContactPermission
'on'
landlordName
'Landlord'
landlordPhone
'555-444-3333'
hoursAway
'3'
haveBackYard
'on'
yardSizeInAcres
'150'
haveFence
'on'
fenceDeets
'6 Feet Tall, Mixed wire and wood'
yardPhoto
''
housePhoto
''
FILES
No FILES data
COOKIES
Variable Value
sessionid
'2uyil6sff65o46phqvayxewigoy3p01e'
csrftoken
'IFiwj7RpZ998CENmWAbfLJIewayhTEwS2Qz9h8xUWLMuLVU2UjOwBkw0EKSIzScv'
META
Variable Value
Apple_PubSub_Socket_Render
'/private/tmp/com.apple.launchd.zHVr0NmLOt/Render'
BASH_FUNC_generate_command_executed_sequence%%
"() { printf '\\e\\7'\n}"
CONTENT_LENGTH
'655'
CONTENT_TYPE
'application/x-www-form-urlencoded'
CSRF_COOKIE
'IFiwj7RpZ998CENmWAbfLJIewayhTEwS2Qz9h8xUWLMuLVU2UjOwBkw0EKSIzScv'
DJANGO_SETTINGS_MODULE
'animalDirectoryTemplate.settings'
register.html
{% extends 'base.html' %}
{% load static %}
{% load bootstrap %}
{% block head %}
<link rel="stylesheet" href="{% static 'node_modules/bootstrap/dist/css/bootstrap.min.css' %}">
{% endblock %}
{% block content %}
<h2>Application</h2>
<form action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
<table>
{# {{ form1.as_table }}#} {# The only way I've been able to display both forms which means I'm not using formset...? #}
{{ form.as_table }} {# Displays Applicant form #}
</table>
<table>
{{ form_applicant.as_table }} {# Should display Application form but it doesn't. It doesn't display anything visible #}
{# {{ form2.as_table }}#} {# The only way I've been able to display both forms #}
</table>
<input type="submit" value="Submit">
<input type="submit" onclick="window.location='{% url 'animals:animals' %}'; return false;" value="Cancel">
</form>
{% endblock %}
解决方案
您必须添加{{ formset.management_form }}
.
例子:
<form method="post">
{% csrf_token %}
{{ form.as_table }}
<hr>
{{ form_applicant.management_form }}
<table>
{% for form in form_applicant %}
{{ form }}
{% endfor %}
</table>
</form>
额外的
def post(self, request, *args, **kwargs):
"""
Handles POST requests, instantiating a form instance and its inline
formsets with the passed POST variables and then checking them for
validity.
"""
form_class = self.get_form_class()
form = self.get_form(form_class)
form_applicant = ApplicantFormset(self.request.POST, self.request.FILES)
if (form.is_valid() and form_applicant.is_valid()):
return self.form_valid(form)
else:
return self.form_invalid(form)
def form_valid(self, form):
form_applicant = ApplicantFormset(self.request.POST, self.request.FILES)
self.object = form.save()
....
return HttpResponseRedirect(self.get_success_url())
def get_context_data(self, **kwargs):
data = super(ApplicantApplication, self).get_context_data(**kwargs)
data['form_applicant'] = ApplicantFormset()
if self.request.POST:
data['form_applicant'] = ApplicantFormset(self.request.POST, self.request.FILES)
# context = data
else:
data['form_applicant'] = ApplicantFormset()
# context = {'data':data, 'form1': self.form1, 'form2': self.form2}
return data
推荐阅读
- javascript - 当我们在父组件中更改子道具时更新它们
- sql - oracle sql如何组合列字符串值
- python - Ansible 错误:AttributeError:模块“平台”没有属性“dist”
- python - Tkinter 不会将窗口与 pid 关联
- sql - SQL查询根据UNION数据中的列值更新条件
- oracle - AWS 数据管道 - csv(s3) 到 RDS Oracle
- node.js - Docusign Webhooks:错误 - 远程服务器返回错误:(413)请求实体太大
- ssis - 在特定帐户下手动运行 SSIS 包
- c# - 实体框架核心不保存更改(没有主键,一个行表)
- python - tf_gather_nd 和 tensor_scatter_nd_update 批量