覆盖具有相同名称的图像-Django

时间:2019-04-10 02:27:43

标签: python django overwrite

在我的项目中,我让用户上传个人资料图片。我将个人资料图片另存为userID.jpg。如果他们上传了新的个人资料图片,我想覆盖旧的个人资料图片,这样就不会浪费存储空间。通过浏览有关stackoverflow的先前提出的问题,我重新定义了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

上传个人资料图片时,我可以在计算机目录中看到该图片已被成功覆盖。该图片以路径“ media / profile / userID.jpg”保存。但是,当我在网站上显示图片时,它仍然是旧图片。 通过Django站点,当我打开路径时,我看到了旧图片,并且当我尝试通过admin更改它时,出现以下错误:

[WinError 32] The process cannot access the file because it is being used by another process: '\media\\profile\\userID.jpg'

我想我不正确地覆盖了文件,并且另一个实例仍处于打开状态,并且要解决该问题,我需要在覆盖之前正确关闭映像。我尝试这样做,但是没有成功。

3 个答案:

答案 0 :(得分:0)

我做了类似的事情,但是我使用信号来更新和删除图像。

首先,我在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)

所以,我在模型中调用了def,特别是在图像字段中

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'

最后,我定义了在模型中发生动作(更新或删除)之前更新或删除图像的信号。

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

我希望这对您有所帮助。

答案 1 :(得分:0)

receive and process via signals很有趣。在某些情况下,它可能比OverwriteStorage(FileSystemStorage)更方便。

但是,os.remove(filename)在没有本地文件系统的情况下是不安全的。我建议使用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

答案 2 :(得分:-1)

将旧名称重命名为userID-old.jpg,然后保存userID.jpg。很快,没人会注意到它的发生。