Overwriting Image with same name - Django

若如初见. 提交于 2021-01-29 09:44:24

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!