Django - 无法为具有动态 upload_to 值的 ImageField 创建迁移

Posted

技术标签:

【中文标题】Django - 无法为具有动态 upload_to 值的 ImageField 创建迁移【英文标题】:Django - Cannot create migrations for ImageField with dynamic upload_to value 【发布时间】:2014-11-04 05:48:42 【问题描述】:

我刚刚将我的应用升级到 1.7(实际上仍在尝试)。

这就是我在 models.py 中的内容:

def path_and_rename(path):
    def wrapper(instance, filename):
        ext = filename.split('.')[-1]
        # set filename as random string
        filename = '.'.format(uuid4().hex, ext)
        # return the whole path to the file
        return os.path.join(path, filename)
    return wrapper

class UserProfile(AbstractUser):
    #...
    avatar = models.ImageField(upload_to=path_and_rename("avatars/"),
                               null=True, blank=True,
                               default="avatars/none/default.png",
                               height_field="image_height",
                               width_field="image_width")

当我尝试makemigrations 时,它会抛出:

ValueError: Could not find function wrapper in webapp.models.
Please note that due to Python 2 limitations, you cannot serialize unbound method functions (e.g. a method declared
and used in the same class body). Please move the function into the main module body to use migrations.

【问题讨论】:

【参考方案1】:

我不确定是否可以回答我自己的问题,但我只是想通了(我认为)。

根据this bug report,我编辑了我的代码:

from django.utils.deconstruct import deconstructible

@deconstructible
class PathAndRename(object):

    def __init__(self, sub_path):
        self.path = sub_path

    def __call__(self, instance, filename):
        ext = filename.split('.')[-1]
        # set filename as random string
        filename = '.'.format(uuid4().hex, ext)
        # return the whole path to the file
        return os.path.join(self.path, filename)

path_and_rename = PathAndRename("/avatars")

然后,在字段定义中:

avatar = models.ImageField(upload_to=path_and_rename,
                               null=True, blank=True,
                               default="avatars/none/default.png",
                               height_field="image_height",
                               width_field="image_width")

这对我有用。

【讨论】:

是否可以使用这个,并为每个字段添加自定义文件路径? @Garreth00 是的,将文件路径作为参数传递给PathAndRename 类。喜欢:custom_path = PathAndRename("/profiles/bg-images") 这是一个很好的答案!完美运行。谢谢! @ip。有什么错误吗?因为我两天前在另一个项目中使用了完全相同的代码。并且运作良好 ^ 不管我用的是普通的方法还是可解构的方法【参考方案2】:

我有同样的问题,但我的模型中有很多 ImageFile

head = ImageField(upload_to=upload_to("head")
icon = ImageField(upload_to=upload_to("icon")
...etc

我不想为我拥有的每个 ImageField 列创建 upload_to 包装函数。

所以我只创建了一个名为 wrapper 的函数,它就可以工作了

def wrapper():
    return

我认为它工作得很好,因为我打开了迁移文件,我发现了这个:

('head', models.ImageField(upload_to=wrapper)),

我猜这不会影响迁移过程

【讨论】:

【参考方案3】:

您可以像这样使用 kwargs 创建函数:

def upload_image_location(instance, filename, thumbnail=False):
    name, ext = os.path.splitext(filename)
    path = f'news/instance.slugf"_thumbnail" if thumbnail else ""ext'
    n = 1
    while os.path.exists(path):
        path = f'news/instance.slug-next'
        n += 1
    return path

并在您的模型中将此方法与 functools.partial 一起使用:

image = models.ImageField(
    upload_to=upload_image_location,
    width_field='image_width',
    height_field='image_height'
)
thumbnail_image = models.ImageField(upload_to=partial(upload_image_location, thumbnail=True), blank=True)

你会得到这样的迁移:

class Migration(migrations.Migration):

    dependencies = [
        ('news', '0001_initial'),
    ]

    operations = [
        migrations.AddField(
            model_name='news',
            name='thumbnail_image',
            field=models.ImageField(blank=True, upload_to=functools.partial(news.models.upload_image_location, *(), **'thumbnail': True)),
        ),
        migrations.AlterField(
            model_name='news',
            name='image',
            field=models.ImageField(height_field='image_height', upload_to=news.models.upload_image_location, width_field='image_width'),
        ),
    ]

【讨论】:

以上是关于Django - 无法为具有动态 upload_to 值的 ImageField 创建迁移的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Django 的 FileField 中保存来自传入电子邮件的附件?

具有动态数据的 django 模板表单目标

使用 django html 模板创建具有动态行和列的表

Django DetailView 动态模型

具有 ForeignKey 字段的模型的 Django ModelForm 无法正确显示 selectBox

无法在 Django 中使用动态图像 URL