2014-09-10 86 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)), 

我猜測這不是影響遷移過程