【转载】django:设置上传文件夹

原文地址:http://plq168.blog.163.com/blog/static/53101462201093115050188/

参考于http://adil.2scomplement.com/2009/01/django-playing-with-upload_to-field/

    django提供了两种字段类型models.FileField与models.ImageField,用于保存上传文件与图

象.这两类字段提供了一个参数'upload_to',用于定义上传文件保存的路径(完整的路径为settings.MEDIA_ROOT + upload_to).

运行时创建基于时间的文件夹

    你可以使用参数upload_to,上传文件到一个基于文件时间的文件夹中.
    假如你要创建一个相册,要把图片传到名称包含年与月的文件夹中.

class Photo(models.Model):
  original = models.ImageField(upload_to='album/%m-%Y/')

    每次保存一个图片时,django会在MEDIA_ROOT/album/中创建一个'MM-YYYY'文件夹,用来保存图片.
   使用django源码来说明实现方式:
   在django/db/models/fields/fiels.py中
   class FileField(Field):
       ....
       def __init__(self,...,upload_to='',...):
           ...
   self.upload_to = upload_to
           if callable(upload_to):
               self.generate_filename = upload_to
           ...
   说明:
       如果upload_to是可执行的,则FileField的方法generate_filename的默认方法就会被覆盖

   保存时的操作:
   Class FileField(Field):
       ...
       def pre_save(self, model_instance, add):
           file = super(FileField, self).pre_save(model_instance, add)  # file的类型是FieldFile
           if file and not file._committed:
               file.save(file.name, file, save=False)
           return file
   而file中save的代码如下:
   class FieldFile(File):
       ...
       def save(...):
           name = self.field.generate_filename(self.instance, name)
           self.name = self.storage.save(name, content)
           ...
  从以上代码看来,如果upload_to是可执行的,FieldFile的方法save会调用generate_filename方

法,但实际上是已替换为upload_to.如upload_to不能执行,就会执行FieldFile的方法save会调用

FileField的默认方法generate_filename方法.
    class FieldFile(Field):
        ...
        def generate_filename(self, instance, filename):
           return os.path.join(self.get_directory_name(), self.get_filename(filename))

        def get_directory_name(self):
           return os.path.normpath(force_unicode(datetime.datetime.now().strftime(smart_str(self.upload_to))))

        def get_filename(self, filename):
           return os.path.normpath(self.storage.get_valid_name(os.path.basename(filename)))

  上面的实例中,为了产生上传文件夹名,实际上是执行了get_directory_name,而这个函数中包含

了upload_to,把实际的数据代入后,文件名是由下面的代码计算出来的:
datetime.datetime.now().strftime('album/%m-%Y/'),'%m-%Y'是时间格式符.

动态更改上传文件夹
以下面的model为例:
class MediaContent(models.Model):
   content_file = models.FileField()
   content_type = models.CharField(max_length=1,
      choices=(('I','Image'),('V','Video'),('A','Audio'),('D','Doc')))
   #other fields

MediaContent文件提供了各种媒体文件,如图象,视频,音频,文档与pdf文件.我要对这些媒体文件
提供一致的操作,但不同的文件类型上传到不同的文件夹中.所以在保存MediaContent实例前需要
更改upload_to.

使用一个callback作为upload_to

django可以让你提供一个callback作为upload_to值.这个回调函数有如下参数:
   1) self  MediaConten实例
   2) instance 真正的FileField或ImageField实例(此处实际上是content_file)
   3) filename 当保存文件时需要传递的文件名
使用这个技术,按下面代码来实现:
class MediaContent(models.Model):
  content_file = models.FieldFile(upload_to=get_media_upload_to)
  content_type = models.CharField(max_length=1,
    choices=(('I','Image'),('V','Video'),('A','Audio'),('D','Doc')))
  #other fields

def get_media_upload_to(instance, filename):
    """
    A simple way to return the full path      
    """
    paths = { 'I':'images/', 'V':'videos/', 'A':'audio/', 'D':'documents'/ }
    return settings.MEDIA_ROOT + 'content/' + paths[instance.content_type] + filename
每次调用media_content_object.content_file.save(filename, mem_file)
时,get_media_upload_to就会被调用,你可以基于content_type来确定文件路径.

运行时修改upload_to

你可以设置upload_to为一个固定的值,然后在保存对象时更改为你要的位置
def save_content(request):
    #if image
        MediContent._meta.get_field('content_file').upload_to='content/images/'
    #if video
        MediContent._meta.get_field('content_file').upload_to='content/videos/'
    #if audio
        MediContent._meta.get_field('content_file').upload_to='content/audios/'
    #if doc
        MediContent._meta.get_field('content_file').upload_to='content/documents/'
    #if pdf
        MediContent._meta.get_field('content_file').upload_to='content/acrobat/'
    #other types

猜你喜欢

转载自gwmwhu.iteye.com/blog/1453827