Django - 如何防止重命名 FileFields 的文件名

时间:2021-03-27 00:59:19

标签: python django django-models

我正在尝试使用 Django 制作一个应用程序,该应用程序存储带有两个用于上传图像的字段的健身练习。我遇到的问题是,每次我更改、更新、覆盖这两个图像文件中的一个时,另一个由 Django 本身重命名。不仅如此,重命名的字段会使用另一个文件名复制图像。我搜索了类似的问题,但找不到解决方案。

文件models.py

from django.core.files.storage import FileSystemStorage
from django.db import models
from io import BytesIO
from PIL import Image
import os
from django.core.files import File
from django.urls import reverse

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


def compress(image):
    im = Image.open(image)
    # create a BytesIO object
    im_io = BytesIO()
    # save image to BytesIO object
    im.save(im_io, 'JPEG', quality=70)
    # create a django-friendly Files object
    new_image = File(im_io, name=image.name)
    return new_image


def content_file_name1(instance, filename):

        ext = filename.split('.')[-1]
        filename = "A_%s.%s" % (instance.id, ext)
        return os.path.join('exercises', filename)


def content_file_name2(instance, filename):
    ext = filename.split('.')[-1]
    filename = "B_%s.%s" % (instance.id, ext)
    return os.path.join('exercises', filename)


# Create your models here.
....

class Exercise(models.Model):
    id = models.AutoField(primary_key=True)
    exercise_name_eng = models.CharField(max_length=255, blank=False)
    exercise_name_it = models.CharField(max_length=255, blank=False)
    primary_muscle_group = models.ForeignKey(MusclesGroup, on_delete=models.CASCADE, related_name='primary_muscle',
                                             blank=True, null=True)
    secondary_muscle_group = models.ForeignKey(MusclesGroup, on_delete=models.CASCADE, related_name='secondary_muscle',
                                               blank=True, null=True)
    pattern_group = models.ForeignKey(PatternsGroup, on_delete=models.CASCADE, blank=True, null=True)
    type = models.ManyToManyField(Typology, blank=True)
    image1 = models.FileField(blank=True, upload_to=content_file_name1)
    image2 = models.FileField(blank=True, upload_to=content_file_name2)
    video_url = models.CharField(max_length=255, blank=True)
    description = models.TextField(blank=True)
    equip = models.ForeignKey(Equipment, on_delete=models.CASCADE, blank=True, null=True)

    date_created = models.DateTimeField(auto_now_add=True)
    date_modified = models.DateTimeField(auto_now=True)

    def save(self, *args, **kwargs):
        # call the compress function
        if self.image1 == "":
            super().save(*args, **kwargs)
        else:
            if self.image2 == "":
                new_image1 = compress(self.image1)
                self.image1 = new_image1
                super().save(*args, **kwargs)
            else:
                new_image1 = compress(self.image1)
                new_image2 = compress(self.image2)
                # set self.image to new_image
                self.image1 = new_image1
                self.image2 = new_image2
                # save2
                super().save(*args, **kwargs)

    def __str__(self):
        return "{0} - {1}".format(self.exercise_name_eng, self.exercise_name_it)

    def get_absolute_url(self):
        return reverse('exercise-detail', kwargs={'pk': self.id})

    class Meta:
        db_table = 'exercise'
        verbose_name_plural = "exercises"



""" Only delete the file if no other instances of that model are using it"""


def delete_file_if_unused(model, instance, field, instance_file_field):
    dynamic_field = {}
    dynamic_field[field.name] = instance_file_field.name
    other_refs_exist = model.objects.filter(**dynamic_field).exclude(pk=instance.pk).exists()
    if not other_refs_exist:
        instance_file_field.delete(False)


""" Whenever ANY model is deleted, if it has a file field on it, delete the associated file too"""


@receiver(post_delete)
def delete_files_when_row_deleted_from_db(sender, instance, **kwargs):
    for field in sender._meta.concrete_fields:
        if isinstance(field, models.FileField):
            instance_file_field = getattr(instance, field.name)
            delete_file_if_unused(sender, instance, field, instance_file_field)


""" Delete the file if something else get uploaded in its place"""


@receiver(pre_save)
def delete_files_when_file_changed(sender, instance, **kwargs):
    # Don't run on initial save
    if not instance.pk:
        return
    for field in sender._meta.concrete_fields:
        if isinstance(field, models.FileField):
            # its got a file field. Let's see if it changed
            try:
                instance_in_db = sender.objects.get(pk=instance.pk)
            except sender.DoesNotExist:
                # We are probably in a transaction and the PK is just temporary
                # Don't worry about deleting attachments if they aren't actually saved yet.
                return
            instance_in_db_file_field = getattr(instance_in_db, field.name)
            instance_file_field = getattr(instance, field.name)
            if instance_in_db_file_field.name != instance_file_field.name:
                delete_file_if_unused(sender, instance, field, instance_in_db_file_field)

首次上传后的文件名:

Filename after first upload

覆盖图像 1 后的文件名:

Filename after I overwrite Image 1

问题可能是由于upload_to方法造成的吗?

0 个答案:

没有答案