Django中的文件上傳(利用class-based view)

背景介紹

在Django的官網上有專門介紹如何處理文件上傳文檔,其中說到了如何利用model來處理文件上傳的場景。可是,在Django中最快速的開發方式是利用class-based views來進行開發。因此,我本身整理了一下如何利用class-based views來處理文件上傳的場景,特此記錄。html


model

既然是數據驅動的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

view

本例中使用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)

template

<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>

url

在app的urls.py中加入一條對應的url規則:post

url(r'^upload/$', views.UploadRolesFormView.as_view(), name='rolesUpload'),

這樣,就能夠利用Django最方便的class-based views開處理文件上傳的場景了。測試

相關文章
相關標籤/搜索