2014-10-31 150 views
2

我有一個形式獲取當前登錄的用戶,一些投入和文件:動態文件上傳路徑

class AddItemForm(ModelForm): 
    class Meta: 
     model = Item 
     exclude = ['user'] 

對於這種形式有一個觀點:

item_form = AddItemForm(request.POST, request.FILES) 
if item_form.is_valid(): 
    item = item_form.save(commit=False) 
    item.user = request.user 
    item.save() 

對於此項目的文件字段,我正在使用upload_to功能。這裏是我的模式:

class Item(models.Model): 
    user = models.ForeignKey(User) 
    cover_image = models.FileField(upload_to=get_upload_path) 

def get_upload_path(instance, filename): 

    return "items/user_{user_id}/item_{item_id}/{filename}".format(user_id=instance.user.id, item_id=instance.id,filename=filename) 

的問題是,我不能看到當前實例ID,因爲下面一行的上傳路徑:

item = item_form.save(commit=False) 

它沒有實例ID還沒有,而是當前項目的它創建user_1/item_NONE /文件

我該如何設置id到這個路徑?

在此先感謝

+0

你不能爲一個新的紀錄'get_upload_path'使用'instance.id',因爲屬性尚未在該點分配。它只會在更新現有記錄時起作用。 – Brandon 2014-10-31 19:32:03

回答

0

Here我發現基於使用post_save信號,在模型類對象時,從創建臨時目錄移動到指定的一個想法& &代碼:

use_key和upload_to是可選的。 use_key默認爲False。如果它是True,那麼實例的id將被用作新文件的前綴,因爲現在可能會覆蓋我們正在移動文件。 upload_to將簡單地定義將文件上傳到臨時目錄的臨時目錄。

from django.db.models import ImageField, FileField, signals 
from django.dispatch import dispatcher 
from django.conf import settings 
import shutil, os, glob, re 
from distutils.dir_util import mkpath 

class CustomImageField(ImageField): 
    """Allows model instance to specify upload_to dynamically. 

    Model class should have a method like: 

     def get_upload_to(self, attname): 
      return 'path/to/{0}'.format(self.id) 
    """ 
    def __init__(self, *args, **kwargs): 
     kwargs['upload_to'] = kwargs.get('upload_to', 'tmp') 

     try: 
      self.use_key = kwargs.pop('use_key') 
     except KeyError: 
      self.use_key = False 

     super(CustomImageField, self).__init__(*args, **kwargs) 

    def contribute_to_class(self, cls, name): 
     """Hook up events so we can access the instance.""" 
     super(CustomImageField, self).contribute_to_class(cls, name) 
     dispatcher.connect(self._move_image, signal=signals.post_save, sender=cls) 

    def _move_image(self, instance=None): 
     """ 
      Function to move the temporarily uploaded image to a more suitable directory 
      using the model's get_upload_to() method. 
     """ 
     if hasattr(instance, 'get_upload_to'): 
      src = getattr(instance, self.attname) 
      if src: 
       m = re.match(r"%s/(.*)" % self.upload_to, src) 
       if m: 
        if self.use_key: 
         dst = "%s/%d_%s" % (instance.get_upload_to(self.attname), instance.id, m.groups()[0]) 
        else: 
         dst = "%s/%s" % (instance.get_upload_to(self.attname), m.groups()[0]) 
        basedir = "%s%s/" % (settings.MEDIA_ROOT, os.path.dirname(dst)) 
        mkpath(basedir) 
        shutil.move("%s%s" % (settings.MEDIA_ROOT, src),"%s%s" % (settings.MEDIA_ROOT, dst)) 
        setattr(instance, self.attname, dst) 
        instance.save() 

    def db_type(self): 
     """Required by Django for ORM.""" 
     return 'varchar(100)' 


class Image(models.Model): 
    file = CustomImageField(use_key=True, upload_to='tmp') 

    def get_upload_to(self, attname): 
     return 'path/to/{0}'.format(self.id)