最近在做一个管理问句的平台,需要上传一些问句,就想用django的upload模块来做,遇到一些问题,记录一下。
就拿测试用的demo来做例子吧:
第一:因为django默认的文件是存储在media下面的,所以需要现在settings.py里面把media定义一下
CUR_DIR=os.path.dirname(__file__) MEDIA_ROOT = os.path.join(CUR_DIR,'media/') # URL that handles the media served from MEDIA_ROOT. Make sure to use a # trailing slash. # Examples: "http://media.lawrence.com/media/", "http://example.com/media/" MEDIA_URL = '/media/'
然后就是写forms和models.
#forms.py from django import forms from django.forms.widgets import * from blogapp.validate import * class UpLoadPicForm(forms.Form): title=forms.CharField(max_length=100) pic=forms.FileField(validators=[validate_fize]) #models.py class Pic(models.Model): #这里的保存目录就是/mdeia.documents/%Y pic=models.FileField(upload_to='documents/%Y') class PicGallery(models.Model): picid=models.IntegerField(primary_key=True) pic=models.ManyToManyField(Pic)
OK,都定义好了,然后就是把views.py补上
def uploadPic(request): if request.method=="POST": form=UpLoadPicForm(request.POST,request.FILES) if form.is_valid(): storePic(request.FILES) return HttpResponse("success") else: form=UpLoadPicForm() return render_to_response('upload.html',{"form":form},context_instance=RequestContext(request)) def storePic(fileobj): newdoc=Pic(pic=fileobj["pic"]) newdoc.save()
然后是超简单的模板页面
<form enctype="multipart/form-data" method='post',action='/upload/'> {% csrf_token %} <p>{{ form.non_field_errors }}</p> <p> {{form.title.errors}} {{form.title.label_tag}} {{form.title}} </p> <p> {{ form.pic.errors }} {{form.pic}} {{ form.pic.errors }} {{form.pic}} </p> <input type="submit",value="提交"> </form>
这样就实现了上传文件,过程很简单,然后着重说下我遇到过的问题.
第一:UserWarning: A {% csrf_token %} was used in a template, but the context did not provide the value. This is usually caused by not using RequestContext.
这个错误发生的原因在与
return render_to_response('upload.html',{"form":form},context_instance=RequestContext(request))
这个里面忘记添加了context_instance=RequestContext(request),一开始不知道为什么,后来才发现django的说明文档里面有这么一句话:
If you are using generic views or contrib apps, you are covered already, since these apps use RequestContext throughout
而我这里的upload不属于contrib apps也不属于通用视图,所以需要手动添加RequestContext
第二:instance is on database "None", value is on database "default"
这个问题很粗心,发生的原因是这样的,我本来是想一个图库,就是PicGallery
于是我的storePic方法就变成了:
def storePic(fileobj): newdoc=Pic(pic=filobj["pic"]) newdoc.save() picgallery=PicGallery(1) picgallery.pic.add(newdoc) picgallery.save()
问题就在于我这里的picgallery一开始就是没这个query结果的,所以当我add的时候就出错了,应该先picgallery.save(),然后再是add()
第三:object has no attribute _state
这个也是很粗心,我本来是想再扩展下Pic这个模型的,然后就变成
class Pic(models.Model): pic=models.FileField(upload_to='documents/%Y') def __init__(self,*args,**kargs): ''' 问题就在于我这里init没有任何操作,也没有去super,所以出错了, ''' pass
第四:DjangoUnicodeDecodeError: 'utf8' codec can't decode byte 0x89 in position 77: invalid start byte.
这个问题是我想尝试下多个文件上传的时候出现的。
def storePic(fileobj): print fileobj["pic"]
''' 本来是这样,但是出现了错误 for pic in fileobj["pic"]: 后来通过getlist来获取上传的多个文件对象,才可以了 ''' for pic in fileobj.getlist('pic'): newdoc=Pic(pic=pic) newdoc.save()
PS:另外是自己学的一些,因为以前如果想自定义判断一个form数据是否有效的函数,都是在外部定义,比如在forms.is_valid()之后再调用自己的验证函数,今天也刚好尝试一下在form里面添加validate
比如我要判断文件大小是不是大于8M:
#validate.py from django.core.exceptions import ValidationError def validate_fize(value): if value.size>8*1024: raise ValidationError(u'sorry ,the size is too large',code='_invalid')
然后调用就是在定义forms的时候
class UpLoadPicForm(forms.Form): title=forms.CharField(max_length=100) pic=forms.FileField(validators=[validate_fize])
即可,具体运行结果就是:
另外记录一个判断图片类型的函数:
def get_pic_type(picobj): filetype=None data=picobj.read(10).encode("hex") if data.startwith("ffd8ffe0"): filetype="jpg" elif data.startwith("474946"): filetype="gif" elif data.startwith("424d"): filetype="bmp" elif data.startswith('89504e470d0a1a0a'): filetype="png" return filetype