首页 > 解决方案 > 无法使用 upload_to 动态创建路径

问题描述

在我的用户模型中,我有一个ImageField包含upload_to将根据用户 ID 动态创建图像路径的属性。

avatar  = models.ImageField(storage=OverwriteStorage(), upload_to=create_user_image_path)

def create_user_image_path(instance, image_name):
    image_name = str(instance.user.id) + image_name[-4:]
    return 'users/{0}/avatars/{1}'.format(instance.user.id, image_name)

当我注册时,我收到一个如下所示的错误:

系统找不到指定的路径:'C:\Users\xx\PycharmProjects\project_name\media\users\150\avatars'

如果我删除 id 和头像并只包含图像名称(没有新目录),它会成功运行并写入图像。我试过chmod -R 777在这个目录上做,但它仍然没有动态创建这些新目录。我不确定我做错了什么。

编辑

class OverwriteStorage(FileSystemStorage):

    def get_available_name(self, name, *args, **kwargs):

        # Delete all avatars in directory before adding new avatar.
        # (Sometimes we have different extension names, so we can't delete by name
        file_path = os.path.dirname(name)
        shutil.rmtree(os.path.join(settings.MEDIA_ROOT, file_path))

        return name

我看到的问题是因为我的OverwriteStorage功能。当我删除它时,它会保存。如何修复此功能以使其在存在时覆盖?

标签: djangodjango-models

解决方案


我认为您的问题 IDinstance.user.id 建议您尝试按如下方式导入用户,这可能会有所帮助

从 django.contrib.auth.models 导入用户
用户 = User.objects.get(id=user_id)

def create_user_image_path(实例,image_name):
    image_name = str(user) + image_name[-4:]
    return 'users/{0}/avatars/{1}'.format(user.id, image_name)

但是 django 建议用户AUTH_USER_MODEL 实现

从 django.contrib.auth 导入 get_user_model
用户 = get_user_model()

更新

当您查看覆盖存储时,该变量name会获取您要上传的图像的名称。您的file_path = os.path.dirname(name),您正在返回一个带有图像名称的文件夹。当 shutil.rmtree 绑定找到文件夹时,它返回错误它找不到路径。使用条件语句即iftry except block如下所示。

从 django.core.files.storage 导入 FileSystemStorage
从 django.conf 导入设置
从 django.core.files.storage 导入 default_storage
导入操作系统


类覆盖存储(文件系统存储):

    def get_available_name(self, name, max_length=None):
        """返回目标存储系统上可用的文件名,并且
        可用于写入新内容。

        见 http://djangosnippets.org/snippets/976/

        此文件存储解决了上传问题的覆盖。其他
        建议的解决方案是覆盖模型上的保存方法
        像这样(来自https://code.djangoproject.com/ticket/11663):

        def 保存(自我,*args,**kwargs):
            尝试:
                这 = MyModelName.objects.get(id=self.id)
                如果 this.MyImageFieldName != self.MyImageFieldName:
                    this.MyImageFieldName.delete()
            除了:通过
            super(MyModelName, self).save(*args, **kwargs)
        """
        # 如果文件名已经存在,则删除它,就好像它是一个真正的文件系统一样
        如果 self.exists(name):
            os.remove(os.path.join(settings.MEDIA_ROOT, name))
            # default_storage.delete(os.path.join(settings.MEDIA_ROOT, name))
        返回名称

就像你的情况一样

类覆盖存储(文件系统存储):

    def get_available_name(self, name, *args, **kwargs):

        # 在添加新头像之前删除目录中的所有头像。
        # (有时我们有不同的扩展名,所以不能按名字删除
        如果 self.exists(name):
            file_path = os.path.dirname(name)
            shutil.rmtree(os.path.join(settings.MEDIA_ROOT, file_path))

        返回名称

推荐阅读