web-dev-qa-db-ja.com

Django-動的upload_to値でImageFieldの移行を作成できません

アプリを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.
28
alix

自分の質問に答えてもいいかどうかはわかりませんが、理解できただけです(私は思います)。

このバグレポート によると、私は自分のコードを編集しました:

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

これは私のために働いた。

60
alix

同じ問題が発生しましたが、モデルに多くのImageFileがあります

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

持っているすべてのImageField列にupload_toラッパー関数を作成したくありません。

だから私はラッパーという名前の関数を作成するだけで、それは中華鍋です

def wrapper():
    return

移行ファイルを開いたところ、次のことがわかったので、問題なく動作すると思います。

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

移行プロセスには影響しないと思います

3
Juntao

次のようなkwargsを使用して関数を作成できます。

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

モデルで 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'),
        ),
    ]
0
QuadX