Django ImageField在上传时更改文件名

jas*_*son 34 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")
Run Code Online (Sandbox Code Playgroud)

mik*_*725 71

您可以将函数传递到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
Run Code Online (Sandbox Code Playgroud)

我的建议是返回一个随机文件名而不是{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/'), ...)
Run Code Online (Sandbox Code Playgroud)

  • 不,不,不要道歉。我还没有发布函数,这就是OP所需要的。您的回答比我的回答更好,发布得更快。无论如何都会向我+1。 (3认同)
  • 解决方案正在运行但是当我进行迁移时,我收到一个值错误,说"找不到包装器" (3认同)
  • 在实现该新函数时,我收到“找不到函数包装器”的消息。我究竟做错了什么? (3认同)
  • 你正在传递被调用的函数.相反,你应该传递函数本身 - "upload_to = path_and_rename,..." (2认同)
  • 对于仍然遇到“无法找到函数包装器”问题的任何人:/sf/answers/1803762411/ (2认同)

bmi*_*vic 24

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

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'), ...)
Run Code Online (Sandbox Code Playgroud)


Aid*_*wen 7

您可以使用文档中upload_to描述的可调用替换您指定的字符串.但是,我怀疑在使用参数时主键可能不可用.upload_to


小智 5

默认情况下,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)
Run Code Online (Sandbox Code Playgroud)

在模型领域:

class CardInfo(models.Model):
    ...
    photo = models.ImageField(upload_to=path_and_rename, max_length=255, null=True, blank=True)
Run Code Online (Sandbox Code Playgroud)

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