使用当前模型ID的Django管理文件上传

Kri*_*azs 15 python django upload django-models django-admin

我正在尝试使用默认的Django管理员创建一个简单的照片库.我想为每个图库保存一张示例照片,但我不想保留该名称.而不是文件名,我想保存模型的ID(N.jpg).但是我第一次想要保存对象时id不存在.我怎么能知道模型中的下一个自动增量,或以某种方式保存模型数据在上传之前super.save和之后上传文件时self.id存在?有一个很酷的解决方案吗?

像这样的东西:

def upload_path_handler(instance, filename):
    ext = filename extension
    return "site_media/images/gallery/{id}.{ext}".format(id=instance.nextincrement, ext=ext)

class Gallery(models.Model):
    name  = models.TextField()
    image = models.FileField(upload_to=upload_path_handler)
Run Code Online (Sandbox Code Playgroud)

并且可能将文件名存储在不同的字段中.

Lou*_*uis 37

我遇到了同样的问题.Okm的回答让我走上正确的道路,但在我看来,通过覆盖save()方法可以获得相同的功能.

def save(self, *args, **kwargs):
    if self.pk is None:
        saved_image = self.image
        self.image = None
        super(Material, self).save(*args, **kwargs)
        self.image = saved_image

    super(Material, self).save(*args, **kwargs)
Run Code Online (Sandbox Code Playgroud)

这肯定会正确保存信息.

  • 好的解决方案 过了一会儿,我注意到它在单元测试中断了,因为kwargs包含'force_insert = True',第二个保存导致IntegrityError:(1062,"Duplicate entry").在if块的末尾添加kwargs.pop('force_insert')可以解决问题. (4认同)

okm*_*okm 10

图像文件在Gallery实例之前保存.所以你必须使用带有状态的Gallery实例本身的信号将保存拆分为两个阶段:

from django.db.models.signals import post_save, pre_save
from django.dispatch import receiver

_UNSAVED_FILEFIELD = 'unsaved_filefield'

@receiver(pre_save, sender=Image)
def skip_saving_file(sender, instance, **kwargs):
    if not instance.pk and not hasattr(instance, _UNSAVED_FILEFIELD):
        setattr(instance, _UNSAVED_FILEFIELD, instance.image)
        instance.image = None

@receiver(post_save, sender=Image)
def save_file(sender, instance, created, **kwargs):
    if created and hasattr(instance, _UNSAVED_FILEFIELD):
        instance.image = getattr(instance, _UNSAVED_FILEFIELD)
        instance.save()        
        # delete it if you feel uncomfortable...
        # instance.__dict__.pop(_UNSAVED_FILEFIELD)
Run Code Online (Sandbox Code Playgroud)

upload_path_handler看起来像

def upload_path_handler(instance, filename):
    import os.path
    fn, ext = os.path.splitext(filename)
    return "site_media/images/gallery/{id}{ext}".format(id=instance.pk, ext=ext)
Run Code Online (Sandbox Code Playgroud)

如果该字段仅用于图像上载,我建议使用ImageField而不是FileField进行类型检查.此外,您可能希望规范化文件扩展名(由于mimetype而不必要)

def normalize_ext(image_field):
    try:
        from PIL import Image
    except ImportError:
        import Image
    ext = Image.open(image_field).format
    if hasattr(image_field, 'seek') and callable(image_field.seek):
       image_field.seek(0)
    ext = ext.lower()
    if ext == 'jpeg':
        ext = 'jpg'
    return '.' + ext
Run Code Online (Sandbox Code Playgroud)