2009-10-08 7 views
15

J'ai un problème parce que je supprime un widget en utilisant some_widget_instance.delete(). J'ai aussi un modèle appelé WidgetFile avec une méthode redéfinir delete() afin que je puisse supprimer des fichiers de mon disque dur quand un WidgetFile est supprimé. Le problème que je vais avoir est que si je supprimer un Widget, et il a WidgetFiles qui s'y rattachent comme ceci:Comment redéfinir delete() sur un modèle et le faire fonctionner avec des suppressions associées

class WidgetFile(models.Model): 

    widget = models.ForeignKey(Widget) 

Eh bien, quand je supprime ce widget, il est WidgetFiles sont supprimés, mais la méthode de suppression() doesn Ne pas déclencher et faire mes trucs de disque dur supplémentaire. Toute aide est très appréciée.

+0

Ce problème est dû au fait que lorsqu'un widget est supprimé, il ne déclenche pas la méthode delete() sur chacune de ses dépendances (les classes qui ont une référence de clé étrangère). Il supprime simplement les objets associés de la base de données. Cela le rend plus efficace mais conduit évidemment à des problèmes comme celui-ci. – orokusaki

Répondre

24

I figured it out. Je viens de mettre cela sur ce modèle Widget:

def delete(self): 
    files = WidgetFile.objects.filter(widget=self) 
    if files: 
     for file in files: 
      file.delete() 
    super(Widget, self).delete() 

Cette méthode a déclenché la suppression() nécessaire sur chacun des objets connexes, déclenchant ainsi mon fichier code personnalisé suppression. C'est plus cher que la base de données oui, mais quand vous essayez de supprimer des fichiers sur un disque dur de toute façon, ce n'est pas une grosse dépense pour frapper le db quelques fois supplémentaires.

+0

On ne sait pas pourquoi vous pensez que Celery ou cron ne rencontreraient pas une situation similaire où le fichier en cours de suppression pourrait être déjà ouvert pour une opération de lecture/écriture d'un autre processus. Dans les deux cas, vous devrez coder pour gérer le cas particulier. –

+2

J'ai enlevé ce bit ... Il y a 4,5 ans, j'ai pensé que ce serait une bonne idée, mais je ne sais pas trop pourquoi. – orokusaki

1

Est some_widget_instance et l'instance de Widget ou de WidgetFile? Parce que si c'est une instance de Widget il n'obtiendra pas votre fonction delete() personnalisée, qui est dans la classe WidgetFile.

1

Cela semble seulement être plein de sens si un Widget est connecté à un WidgetFile exactement. Dans ce cas, vous devez utiliser un OneToOneField

de On-to-one examples:

# Delete the restaurant; the waiter should also be removed 
>>> r = Restaurant.objects.get(pk=1) 
>>> r.delete() 
+0

vrai en effet, mais Django effectue une suppression de masse au niveau base de données sur tous les serveurs sans déclencher chacune de leurs méthodes de suppression, ce qui est moins cher, mais aussi moins conventionnel. – orokusaki

1

Juste pour jeter de manière possible contourner ce problème: pre-deletesignal. (Cela n'implique en aucun cas qu'il n'y a pas de solution réelle.)

50

que je fais la même chose et remarqué une pépite dans le Django docs que vous devriez penser.

Overriding predefined model methods

Redéfinition Supprimer Notez que la méthode de suppression() pour un objet n'est pas appelé nécessairement lors de la suppression des objets en vrac à l'aide d'un QuerySet. Pour vous assurer que la logique de suppression personnalisée est exécutée, vous pouvez utiliser les signaux pre_delete et/ou post_delete.

Cela signifie que votre extrait ne sera pas toujours faire ce que vous voulez. L'utilisation de Signals est une meilleure option pour traiter les suppressions.

Je suis allé avec les éléments suivants:

import shutil 
from django.db.models.signals import pre_delete 
from django.dispatch import receiver 

@receiver(pre_delete) 
def delete_repo(sender, instance, **kwargs): 
    if sender == Set: 
     shutil.rmtree(instance.repo) 
0

De Django 1.9, si vous voulez bien définir on_delete=models.CASCADE pour le champ, il supprimera tous les objets liés à supprimer.

+0

Ce n'est pas correct. La question ne concerne pas les suppressions en cascade. Il s'agit de s'assurer que les méthodes 'delete' associées sont appelées. – orokusaki

Questions connexes