Django 1.7 request.FILES 'None' 未验证 (is_valid())
Django 1.7 request.FILES 'None' not validated (is_valid())
所以我扩展了用户模型以添加一些字段,但在图像(头像)POST 部分遇到了问题。首先是一个显示用户信息的配置文件页面,以及用于编辑后者的 link。
一旦进入 'editprofile' 页面,表单就会加载并预填充现有数据。上传头像文件后,一切正常。但是当没有上传头像时(无论用户配置文件是否已经有一个),is_valid() 方法会失败,如下所示:
Request Method: POST
Django Version: 1.7.4
Exception Type: TypeError
Exception Value: invalid file: None
Exception location: /usr/local/lib/python3.4/dist-packages/django/core/files/images.py in get_image_dimensions, line 46
我的问题是:如何在 request.FILES 中使用空字段(值 None)通过验证?
这是我的代码。
models.py
from django.db import models
from django.contrib.auth.models import User
from famsite import settings
from sorl.thumbnail import ImageField
class UserProfile(models.Model):
user = models.OneToOneField(User, primary_key=True)
birth_date = models.DateField('Date of birth', null=True)
phone1 = models.CharField('Primary phone', null=True, blank=True, max_length=15)
phone2 = models.CharField('Secondary phone', null=True, blank=True, max_length=15)
address = models.CharField('Address', null=True, blank=True, max_length=256)
avatar = ImageField('Avatar', upload_to='usrprofile/', blank=True)
forms.py
from django import forms
from django.core.files.images import get_image_dimensions
from django.utils.translation import ugettext as u_
from django.forms.extras.widgets import SelectDateWidget
import datetime
from usrprofile.models import UserProfile
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
exclude = ['user']
fields = ['birth_date', 'phone1', 'phone2', 'email', 'address', 'avatar']
birth_date = forms.DateField(widget=SelectDateWidget(years=[y for y in range(1950, datetime.date.today().year)]))
email = forms.EmailField()
def clean_avatar(self):
avatar = self.cleaned_data['avatar']
try:
w, h = get_image_dimensions(avatar)
#validate dimensions
max_width = max_height = 100
if w > max_width or h > max_height:
raise forms.ValidationError(
u_('Please use an image that is '
'%s x %s pixels or smaller.') % (max_width, max_height))
#validate content type
main, sub = avatar.content_type.split('/')
if not (main == 'image' and sub in ['jpeg', 'pjpeg', 'gif', 'png']):
raise forms.ValidationError(u_('Please use a JPEG, '
'GIF or PNG image.'))
#validate file size
if len(avatar) > (20 * 1024):
raise forms.ValidationError(
u_('Avatar file size may not exceed 20k.'))
except AttributeError:
"""
Handles case when we are updating the user profile
and do not supply a new avatar
"""
pass
return avatar
views.py
from django.shortcuts import get_object_or_404, render, render_to_response
from django.http import HttpResponseRedirect, HttpResponseForbidden, HttpResponse
from django.core.urlresolvers import reverse
from django.views import generic
from django import forms
from django.template import RequestContext
from sorl.thumbnail import get_thumbnail
from usrprofile.models import UserProfile
from usrprofile.forms import *
class IndexView(generic.ListView):
model = UserProfile
template_name = 'usrprofile/profile.html'
def edit(request):
user = request.user
if request.method == 'POST':
#deletes old file in case of new file upload
form_aux = UserProfileForm(request.POST, request.FILES)
if form_aux.is_valid() and 'avatar' in request.FILES:
user.userprofile.avatar.delete()
#check if form has changed
#if form has changed, check if form is valid
#if form is valid, save data, associate with userprofile, save data to server
form = UserProfileForm(request.POST, request.FILES)
if form.has_changed():
if form.is_valid():
profile = form.save(commit=False)
profile.user = user
profile.save()
return render_to_response('usrprofile/profile.html', RequestContext(request))
else:
#if GET method, populate form with existing data
profile = user.userprofile
form = UserProfileForm(instance=profile, initial={'email': user.email})
return render_to_response('usrprofile/editprofile.html', RequestContext(request, {'form' : form}))
editprofile.html
{% extends "base.html" %}
{% load i18n %}
<html>
<head>
<title>{% block title %}{% trans "Profile edition" %}{% endblock %}</title>
</head>
<body>
<div id="content">
{% block content %}
<form id="form" method="POST" action="" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" name="submit" value="Save" />
</form>
{% endblock %}
</div>
</body>
</html>
ImageField
没有 required
参数(Django 和 sorl.thumbnail 都没有)。在您的模型定义中,而不是
avatar = ImageField('Avatar', upload_to='usrprofile/', required=False)
尝试
avatar = ImageField('Avatar', upload_to='usrprofile/', blank=True)
所以我扩展了用户模型以添加一些字段,但在图像(头像)POST 部分遇到了问题。首先是一个显示用户信息的配置文件页面,以及用于编辑后者的 link。 一旦进入 'editprofile' 页面,表单就会加载并预填充现有数据。上传头像文件后,一切正常。但是当没有上传头像时(无论用户配置文件是否已经有一个),is_valid() 方法会失败,如下所示:
Request Method: POST
Django Version: 1.7.4
Exception Type: TypeError
Exception Value: invalid file: None
Exception location: /usr/local/lib/python3.4/dist-packages/django/core/files/images.py in get_image_dimensions, line 46
我的问题是:如何在 request.FILES 中使用空字段(值 None)通过验证?
这是我的代码。
models.py
from django.db import models
from django.contrib.auth.models import User
from famsite import settings
from sorl.thumbnail import ImageField
class UserProfile(models.Model):
user = models.OneToOneField(User, primary_key=True)
birth_date = models.DateField('Date of birth', null=True)
phone1 = models.CharField('Primary phone', null=True, blank=True, max_length=15)
phone2 = models.CharField('Secondary phone', null=True, blank=True, max_length=15)
address = models.CharField('Address', null=True, blank=True, max_length=256)
avatar = ImageField('Avatar', upload_to='usrprofile/', blank=True)
forms.py
from django import forms
from django.core.files.images import get_image_dimensions
from django.utils.translation import ugettext as u_
from django.forms.extras.widgets import SelectDateWidget
import datetime
from usrprofile.models import UserProfile
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
exclude = ['user']
fields = ['birth_date', 'phone1', 'phone2', 'email', 'address', 'avatar']
birth_date = forms.DateField(widget=SelectDateWidget(years=[y for y in range(1950, datetime.date.today().year)]))
email = forms.EmailField()
def clean_avatar(self):
avatar = self.cleaned_data['avatar']
try:
w, h = get_image_dimensions(avatar)
#validate dimensions
max_width = max_height = 100
if w > max_width or h > max_height:
raise forms.ValidationError(
u_('Please use an image that is '
'%s x %s pixels or smaller.') % (max_width, max_height))
#validate content type
main, sub = avatar.content_type.split('/')
if not (main == 'image' and sub in ['jpeg', 'pjpeg', 'gif', 'png']):
raise forms.ValidationError(u_('Please use a JPEG, '
'GIF or PNG image.'))
#validate file size
if len(avatar) > (20 * 1024):
raise forms.ValidationError(
u_('Avatar file size may not exceed 20k.'))
except AttributeError:
"""
Handles case when we are updating the user profile
and do not supply a new avatar
"""
pass
return avatar
views.py
from django.shortcuts import get_object_or_404, render, render_to_response
from django.http import HttpResponseRedirect, HttpResponseForbidden, HttpResponse
from django.core.urlresolvers import reverse
from django.views import generic
from django import forms
from django.template import RequestContext
from sorl.thumbnail import get_thumbnail
from usrprofile.models import UserProfile
from usrprofile.forms import *
class IndexView(generic.ListView):
model = UserProfile
template_name = 'usrprofile/profile.html'
def edit(request):
user = request.user
if request.method == 'POST':
#deletes old file in case of new file upload
form_aux = UserProfileForm(request.POST, request.FILES)
if form_aux.is_valid() and 'avatar' in request.FILES:
user.userprofile.avatar.delete()
#check if form has changed
#if form has changed, check if form is valid
#if form is valid, save data, associate with userprofile, save data to server
form = UserProfileForm(request.POST, request.FILES)
if form.has_changed():
if form.is_valid():
profile = form.save(commit=False)
profile.user = user
profile.save()
return render_to_response('usrprofile/profile.html', RequestContext(request))
else:
#if GET method, populate form with existing data
profile = user.userprofile
form = UserProfileForm(instance=profile, initial={'email': user.email})
return render_to_response('usrprofile/editprofile.html', RequestContext(request, {'form' : form}))
editprofile.html
{% extends "base.html" %}
{% load i18n %}
<html>
<head>
<title>{% block title %}{% trans "Profile edition" %}{% endblock %}</title>
</head>
<body>
<div id="content">
{% block content %}
<form id="form" method="POST" action="" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" name="submit" value="Save" />
</form>
{% endblock %}
</div>
</body>
</html>
ImageField
没有 required
参数(Django 和 sorl.thumbnail 都没有)。在您的模型定义中,而不是
avatar = ImageField('Avatar', upload_to='usrprofile/', required=False)
尝试
avatar = ImageField('Avatar', upload_to='usrprofile/', blank=True)