我正在尝试使用 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)
首次上传后的文件名:
覆盖图像 1 后的文件名:
问题可能是由于upload_to方法造成的吗?