问题
Through my project, I have users upload a profile picture. I save the profile picture as userID.jpg. If they upload a new profile picture, I want to overwrite the old profile picture, so I don't waste storage space. By browsing previously asked questions on stackoverflow, I redefined the OverwriteStorage:
class OverwriteStorage(FileSystemStorage):
def get_available_name(self, name, max_length=None):
if self.exists(name):
os.remove(os.path.join(settings.MEDIA_ROOT, name))
return name
When I upload the profile picture, I can see in the directory on my computer that the picture has been overwritten successfully.The image is saved with the path "media/profile/userID.jpg". However, when I display the image on my site, it is still the old picture. Through the Django site, when I open the path, I see the old picture, and when I try to change it through the admin, I get the following error:
[WinError 32] The process cannot access the file because it is being used by another process: '\media\\profile\\userID.jpg'
I guess I am incorrectly overwriting the file and another instance is still open, and to solve it, I need to properly close the image before overwriting. I tried doing that, but to to no success.
回答1:
I did something similar but I used signals to update and delete images.
Firstable, I defined the name of the image in the helpers.py
from django.conf import settings
from datetime import datetime
def upload_to_image_post(self, filename):
"""
Stores the image in a specific path regards to date
and changes the name of the image with for the name of the post
"""
ext = filename.split('.')[-1]
current_date = datetime.now()
return '%s/posts/main/{year}/{month}/{day}/%s'.format(
year=current_date.strftime('%Y'), month=current_date.strftime('%m'),
day=current_date.strftime('%d')) % (settings.MEDIA_ROOT, filename)
SO, I called the def in my model, specifically in the image's field
from django.db import models
from django.utils.text import slugify
from .helpers import upload_to_image_post
class Post(models.Model):
"""
Store a simple Post entry.
"""
title = models.CharField('Title', max_length=200, help_text='Title of the post')
body = models.TextField('Body', help_text='Enter the description of the post')
slug = models.SlugField('Slug', max_length=200, db_index=True, unique=True, help_text='Title in format of URL')
image_post = models.ImageField('Image', max_length=80, blank=True, upload_to=upload_to_image_post, help_text='Main image of the post')
class Meta:
verbose_name = 'Post'
verbose_name_plural = 'Posts'
Finally, I defined signals to update or delete the image before the actions (update or delete) happen in the model.
import os
from django.db import models
from django.dispatch import receiver
from django.db.models.signals import pre_delete, pre_save
from .models import Post
@receiver(pre_delete, sender=Post)
def post_delete(sender, instance, **kwargs):
"""
Deleting the specific image of a Post after delete it
"""
if instance.image_post:
if os.path.isfile(instance.image_post.path):
os.remove(instance.image_post.path)
@receiver(pre_save, sender=Post)
def post_update(sender, instance, **kwargs):
"""
Replacing the specific image of a Post after update
"""
if not instance.pk:
return False
if sender.objects.get(pk=instance.pk).image_post:
old_image = sender.objects.get(pk=instance.pk).image_post
new_image = instance.image_post
if not old_image == new_image:
if os.path.isfile(old_image.path):
os.remove(old_image.path)
else:
return False
I hope, this helped you.
回答2:
It is interesting to receive and process via signals. In some cases, it may be more convenient than OverwriteStorage(FileSystemStorage)
.
But, os.remove(filename)
is not safe/working without local filesystem. I recommend using Django File Storage API.
from django.core.files.storage import default_storage
os.path.isfile(path) # worse
default_storage.exists(path) # better
os.remove(path) # worse
default_storage.delete(path) # better
回答3:
Have it rename the old one to userID-old.jpg and then save userID.jpg. It will be quick that no one would likely notice it happening.
来源:https://stackoverflow.com/questions/55603878/overwriting-image-with-same-name-django