Ответ 1
До 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).