django - 具有当前实例 ID 的动态文件上传路径

标签 django file-upload django-views

我有一个获取当前登录用户、一些输入和一个文件的表单:

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/file,而不是当前的 item id

我如何将 id 设置为这条路径?

提前致谢

最佳答案

Here我发现想法 && 代码基于使用 post_save 信号,当创建的对象从临时目录移动到模型类中的指定对象时:

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)

关于django - 具有当前实例 ID 的动态文件上传路径,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26681719/

相关文章:

python - 如果您在文件中看到有效模式,那么问题可能是由 django 中的循环导入引起的

django - 如何使 Django REST Framework 中的所有超链接相对?

django - 在我的测试(非生产)站点上排除 Django urls.py 中的某些 URLS

javascript - 从输入字段中抓取图像以获取图像数据/显示图像

php - Laravel 4 图片上传

django - 将整个 django 应用程序限制为普通用户

添加到数据库的 Python Django 表单

Django channel Postgres InterfaceError : connection already closed

r - Shiny 的 fileInput 不保留文件名

Django 更新/删除 View 。处理用户权限