Django ImageField在上传时更改文件名

时间:2013-02-28 16:43:29

标签: django

保存模型'产品'后,我希望上传的图像命名与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")

5 个答案:

答案 0 :(得分:66)

您可以将函数传递到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/'), ...)

答案 1 :(得分:19)

Django 1.7和更新版本不会像这样的功能进行迁移。基于@ miki275和this票的回答,你需要让你的功能如下:

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

答案 2 :(得分:6)

您可以将upload_to指定的字符串替换为docs中所述的可调用字符串。但是,我怀疑在使用upload_to参数时主键可能不可用。

答案 3 :(得分:0)

另一个选项,就是按照此回答https://stackoverflow.com/a/15141228/3445802,我们在需要%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

答案 4 :(得分:0)

默认情况下,Django保留上传文件的原始名称,但是您很可能希望将其重命名为其他名称(例如对象的ID)。幸运的是,使用Django表单的ImageField或FileField,您可以将可调用函数分配给upload_to参数以进行重命名。例如:

from django.db import models
from django.utils import timezone
import os
from uuid import uuid4

def path_and_rename(instance, filename):
    upload_to = 'photos'
    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(upload_to, filename)

以及在“模型”字段中:

class CardInfo(models.Model):
    ...
    photo = models.ImageField(upload_to=path_and_rename, max_length=255, null=True, blank=True)

在此示例中,所有上传的图像都将重命名为CardInfo对象的主键,即id_number。

相关问题