Django - Cannot create migrations for ImageField with dynamic upload_to value
I am not sure if it is OK to answer my own question, but i just figured out (i think).
According to this bug report, i edited my code:
from django.utils.deconstruct import deconstructible@deconstructibleclass 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")
And then, in field definition:
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")
This worked for me.
I had the same problem but I have many ImageFile in my models
head = ImageField(upload_to=upload_to("head")icon = ImageField(upload_to=upload_to("icon")...etc
I don't want create upload_to wraper func for every ImageField column I have.
So I just create a func named wrapper, and it woks
def wrapper(): return
I think it works just fine because I opened migration file and I found this:
('head', models.ImageField(upload_to=wrapper)),
I guess it's not effect migration process
You can create function with kwargs like this:
def upload_image_location(instance, filename, thumbnail=False): name, ext = os.path.splitext(filename) path = f'news/{instance.slug}{f"_thumbnail" if thumbnail else ""}{ext}' n = 1 while os.path.exists(path): path = f'news/{instance.slug}-{n}{ext}' n += 1 return path
and use this method with functools.partial in your model:
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)
You will get migration like this:
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'), ), ]