runpython migrations makemigrations force empty create all python django django-migrations

python - migrations - Django: no se pueden crear migraciones para ImageField con el valor dinámico upload_to



reset all migrations (3)

Acabo de actualizar mi aplicación a 1.7 (en realidad aún estoy intentando).

Esto es lo que tenía en 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")

Cuando intento hacer makemigrations , arroja:

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.


No estoy seguro de si está bien responder mi propia pregunta, pero acabo de descubrir (creo).

Según este informe de error , edité mi código:

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

Y luego, en definición de campo:

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

Esto funcionó para mí.


Puedes crear una función con kwargs así:

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

y use este método con functools.partial en su modelo:

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)

Obtendrá la migración de esta manera:

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''), ), ]


Tuve el mismo problema pero tengo muchos ImageFile en mis modelos

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

No quiero crear la función upload_to wraper para cada columna ImageField que tengo.

Así que solo creo una función llamada wrapper, y funciona

def wrapper(): return

Creo que funciona bien porque abrí el archivo de migración y encontré esto:

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

Supongo que no es efecto del proceso de migración.