Estou construindo um aplicativo da web em Django. Tenho um modelo que carrega um arquivo, mas não consigo excluí-lo. Aqui está o meu código:
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)
Então, em "python manage.py shell", faço o seguinte:
song = Song.objects.get(pk=1)
song.delete()
Ele exclui do banco de dados, mas não o arquivo no servidor. O que mais posso tentar?
Obrigado!
django
django-models
Marcos Aguayo
fonte
fonte
Respostas:
Antes do Django 1.3, o arquivo era excluído do sistema de arquivos automaticamente quando você excluía a instância de modelo correspondente. Você provavelmente está usando uma versão mais recente do Django, então terá que implementar a exclusão do arquivo do sistema de arquivos por conta própria.
Você pode fazer isso de algumas maneiras, uma das quais é usando um
pre_delete
oupost_delete
sinal .Exemplo
Meu método de escolha atualmente é uma mistura de
post_delete
epre_save
sinais, o que faz com que arquivos obsoletos sejam excluídos sempre que os modelos correspondentes forem excluídos ou seus arquivos alterados.Com base em um
MediaFile
modelo hipotético :save()
(por exemplo, atualizando em massa aQuerySet
), o arquivo antigo continuará parado porque os sinais não serão executados. Isso não acontece se você usar métodos convencionais de tratamento de arquivos.file
como nome de campo, o que não é um bom estilo porque entra em conflito com ofile
identificador de objeto .Veja também
FieldFile.delete()
na referência de campo do modelo Django 1.11 (observe que ele descreve aFieldFile
classe, mas você chamaria.delete()
diretamente no campo:FileField
proxies de instância para o correspondenteFieldFile
instância , e você acessa seus métodos como se fossem de campo)Por que o Django não deleta arquivos automaticamente: entrada nas notas de lançamento do Django 1.3
Exemplo de uso de
pre_delete
apenas um sinalfonte
instance.song.delete(save=False)
, já que usa o mecanismo de armazenamento django correto.os.path.isfile(old_file.path)
falha porqueold_file.path
levanta um erro (nenhum arquivo está associado ao campo). Consertei adicionandoif old_file:
pouco antes da chamada paraos.path.isfile()
.Tente django-cleanup , ele invoca automaticamente o método delete em FileField quando você remove o modelo.
settings.py
fonte
Você pode excluir o arquivo do sistema de arquivos com o
.delete
método de chamada do campo de arquivo mostrado abaixo com Django> = 1.10:fonte
Você também pode simplesmente sobrescrever a função de exclusão do modelo para verificar se o arquivo existe e excluí-lo antes de chamar a função super.
fonte
queryset.delete()
não limpará os arquivos com esta solução. Você precisaria iterar sobre o queryset e chamar.delete()
cada objeto.Solução Django 2.x:
É muito fácil lidar com a exclusão de arquivos no Django 2 . Eu tentei seguir a solução usando Django 2 e SFTP Storage e também FTP STORAGE, e tenho certeza de que funcionará com qualquer outro gerenciador de armazenamento que implementou o
delete
método. (delete
método é um dosstorage
métodos abstratos).Substitua o
delete
método do modelo de forma que a instância exclua seus FileFields antes de excluir a si mesma:Funciona muito fácil para mim. Se você quiser verificar se o arquivo existe antes da exclusão, você pode usar
storage.exists
. por exemploself.song.storage.exists(self.song.name)
, retornará umboolean
representando se a música existe. Então, ficará assim:EDITAR (além):
Como @HeyMan mencionou, com esta solução, chamar
Song.objects.all().delete()
não exclui arquivos! Isso está acontecendo porqueSong.objects.all().delete()
está executando a consulta de exclusão do Default Manager . Portanto, se você deseja excluir arquivos de um modelo usandoobjects
métodos, deve escrever e usar um gerenciador personalizado (apenas para substituir sua consulta de exclusão):e para atribuir o
CustomManager
ao modelo, você deve rubricarobjects
em seu modelo:Agora você pode usar
.delete()
no final de quaisquerobjects
subconsultas. Eu escrevi o mais simplesCustomManager
, mas você pode fazer melhor retornando algo sobre os objetos que você excluiu ou o que quiser.fonte
Este é um aplicativo que removerá arquivos antigos sempre que o modelo for excluído ou um novo arquivo for carregado: django-smartfields
fonte
@Anton Strogonoff
Estou faltando alguma coisa no código quando um arquivo muda, se criar um novo arquivo gera um erro, pois é um arquivo novo e não encontrou um caminho. Modifiquei o código de função e adicionei uma frase try / except e funciona bem.
fonte
try:
bloco (AttributeError
talvez?).Este código será executado toda vez que eu carregar uma nova imagem (campo de logotipo) e verificar se já existe um logotipo, feche-o e remova-o do disco. O mesmo procedimento pode ser feito na função de receptor. Espero que isto ajude.
fonte