Django ModelForm 不显示字段错误
Posted
技术标签:
【中文标题】Django ModelForm 不显示字段错误【英文标题】:Django ModelForm not showing field errors 【发布时间】:2014-04-05 02:46:10 【问题描述】:我有一个没有在模板中正确显示字段错误的 Django ModelForm。我有几个必填字段,以及我认为捕获错误并向用户显示错误的正确逻辑。
提交表单时出现以下错误:
Traceback (most recent call last):
File "/home/thevariable/.virtualenvs/va_jobs/lib/python2.7/site-packages/django/core/handlers/base.py", line 114, in get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/thevariable/.virtualenvs/va_jobs/lib/python2.7/site-packages/django/views/generic/base.py", line 69, in view
return self.dispatch(request, *args, **kwargs)
File "/home/thevariable/webapps/va_jobs/va_jobs/jobs/views.py", line 29, in dispatch
return super(ApplicationCreateView, self).dispatch(*args, **kwargs)
File "/home/thevariable/.virtualenvs/va_jobs/lib/python2.7/site-packages/django/views/generic/base.py", line 87, in dispatch
return handler(request, *args, **kwargs)
File "/home/thevariable/.virtualenvs/va_jobs/lib/python2.7/site-packages/django/views/generic/edit.py", line 205, in post
return super(BaseCreateView, self).post(request, *args, **kwargs)
File "/home/thevariable/.virtualenvs/va_jobs/lib/python2.7/site-packages/django/views/generic/edit.py", line 170, in post
if form.is_valid():
File "/home/thevariable/.virtualenvs/va_jobs/lib/python2.7/site-packages/django/forms/forms.py", line 129, in is_valid
return self.is_bound and not bool(self.errors)
File "/home/thevariable/.virtualenvs/va_jobs/lib/python2.7/site-packages/django/forms/forms.py", line 121, in errors
self.full_clean()
File "/home/thevariable/.virtualenvs/va_jobs/lib/python2.7/site-packages/django/forms/forms.py", line 274, in full_clean
self._clean_form()
File "/home/thevariable/.virtualenvs/va_jobs/lib/python2.7/site-packages/django/forms/forms.py", line 300, in _clean_form
self.cleaned_data = self.clean()
File "/home/thevariable/webapps/va_jobs/va_jobs/jobs/forms.py", line 23, in clean
resume_ext = resume.name.lower().split('.')[1]
AttributeError: 'NoneType' object has no attribute 'name'
这是我的forms.py:
from django.forms import ModelForm
from .models import Application
class ApplicationForm(ModelForm):
class Meta:
model = Application
fields = [
'first_name',
'last_name',
'email_address',
'phone_number',
'salary_requirement',
'resume',
'portfolio_url',
'description',
'can_relocate',
'start_date',
]
def __init__(self, *args, **kwargs):
super(ApplicationForm, self).__init__(*args, **kwargs)
self.fields['first_name'].required = True
self.fields['last_name'].required = True
self.fields['email_address'].required = True
self.fields['phone_number'].required = True
self.fields['salary_requirement'].required = False
self.fields['resume'].required = True
self.fields['portfolio_url'].required = False
self.fields['description'].required = False
self.fields['can_relocate'].required = True
self.fields['start_date'].required = False
def clean(self):
cleaned_data = super(ApplicationForm, self).clean()
resume = cleaned_data.get('resume')
resume_ext = resume.name.lower().split('.')[1]
if not resume_ext in ('pdf', 'doc', 'docx'):
del cleaned_data["resume"]
msg = u"Your file must be a PDF or DOC file type."
raise forms.ValidationError(msg)
#self._errors["resume"] = self.error_class([msg])
return cleaned_data
这是我的看法:
class ApplicationCreateView(CreateView):
model = Application
form_class = ApplicationForm
success_url = 'submitted/'
def dispatch(self, *args, **kwargs):
self.job = get_object_or_404(Job, slug=kwargs['slug'])
return super(ApplicationCreateView, self).dispatch(*args, **kwargs)
def form_valid(self, form):
#Get associated job and save
self.object = form.save(commit=False)
self.object.job = self.job
self.object.save()
# Gather cleaned data for email send
first_name = form.cleaned_data.get('first_name')
last_name = form.cleaned_data.get('last_name')
email_address = form.cleaned_data.get('email_address')
phone_number = form.cleaned_data.get('phone_number')
salary_requirement = form.cleaned_data.get('salary_requirement')
description = form.cleaned_data.get('description')
portfolio_url = form.cleaned_data.get('portfolio_url')
can_relocate = form.cleaned_data.get('can_relocate')
start_date = form.cleaned_data.get('start_date')
resume = self.object.resume
job = self.object.job
#Compose message
email = EmailMessage()
email.body = 'Name: ' + first_name + last_name + '\n' + 'Email: ' + email_address + '\n' + 'Phone number: ' + str(phone_number) + '\n' + 'Salary requirement: ' + str(salary_requirement) + '\n' + 'Description: ' + description + '\n' + 'Portfolio URL: ' + portfolio_url + '\n' + 'Can relocate: ' + str(can_relocate) + '\n' + 'Start date: ' + str(start_date)
email.subject = 'A new application has been submitted for %s' % (job)
email.from_email = 'noreply@abc.com'
email.to = ['jobs@abc.com',]
email.bcc = ['abc@abc.com',]
email.attach(resume.name, resume.read())
email.send()
return HttpResponseRedirect(self.get_success_url())
def get_context_data(self, *args, **kwargs):
context_data = super(ApplicationCreateView, self).get_context_data(*args, **kwargs)
context_data.update('job': self.job)
return context_data
这是我的模板(使用 Django 小部件调整 https://pypi.python.org/pypi/django-widget-tweaks):
<p><em>Note: Fields with an asterisk are required.</em></p>
<form role="form" action="" enctype="multipart/form-data" method="post">
% csrf_token %
% for field in form.visible_fields %
<div class="form-group">
% if field.errors %
<ul class="list-unstyled list-inline">
% for error in field.errors %
<li class="text-warning"><span class="glyphicon glyphicon-warning-sign"></span> error|escape </li>
% endfor %
</ul>
% endif %
field.label_tag
% if field.name == "portfolio_url" %
% if job.portfolio_required % <small><span class="glyphicon glyphicon-asterisk"></span></small>
% endif %
% endif %
% if field.field.required % <small><span class="glyphicon glyphicon-asterisk"></span></small>% endif %
% if field.name == "resume" or field.name == "can_relocate" %
field|add_class:"form-control short"
% elif field.name == "start_date" %
<input id="id_start_date" class="form-control short" name="start_date" type="date" /><input id="initial-id_start_date" name="initial-start_date" type="hidden" />
% elif field.name == "portfolio_url" %
% if job.portfolio_required %
<input class="form-control" id="id_portfolio_url" maxlength="200" name="portfolio_url" type="url" required />
% endif %
% else %
field|add_class:"form-control"
% endif %
% if field.help_text %<p class="help-block"> field.help_text </p>% endif %
</div>
% endfor %
<input type="submit" class="btn btn-default" value="Apply">
</form>
【问题讨论】:
resume
对象由于某种原因正在评估为None
。检查那里的流量。
基本上,如果未设置resume
,则会抛出此错误,请尝试:resume_ext = resume.name.lower().split('.')[1] if resume and resume.name else ''
这也是我的想法。如果我做if cleaned_data.get('resume'):
....else: return cleaned_data
是的.. 这也是干净的解决方案。
【参考方案1】:
为了记录,我的解决方案如下(forms.py
):
def clean(self):
cleaned_data = super(ApplicationForm, self).clean()
if cleaned_data.get('resume'):
resume = cleaned_data.get('resume')
resume_ext = resume.name.lower().split('.')[1]
if not resume_ext in ('pdf', 'doc', 'docx'):
del cleaned_data["resume"]
msg = u"Your file must be a PDF or DOC file type."
self._errors["resume"] = self.error_class([msg])
return cleaned_data
else:
return cleaned_data
这是受到对原始问题 (Django ModelForm not showing field errors) 的评论的启发。
【讨论】:
你是对的。这可以写成self.add_error('resume', msg)
。【参考方案2】:
很简单,在堆栈跟踪中说:“对象resume
没有属性name
”
resume = cleaned_data.get('resume')
也许resume
不在已清理的数据中?
尝试打印它,或将 pudb 放在那里。
这里是例外,因为他是无:
resume_ext = resume.name.lower().split('.')[1]
【讨论】:
不是一个真正的答案。并对此嗤之以鼻。以上是关于Django ModelForm 不显示字段错误的主要内容,如果未能解决你的问题,请参考以下文章
Django - UpdateView ModelForm 在查询集字段上设置初始值
如何在 Django 中向 ModelForm 添加非模型字段?
Django ModelForm booleanfield 必填字段不起作用