具有当前实例ID的动态文件上传路径 [英] dynamic file upload path with current instance id

查看:172
本文介绍了具有当前实例ID的动态文件上传路径的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  class AddItemForm(ModelForm):

我有一个表单获取当前登录的用户,一些输入和一个文件:
class Meta:
model = Item
exclude = ['user']

对于此表单,有一个视图:

  item_form = AddItemForm(request.POST,request.FILES)
如果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):

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

问题是我看不到上传路径中的当前实例ID,因为以下行:

 项目= item_form.save(commit = False)

它还没有实例标识,而不是当前项目ID它创建user_1 / item_NONE / file



如何将id设置为此路径?



提前感谢

解决方案

这里我发现我dea&&基于使用post_save信号的代码,当创建对象时,在模型类中从temp目录移动到指定的一个:


use_key和upload_to是可选的。 use_key默认为False。如果它是True,那么实例的id将被用作新文件的前缀,因为现在有可能覆盖我们正在移动该文件。 upload_to将简单地定义临时目录以将文件上传到最初。




  from django.db .models import imageField,FileField,来自django.dispatch的
import dispatcher
from django.conf import settings
import shutil,os,glob,re
from distutils.dir_util import mkpath

class CustomImageField(ImageField):
允许模型实例动态地指定upload_to

模型类应该有一个方法,如:

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')
除了KeyError:
self.use_key = False

super(CustomImageField,self).__ init __(* args,** kwargs)

def contribut_to_class(s​​elf,cls,name):
挂钩事件,所以我们可以访问实例。
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):

使用模型的get_upload_to()方法将临时上传的图像移动到更合适的目录
的功能。

if hasattr(instance,'get_upload_to'):
src = getattr(instance,self.attname)
如果src:
m = re.match (r%s /(.*)%self.upload_to,src)
如果m:
如果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 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):
Django为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)


I have a form which gets current logged in user, some inputs and a file:

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

For this form a have a view:

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

for this item's file field i am using upload_to feature. here is my modal:

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)

problem is that i can't see the current instance id in uploaded path because of following line:

item = item_form.save(commit=False)

it has not instance id yet and instead of current item id it create user_1/item_NONE/file

how can i set id to this path?

thanks in advance

解决方案

Here I've found idea && code based on using the post_save signal, when object created move from temp directory to specified one in model class:

use_key and upload_to are optional. use_key defaults to False. If it is True then the id of the instance will be used as a prefix for the new file as there is the potential for overwriting now that we are moving the file. upload_to will simply define the temporary directory to upload the files to initially.

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)

这篇关于具有当前实例ID的动态文件上传路径的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆