我有一个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>
答案 0 :(得分: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)的评论的启发。
答案 1 :(得分:-1)
所有简单的堆栈跟踪说:“对象resume
没有属性name
”
resume = cleaned_data.get('resume')
也许resume
没有清理数据?
尝试打印,或将 pudb 放在那里。
这是例外,因为他是无:
resume_ext = resume.name.lower().split('.')[1]