在Django的官网上有专门介绍如何处理文件上传的文档,其中说到了如何利用model来处理文件上传的场景。可是,在Django中最快速的开发方式是利用class-based views来进行开发。因此,我本身整理了一下如何利用class-based views来处理文件上传的场景,特此记录。html
既然是数据驱动的web,天然先要有model。web
from django.db import models from django.contrib.auth.models import User from django.conf import settings import os _roles_path = os.path.join(_base_path, 'roles') def var_dir(instance, filename): return os.path.join(_roles_path, instance.name, 'vars', filename) def task_dir(instance, filename): return os.path.join(_roles_path, instance.name, 'tasks', filename) class Roles(models.Model): id = models.AutoField(primary_key=True) name = models.CharField(max_length=50) creator = models.ForeignKey(User) createDatetime = models.DateTimeField(auto_now_add=True) directory = models.FilePathField(path=_roles_path, match='*.yml', recursive=True, max_length=200) tasks = models.FileField(upload_to=task_dir, blank=False) vars = models.FileField(upload_to=var_dir) def __unicode__(self): return u'%s' % self.name
上面用到了动态的upload_to,对应每一个FileField都提供不一样的上传路径。由于upload_to能够接受一个callable的对象,因此我尝试过把lambda赋值给upload_to,可是在测试中发现,给upload_to赋值为lambda表达式是会报错的ValueError: Cannot serialize function: lambda。应该能够尝试利用闭包的方式来给upload_to赋值,以解决多种动态路径的需求。django
通过后续的测试发现,闭包也是不支持的闭包
def _roles_subdir(roles_path, subdir): def wrapper(instance, filename): return os.path.join(roles_path, instance.name, subdir, filename) return wrapper
Please note that due to Python 2 limitations, you cannot serialize unbound method functions (e.g. a method declared
and used in the same class body). Please move the function into the main module body to use migrations.
For more information, see
https://docs.djangoproject.com/en/1.7/topics/migrations/#serializing-valuesapp
本例中使用Django提供的CreateView。在实际的使用中,能够针对于本身的应用场景选择CreateView、UpdateView。ide
from django.views.generic.edit import FormView, CreateView from django.views.decorators.csrf import csrf_exempt from django.core.urlresolvers import reverse_lazy class UploadRolesFormView(CreateView): template_name = 'app/upload_roles.html' model = Roles fields = ['name', 'tasks', 'vars'] success_url = reverse_lazy('app:index') #临时去掉CSRF保护,千万别学我! @csrf_exempt def dispatch(self, request, *args, **kwargs): return super(UploadRolesFormView, self).dispatch(request, *args, **kwargs) #override def form_valid(self, form): #在form中加入user对象存入model form.instance.creator = self.request.user return super(UploadRolesFormView, self).form_valid(form)
<html> <head> <title>upload</title> <meta http-equiv="description" content="this is my page"> <meta http-equiv="content-type" content="text/html; charset=GB18030"> </head> <body> <form action="{% url 'app:rolesUpload' %}" method="post" enctype="multipart/form-data"> <input type="text" name="name" /> <input type="file" name="tasks" /> <input type="file" name="vars" /> <input type="submit" value="上传" /> </form> </body> </html>
在app的urls.py中加入一条对应的url规则:post
url(r'^upload/$', views.UploadRolesFormView.as_view(), name='rolesUpload'),
这样,就能够利用Django最方便的class-based views开处理文件上传的场景了。测试