Подтвердить что ты не робот

Django ImageField изменяет имя файла при загрузке

При сохранении модели "Продукты" я хотел бы, чтобы загруженное изображение было названо так же, как и pk, например 22.png или 34.gif Я не хочу изменять формат изображения только для имени. Как это может быть сделано? пример моей модели до сих пор ниже...

image = models.ImageField(
        upload_to="profiles",
        height_field="image_height",
        width_field="image_width",
        null=True,
        blank=True,
        editable=True,
        help_text="Profile Picture",
        verbose_name="Profile Picture"
    )
    image_height = models.PositiveIntegerField(null=True, blank=True, editable=False, default="100")
    image_width = models.PositiveIntegerField(null=True, blank=True, editable=False, default="100")
4b9b3361

Ответ 1

Вы можете передать функцию в поле upload_to:

def f(instance, filename):
    ext = filename.split('.')[-1]
    if instance.pk:
        return '{}.{}'.format(instance.pk, ext)
    else:
        pass
        # do something if pk is not there yet

Мои предложения состоят в том, чтобы вернуть произвольное имя файла вместо {pk}.{ext}. В качестве бонуса он будет более безопасным.

Что происходит, так это то, что Django вызовет эту функцию, чтобы определить, куда должен быть загружен файл. Это означает, что ваша функция отвечает за возвращение всего пути файла, включая имя файла. Ниже приведена измененная функция, в которой вы можете указать, куда загрузить и как ее использовать:

import os
from uuid import uuid4

def path_and_rename(path):
    def wrapper(instance, filename):
        ext = filename.split('.')[-1]
        # get filename
        if instance.pk:
            filename = '{}.{}'.format(instance.pk, ext)
        else:
            # 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

FileField(upload_to=path_and_rename('upload/here/'), ...)

Ответ 2

Django 1.7 и новее не будут выполнять миграцию с такой функцией. Исходя из ответа @miki725 и этого тикета, вам нужно настроить свою функцию следующим образом:

import os
from uuid import uuid4
from django.utils.deconstruct import deconstructible

@deconstructible
class UploadToPathAndRename(object):

    def __init__(self, path):
        self.sub_path = path

    def __call__(self, instance, filename):
        ext = filename.split('.')[-1]
        # get filename
        if instance.pk:
            filename = '{}.{}'.format(instance.pk, ext)
        else:
            # set filename as random string
            filename = '{}.{}'.format(uuid4().hex, ext)
        # return the whole path to the file
        return os.path.join(self.sub_path, filename)

FileField(upload_to=UploadToPathAndRename(os.path.join(MEDIA_ROOT, 'upload', 'here'), ...)

Ответ 3

Вы можете заменить строку, которую вы присваиваете upload_to на вызываемую, как описано в документации. Однако я подозреваю, что первичный ключ может быть недоступен в тот момент, когда upload_to параметр upload_to.

Ответ 4

Другой вариант, следующий после этого ответа fooobar.com/info/209317/..., мы обнаружили проблему, когда нам нужен обратный путь с %Y/%m/%d, например:

FileField(upload_to=path_and_rename('upload/here/%Y/%m/%d'), ...)

поэтому мы справляемся с этим:

FileField(upload_to=path_and_rename('upload/here/{}'.format(time.strftime("%Y/%m/%d"))), ...)

Будет импортирован модуль time.