选择POST中出现但未清除数据的小部件值



我的一个表单有一个Select小部件无法正常工作。使用VS代码调试器,我发现数据显示在POST中,而不是cleaned_data中。这是我的代码:

视图.py

def index(request):
if request.method == 'GET':
return render(request, 'quotes/index.html', {
'form': QuoteRequestForm(),
})
elif request.method == 'POST':
form = QuoteRequestForm(request.POST)
# edit 2
pp = pprint.PrettyPrinter(indent=2)
pp.pprint(request.POST)
g_recaptcha_response = request.POST.get('g-recaptcha-response')
ip = get_client_ip(request)
api_response = verify(g_recaptcha_response, ip)
api_response_content = json.loads(str(api_response.content, encoding='utf-8'))
if not api_response_content['success'] or api_response.status_code != 200:
messages.error(request, 'There was an error submitting the form.')
messages.error(request, 'Please prove you are human by clicking the last checkbox and possibly completing a security challenge.')
return render(request, 'quotes/index.html', {'form': form})
if form.is_valid():
quote_request = form.save()
messages.success(request, 'Thank you for submitting a quote request. We will contact you via phone or email within 1-3 business days.')
return redirect('quotes:index')
messages.error(request, 'There was an error submitting the form.')
return render(request, 'quotes/index.html', {
'form': form,
})
return HttpResponseBadRequest()

表单.py

class QuoteRequestForm(forms.ModelForm):
title = forms.MultipleChoiceField(
label='',
choices=Contact.title_choices,
widget=forms.Select(
attrs={
'class': 'form-control',
'data-label': 'Title',
},
),
)
first_name = forms.CharField(
label='',
max_length=35,
widget=forms.TextInput(attrs={
'class': 'form-control',
'placeholder': 'First Name',
}),
)
last_name = forms.CharField(
label='',
max_length=70,
widget=forms.TextInput(attrs={
'class': 'form-control',
'placeholder': 'Last Name',
}),
)
family_first = forms.BooleanField(
required=False,
label='Family Name Is First',
widget=forms.CheckboxInput(),
)
phone = forms.CharField(
label='',
max_length=20,
widget=forms.TextInput(attrs={
'class': 'form-control',
'placeholder': 'Phone',
}),
validators=[RegexValidator(PHONE_REGEX, 'Enter a valid U.S. phone number.')],
)
email = forms.EmailField(
label='',
max_length=200,
widget=forms.TextInput(attrs={
'class': 'form-control',
'placeholder': 'Email',
}),
)
description = forms.CharField(
label='',
max_length=500,
widget=forms.Textarea(attrs={
'class': 'form-control',
'placeholder': 'Summary of Site Contents (please be detailed)nE.g. an attractive home page, an about page, a quote request form, and a portfolio with private submission form and management page.',
'rows': 6,
}),
)
def clean(self):
super().clean()
cleaned_data = self.cleaned_data
cleaned_data['title'] = int(cleaned_data['title'])
try:
cleaned_data['phone'] = PHONE_REGEX.sub(
r'234', cleaned_data['phone']
)
except KeyError:
# 'phone' not in 'cleaned_data'.
# Error handled in RegexValidator.
return cleaned_data
# Retrieve contact first by email, then by phone number.
# If successful, update. Otherwise, create new.
try:
contact = Contact.objects.get(email=cleaned_data['email'])
contact.update(
title=cleaned_data['title'],
first_name=cleaned_data['first_name'],
last_name=cleaned_data['last_name'],
family_first=cleaned_data['family_first'],
phone=cleaned_data['phone'],
)
except Contact.DoesNotExist:
try:
contact = Contact.objects.get(phone=cleaned_data['phone'])
contact.update(
title=cleaned_data['title'],
first_name=cleaned_data['first_name'],
last_name=cleaned_data['last_name'],
family_first=cleaned_data['family_first'],
email=cleaned_data['email'],
)
except Contact.DoesNotExist:
contact = Contact.objects.create(
title=cleaned_data['title'],
first_name=cleaned_data['first_name'],
last_name=cleaned_data['last_name'],
family_first=cleaned_data['family_first'],
email=cleaned_data['email'],
phone=cleaned_data['phone'],
)
cleaned_data['contact'] = contact
return cleaned_data
class Meta:
model = QuoteRequest
fields = [
'title', 'first_name', 'last_name', 'family_first',
'email', 'phone', 'description',
]

型号.py

class Contact(TimestampedModel):
title_choices = [
(0, 'Mx.'),
(1, 'Ms.'),
(2, 'Mrs.'),
(3, 'Mr.'),
(4, 'Dr.'),
]
title = models.PositiveSmallIntegerField(choices=title_choices)
first_name = models.CharField(max_length=35)
last_name = models.CharField(max_length=70)
family_first = models.BooleanField()
phone = models.CharField(max_length=10)
email = models.EmailField(max_length=100)
@classmethod
def create(cls, *args, **kwargs):
pass
def update(self, *args, **kwargs):
pass
class QuoteRequest(TimestampedModel):
contact = models.ForeignKey(Contact, on_delete=models.CASCADE)
description = models.TextField(max_length=500)

提交表格会给我以下错误:

Internal Server Error: /quote/
Traceback (most recent call last):
File "/home/matt/Repositories/example/.env/lib/python3.8/site-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File "/home/matt/Repositories/example/.env/lib/python3.8/site-packages/django/core/handlers/base.py", line 115, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/home/matt/Repositories/example/.env/lib/python3.8/site-packages/django/core/handlers/base.py", line 113, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/matt/Repositories/example/quotes/views.py", line 30, in index
return render(request, 'quotes/index.html', {'form': form})
File "/home/matt/Repositories/example/.env/lib/python3.8/site-packages/django/shortcuts.py", line 19, in render
content = loader.render_to_string(template_name, context, request, using=using)
File "/home/matt/Repositories/example/.env/lib/python3.8/site-packages/django/template/loader.py", line 62, in render_to_string
return template.render(context, request)
File "/home/matt/Repositories/example/.env/lib/python3.8/site-packages/django/template/backends/django.py", line 61, in render
return self.template.render(context)
File "/home/matt/Repositories/example/.env/lib/python3.8/site-packages/django/template/base.py", line 171, in render
return self._render(context)
File "/home/matt/Repositories/example/.env/lib/python3.8/site-packages/django/template/base.py", line 163, in _render
return self.nodelist.render(context)
File "/home/matt/Repositories/example/.env/lib/python3.8/site-packages/django/template/base.py", line 936, in render
bit = node.render_annotated(context)
File "/home/matt/Repositories/example/.env/lib/python3.8/site-packages/django/template/base.py", line 903, in render_annotated
return self.render(context)
File "/home/matt/Repositories/example/.env/lib/python3.8/site-packages/django/template/loader_tags.py", line 150, in render
return compiled_parent._render(context)
File "/home/matt/Repositories/example/.env/lib/python3.8/site-packages/django/template/base.py", line 163, in _render
return self.nodelist.render(context)
File "/home/matt/Repositories/example/.env/lib/python3.8/site-packages/django/template/base.py", line 936, in render
bit = node.render_annotated(context)
File "/home/matt/Repositories/example/.env/lib/python3.8/site-packages/django/template/base.py", line 903, in render_annotated
return self.render(context)
File "/home/matt/Repositories/example/.env/lib/python3.8/site-packages/django/template/loader_tags.py", line 62, in render
result = block.nodelist.render(context)
File "/home/matt/Repositories/example/.env/lib/python3.8/site-packages/django/template/base.py", line 936, in render
bit = node.render_annotated(context)
File "/home/matt/Repositories/example/.env/lib/python3.8/site-packages/django/template/base.py", line 903, in render_annotated
return self.render(context)
File "/home/matt/Repositories/example/.env/lib/python3.8/site-packages/django/template/loader_tags.py", line 62, in render
result = block.nodelist.render(context)
File "/home/matt/Repositories/example/.env/lib/python3.8/site-packages/django/template/base.py", line 936, in render
bit = node.render_annotated(context)
File "/home/matt/Repositories/example/.env/lib/python3.8/site-packages/django/template/base.py", line 903, in render_annotated
return self.render(context)
File "/home/matt/Repositories/example/.env/lib/python3.8/site-packages/django/template/base.py", line 986, in render
output = self.filter_expression.resolve(context)
File "/home/matt/Repositories/example/.env/lib/python3.8/site-packages/django/template/base.py", line 670, in resolve
obj = self.var.resolve(context)
File "/home/matt/Repositories/example/.env/lib/python3.8/site-packages/django/template/base.py", line 795, in resolve
value = self._resolve_lookup(context)
File "/home/matt/Repositories/example/.env/lib/python3.8/site-packages/django/template/base.py", line 857, in _resolve_lookup
current = current()
File "/home/matt/Repositories/example/.env/lib/python3.8/site-packages/django/forms/forms.py", line 308, in non_field_errors
return self.errors.get(NON_FIELD_ERRORS, self.error_class(error_class='nonfield'))
File "/home/matt/Repositories/example/.env/lib/python3.8/site-packages/django/forms/forms.py", line 175, in errors
self.full_clean()
File "/home/matt/Repositories/example/.env/lib/python3.8/site-packages/django/forms/forms.py", line 377, in full_clean
self._clean_form()
File "/home/matt/Repositories/example/.env/lib/python3.8/site-packages/django/forms/forms.py", line 404, in _clean_form
cleaned_data = self.clean()
File "/home/matt/Repositories/example/quotes/forms.py", line 72, in clean
cleaned_data['title'] = int(cleaned_data['title'])
KeyError: 'title'
[29/Jul/2020 22:42:35] "POST /quote/ HTTP/1.1" 500 207974

值得一提的是,我尝试创建一个自定义的Select小部件(一个从Select继承的类,除了在修改后的模板中链接之外什么都不做(,但用Django的Select小程序替换并没有成功。我该如何解决这个问题?重新启动开发服务器也没有让我找到解决方案。感谢您的帮助。

编辑1

index.html

{% extends 'home/base.html' %}
{% block js %}  <!-- reCAPTCHA v2 JS -->
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
{% endblock %}
{% block content %}
<section class="page">
{% if messages %}
<div class="container">
{% include 'home/messages.html' %}
</div>
{% endif %}
<div class="container max-w-480px">
<form method="POST">
<h3 class="h3">{% block title %}Request a Quote{% endblock %}</h3>
{% csrf_token %}
{{ form.non_field_errors }}
{% for field in form.visible_fields %}
{% if field.name == 'title' %}
{{ form.title.errors }}
{{ form.first_name.errors }}
{{ form.last_name.errors }}
{{ form.family_first.errors }}
<div class="name">
{{ form.title }}
{{ form.first_name }}
{{ form.last_name }}
{{ form.family_first.widget }}
{% include 'fields/custom_checkbox.html' with field=form.family_first %}
</div>
{% elif field.name != 'first_name' and field.name != 'last_name' and field.name != 'family_first' %}
{{ field.errors }}
{{ field }}
{% endif %}
{% endfor %}
<div
class="g-recaptcha"
data-sitekey="{{ recaptcha_site_key }}"
data-theme="dark"
></div>
<input class="btn btn-primary form-control" type="submit" value="Submit Request">
</form>
</div>
</section>
{% endblock %}

呈现的HTML

<form method="POST">
<h3 class="h3">Request a Quote</h3>
<input type="hidden" name="csrfmiddlewaretoken" value="nupIoxUpFUm2lqyJcZV5URqPl1VxheIrPp14IPbrg376HwslUrqzNcn7ZJPKU6Zm">
<div class="name">
<select name="title" class="form-control" data-label="Title" autocomplete="off" id="id_title">
<option value="0">Mx.</option>
<option value="1">Ms.</option>
<option value="2">Mrs.</option>
<option value="3">Mr.</option>
<option value="4">Dr.</option>
</select>
<input type="text" name="first_name" class="form-control" placeholder="First Name" maxlength="35" required="" id="id_first_name">
<input type="text" name="last_name" class="form-control" placeholder="Last Name" maxlength="70" required="" id="id_last_name">
<div class="input-group input-group-checkbox" data-target-input="nearest">
<label class="form-control" for="id_family_first">Family Name Is First</label>
<div class="input-group-append">
<input type="checkbox" name="family_first" id="id_family_first">
</div>
</div>
</div>
<input type="text" name="email" class="form-control" placeholder="Email" maxlength="200" required="" id="id_email">
<input type="text" name="phone" class="form-control" placeholder="Phone" maxlength="20" required="" id="id_phone">
<textarea name="description" cols="40" rows="6" class="form-control" placeholder="Summary of Site Contents (please be detailed)
E.g. an attractive home page, an about page, a quote request form, and a portfolio with private submission form and management page." maxlength="500" required="" id="id_description"></textarea><div><small>0/500</small></div>
<!-- reCAPTCHA would be here -->
<input class="btn btn-primary form-control" type="submit" value="Submit Request">
</form>

编辑2

视图.py.中漂亮地打印了request.POST

输出

{ 'csrfmiddlewaretoken': 'fL0n76O27oycoUHbGvOKnD3pPefyJYfcHGCJro54IxjgK0BNoXjegY0HtW9LmQw7',
'description': 'This is a test.',
'email': 'email@example.com',
'first_name': 'Matt',
'g-recaptcha-response': '03AGdBq27KT5kGjvknN9VTcc77Eo7Tg5b-mOSur0jjih8eGr0UYvunA4ExCIgwkkqykOojjfvDb01a-jIzBp2dWm4hUDTh21MU0x8zlDtrMCyu_D4TjfNvmwYvwW6pPDPZmKwM2Qwrc7fEExjdblRh6pTtSSgchsxz7aJV7Es-dlQYxG7AMXehD-j1cRKxqp5tqytWrfohoy6uZGL7J6PlvMiZaGU0VgYT4YKazhtESyiEE95iStIWBCYr0UVrGZGWfCBwh0_uhD4G-zgGmhtA0g23jseg2YU4jACnO5BpG7w9caDfqd8qRWWIV_qaa6lmuRr2E_e_TsmjcA72dHriElwcrapJRpJgUnUBH-oOIORD7U3Qh4thEd5p84UEJBhVfAwUbmoAna_h5E9R-6Vp5J4_Y5nuOR3lYw',
'last_name': 'McCarthy',
'phone': '1234567890',
'title': '3'}

问题似乎是由在MultipleChoiceField上使用Select小部件引起的。你可能不需要多个标题选择,所以用以下内容更新你的表格:

class QuoteRequestForm(forms.ModelForm):
title = forms.ChoiceField(  # this line has changed
label='',
choices=Contact.title_choices,
widget=forms.Select(
attrs={
'class': 'form-control',
'data-label': 'Title',
},
),
)
# other stuff

我之前的回答:

这可能是由于ModelForm.Meta类中的命名字段与QuoteRequest模型上的现有字段不对应。

尝试更新您的ModelForm.Meta以仅包括QuoteRequest型号上存在的字段:

class QuoteRequestForm(forms.ModelForm):
# fields
# clean method
class Meta:
model = QuoteRequest
fields = ['description']

最新更新