Django删除FileField [英] Django delete FileField

查看:921
本文介绍了Django删除FileField的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在Django建立一个网络应用程序。我有一个上传文件的模型,但我不能删除它。这是我的代码:

  class Song(models.Model):
name = models.CharField(blank = True ,max_length = 100)
author = models.ForeignKey(User,to_field ='id',related_name =id_user2)
song = models.FileField(upload_to ='/ songs /')
image = models.ImageField(upload_to ='/ pictures /',blank = True)
date_upload = models.DateField(auto_now_add = True)

def delete(self,* args,*删除模型
存储,path = self.song.storage,self.song.path
#删除模型前的文件
super(Song,self).delete(* args,** kwargs)
#删除模型后的文件
storage.delete(path)

然后,在python manage.py shell中我这样做:

  song = Song.objects.get(pk = 1)
song.delete()

它从数据库中删除但不从数据库中删除服务器上的文件。
我还可以尝试什么?



谢谢!

解决方案

p>在Django 1.3之前,当您删除相应的模型实例时,文件将自动从文件系统中删除。您可能正在使用较新的Django版本,因此您必须自行实现从文件系统中删除该文件。



您可以通过以下几种方法之一:它正在使用 pre_delete post_delete 信号。



示例



我现在选择的方法是混合使用 post_delete pre_save 信号,这样就可以删除每当相应的模型被删除或更改文件时过时的文件。



根据假设的 MediaFile 模型:

 导入os 
import uuid

from django.db import models
from django.dispatch import receiver
from django.utils.translation import ugettext_lazy as _


class MediaFile(models.Model):
file = models.FileField(_(file),
upload_to = lambda实例,filename:str(uuid.uuid4 ))


#这两个文件系统在不需要时自动删除文件:

@receiver(models.signals.post_delete,sender = MediaFile)
def auto_delete_file_on_delete(sender,instance,** kwargs):

从文件系统
中删除文件,当对应的M ediaFile`对象被删除。

if instance.file:
如果os.path.isfile(instance.file.path):
os.remove(instance.file.path)

@receiver(models.signals.pre_save,sender = MediaFile)
def auto_delete_file_on_change(sender,instance,** kwargs):

删除旧文件文件系统
当对应的MediaFile对象被更新
与新文件。

if not instance.pk:
return False

try:
old_file = MediaFile.objects.get(pk = instance.pk ).file
除了MediaFile.DoesNotExist:
return False

new_file = instance.file
如果不是old_file == new_file:
如果os.path .isfile(old_file.path):
os.remove(old_file.path)




  • 边缘案例:如果您的应用上传新文件,并将模型实例指向新文件,而不调用 save()(例如批量更新 QuerySet ),因为信号不会被运行,旧的文件将会继续存在,如果使用传统的文件处理方法,则不会发生。


  • 编码风格:本示例使用文件作为字段名称,这不是一个好的风格,因为它与内置的文件对象标识符



另请参见




  • FileField.delete() (Django 1.11 model field reference)


    请注意,当模型被删除时,相关文件不会被删除。如果您需要清理孤立的文件,那么您需要自己处理(例如,使用自定义管理命令,可以手动运行或通过例如cron定期运行)。



  • 为什么Django不会自动删除文件:在Django 1.3的发行说明中的​​条目


    在早期的Django版本中,当包含 FileField 的模型实例被删除时, FileField 本身也可以从后端存储中删除文件。这为几个数据丢失场景打开了大门,包括回滚事务和引用同一文件的不同模型上的字段。在Django 1.3中,当一个模型被删除时,不会调用 FileField delete()方法。如果您需要清理孤立的文件,您需要自己处理(例如,使用可以手动运行或定期运行的定制管理命令,例如通过cron定期运行)。



  • 仅使用 pre_delete 信号的示例



I'm building a web app in Django. I have a model that uploads a file, but I can not delete it. Here is my code:

class Song(models.Model):
    name = models.CharField(blank=True, max_length=100)
    author = models.ForeignKey(User, to_field='id', related_name="id_user2")
    song = models.FileField(upload_to='/songs/')
    image = models.ImageField(upload_to='/pictures/', blank=True)
    date_upload = models.DateField(auto_now_add=True)

    def delete(self, *args, **kwargs):
        # You have to prepare what you need before delete the model
        storage, path = self.song.storage, self.song.path
        # Delete the model before the file
        super(Song, self).delete(*args, **kwargs)
        # Delete the file after the model
        storage.delete(path)

Then, in "python manage.py shell" I do this:

song = Song.objects.get(pk=1)
song.delete()

It deletes from database but not the file on server. What else can I try?

Thanks!

解决方案

Before Django 1.3, the file was deleted from the filesystem automatically when you deleted the corresponding model instance. You are probably using a newer Django version, so you'll have to implement deleting the file from the filesystem yourself.

You can do that in a few ways, one of which is using a pre_delete or post_delete signal.

Example

My method of choice currently is a mix of post_delete and pre_save signals, which makes it so that obsolete files are deleted whenever corresponding models are deleted or have their files changed.

Based on a hypothetical MediaFile model:

import os
import uuid

from django.db import models
from django.dispatch import receiver
from django.utils.translation import ugettext_lazy as _


class MediaFile(models.Model):
    file = models.FileField(_("file"),
        upload_to=lambda instance, filename: str(uuid.uuid4()))


# These two auto-delete files from filesystem when they are unneeded:

@receiver(models.signals.post_delete, sender=MediaFile)
def auto_delete_file_on_delete(sender, instance, **kwargs):
    """
    Deletes file from filesystem
    when corresponding `MediaFile` object is deleted.
    """
    if instance.file:
        if os.path.isfile(instance.file.path):
            os.remove(instance.file.path)

@receiver(models.signals.pre_save, sender=MediaFile)
def auto_delete_file_on_change(sender, instance, **kwargs):
    """
    Deletes old file from filesystem
    when corresponding `MediaFile` object is updated
    with new file.
    """
    if not instance.pk:
        return False

    try:
        old_file = MediaFile.objects.get(pk=instance.pk).file
    except MediaFile.DoesNotExist:
        return False

    new_file = instance.file
    if not old_file == new_file:
        if os.path.isfile(old_file.path):
            os.remove(old_file.path)

  • Edge case: if your app uploads a new file and points model instance to the new file without calling save() (e.g. by bulk updating a QuerySet), the old file will keep lying around because signals won’t be run. This doesn’t happen if you use conventional file handling methods.
  • I think one of the apps I’ve built has this code in production but nevertheless use at your own risk.
  • Coding style: this example uses file as field name, which is not a good style because it clashes with the built-in file object identifier.

See also

  • FileField.delete() (Django 1.11 model field reference)

    Note that when a model is deleted, related files are not deleted. If you need to cleanup orphaned files, you’ll need to handle it yourself (for instance, with a custom management command that can be run manually or scheduled to run periodically via e.g. cron).

  • Why Django doesn’t delete files automatically: entry in release notes for Django 1.3

    In earlier Django versions, when a model instance containing a FileField was deleted, FileField took it upon itself to also delete the file from the backend storage. This opened the door to several data-loss scenarios, including rolled-back transactions and fields on different models referencing the same file. In Django 1.3, when a model is deleted the FileField’s delete() method won’t be called. If you need cleanup of orphaned files, you’ll need to handle it yourself (for instance, with a custom management command that can be run manually or scheduled to run periodically via e.g. cron).

  • Example of using a pre_delete signal only

这篇关于Django删除FileField的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆