장고 파일 필드 삭제
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, **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)
그런 다음 "python manage.py shell"에서 다음을 수행합니다.
song = Song.objects.get(pk=1)
song.delete()
데이터베이스에서는 삭제되지만 서버의 파일은 삭제되지 않습니다. 또 무엇을 시도 할 수 있습니까?
감사!
Django 1.3 이전에는 해당 모델 인스턴스를 삭제할 때 파일 시스템에서 파일이 자동으로 삭제되었습니다. 아마도 최신 Django 버전을 사용하고있을 것이므로 파일 시스템에서 파일 삭제를 직접 구현해야합니다.
몇 가지 방법으로이를 수행 할 수 있으며 그 중 하나는 pre_delete
또는 post_delete
신호를 사용하는 것 입니다.
예
선택의 나의 방법은 현재의 혼합이다 post_delete
그리고 pre_save
그 오래된 파일은 해당 모델이 삭제 될 때마다 삭제 또는 파일이 변경이되어 있도록한다 신호.
가상 MediaFile
모델을 기반으로 :
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)
- 엣지 케이스 : 앱이 새 파일을 업로드하고 호출하지 않고 모델 인스턴스를 새 파일로 지정하면
save()
(예 : 대량 업데이트QuerySet
) 신호가 실행되지 않기 때문에 이전 파일이 계속 거짓말을합니다. 일반적인 파일 처리 방법을 사용하는 경우에는 발생하지 않습니다. - 내가 만든 앱 중 하나가이 코드를 프로덕션에 가지고 있지만 그럼에도 불구하고 자신의 책임하에 사용한다고 생각합니다.
- 코딩 스타일 :이 예제는
file
기본 제공file
개체 식별자 와 충돌하기 때문에 좋은 스타일이 아닌 필드 이름으로 사용 합니다.
또한보십시오
FieldFile.delete()
Django 1.11 모델 필드 참조 (FieldFile
클래스를 설명 하지만.delete()
필드에서 직접 호출 합니다.FileField
인스턴스는 해당FieldFile
인스턴스에 프록시를 사용하고 필드의 것처럼 메서드에 액세스합니다)모델을 삭제해도 관련 파일은 삭제되지 않습니다. 고아 파일을 정리해야하는 경우 직접 처리해야합니다 (예 : 수동으로 실행하거나 예를 들어 cron을 통해 주기적으로 실행하도록 예약 할 수있는 사용자 지정 관리 명령 사용).
Django가 파일을 자동으로 삭제하지 않는 이유 : Django 1.3 릴리스 정보 항목
이전 Django 버전에서는를 포함하는 모델 인스턴스
FileField
가 삭제FileField
되었을 때 자체적으로 백엔드 저장소에서 파일을 삭제했습니다. 이로 인해 롤백 된 트랜잭션과 동일한 파일을 참조하는 다른 모델의 필드를 포함하여 여러 데이터 손실 시나리오가 발생했습니다. Django 1.3에서는 모델이 삭제 될 때FileField
의delete()
메서드가 호출되지 않습니다. 분리 된 파일을 정리해야하는 경우 직접 처리해야합니다 (예 : 수동으로 실행하거나 예를 들어 cron을 통해 주기적으로 실행하도록 예약 할 수있는 사용자 지정 관리 명령 사용).
django-cleanup을 시도 하면 모델을 제거 할 때 FileField에서 delete 메서드를 자동으로 호출합니다.
pip install django-cleanup
settings.py
INSTALLED_APPS = (
...
'django_cleanup', # should go after your apps
)
You can also simply overwrite the delete function of the model to check for file if it exists and delete it before calling the super function.
import os
class Excel(models.Model):
upload_file = models.FileField(upload_to='/excels/', blank =True)
uploaded_on = models.DateTimeField(editable=False)
def delete(self,*args,**kwargs):
if os.path.isfile(self.upload_file.path):
os.remove(self.upload_file.path)
super(Excel, self).delete(*args,**kwargs)
You can delete file from filesystem with calling .delete
method of file field shown as below with Django >= 1.10:
obj = Song.objects.get(pk=1)
obj.song.delete()
@Anton Strogonoff
I missing something in the code when a file change, if you create a new file generate an error, becuase is a new file a did not find a path. I modified the code of function and added a try/except sentence and it works well.
@receiver(models.signals.pre_save, sender=MediaFile)
def auto_delete_file_on_change(sender, instance, **kwargs):
"""Deletes file from filesystem
when corresponding `MediaFile` object is changed.
"""
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:
try:
if os.path.isfile(old_file.path):
os.remove(old_file.path)
except Exception:
return False
Here is an app that will remove old files whenever model is deleted or a new file is uploaded: django-smartfields
from django.db import models
from smartfields import fields
class Song(models.Model):
song = fields.FileField(upload_to='/songs/')
image = fields.ImageField(upload_to='/pictures/', blank=True)
This code will run every time i upload a new image (logo field) and check if a logo already exists if so, close it and remove it from disk. The same procedure could of course be made in receiver function. Hope this helps.
# Returns the file path with a folder named by the company under /media/uploads
def logo_file_path(instance, filename):
company_instance = Company.objects.get(pk=instance.pk)
if company_instance.logo:
logo = company_instance.logo
if logo.file:
if os.path.isfile(logo.path):
logo.file.close()
os.remove(logo.path)
return 'uploads/{0}/{1}'.format(instance.name.lower(), filename)
class Company(models.Model):
name = models.CharField(_("Company"), null=False, blank=False, unique=True, max_length=100)
logo = models.ImageField(upload_to=logo_file_path, default='')
참고URL : https://stackoverflow.com/questions/16041232/django-delete-filefield
'developer tip' 카테고리의 다른 글
Java의 SOAPMessage에서 원시 XML 가져 오기 (0) | 2020.10.28 |
---|---|
SQL Azure 데이터베이스의 이름을 바꾸시겠습니까? (0) | 2020.10.28 |
OnGlobalLayoutListener : 지원 중단 및 호환성 (0) | 2020.10.28 |
테두리를 축소하는 방법 (div에서)? (0) | 2020.10.28 |
npm / yeoman 설치-sudo없이 각진 생성기 (0) | 2020.10.28 |