2014-09-10 90 views
22

我刚刚将我的应用升级到1.7(实际上仍在尝试)。Django - 无法为具有动态upload_to值的ImageField创建迁移

这是我在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. 

回答

48

我不知道这是否是OK的回答我的问题,但我只是想出了(我认为)。

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") 

这为我工作。

+0

我认为这是正确的解决方案。 – 2014-09-10 14:30:56

+0

是否可以使用它,并为每个字段添加一个自定义文件路径? – 2014-11-14 12:50:25

+0

@ Garreth00是的,将文件路径作为参数传递给'PathAndRename'类。例如:'custom_path = PathAndRename(“/ profiles/bg-images”)' – alix 2014-11-14 13:44:45

3

我有同样的问题,但我有很多镜像文件在我的模型

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

我不想为每列的ImageField我创建upload_to wraper FUNC。

所以,我只是创建了一个名为包装FUNC,它炒锅

def wrapper(): 
    return 

我想是因为我打开迁移文件,我发现这只是正常工作:

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

我猜测这不是影响迁移过程