web-dev-qa-db-fra.com

Comment puis-je remplacer delete () sur un modèle et le laisser fonctionner avec les suppressions associées

J'ai un problème parce que je supprime un widget en utilisant some_widget_instance.delete (). J'ai également un modèle appelé WidgetFile avec une méthode override delete () afin de pouvoir supprimer des fichiers de mon disque dur lorsqu'un fichier WidgetFile est supprimé. Le problème que je rencontre est que si je supprime un widget, il contient des fichiers Widget comme ceci:

class WidgetFile(models.Model):

    widget = models.ForeignKey(Widget)

Eh bien, lorsque je supprime ce widget, ce sont des fichiers Widget qui sont supprimés, mais la méthode delete () ne déclenche pas et ne gère pas le contenu de mon disque dur supplémentaire. Toute aide est très appréciée.

20
orokusaki

Je l'ai compris. Je viens de mettre ceci sur ce modèle de widget:

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

Cela a déclenché la méthode delete () nécessaire sur chacun des objets liés, entraînant ainsi la suppression du code par mon fichier personnalisé. La base de données coûte certes plus cher, mais quand vous essayez de supprimer des fichiers sur un disque dur, ce n'est pas une grosse dépense de frapper la base de données quelques fois de plus.

31
orokusaki

Je fais la même chose et j'ai remarqué une pépite dans la documentation Django à laquelle vous devriez penser.

Remplacement des méthodes de modèle prédéfinies

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

Cela signifie que votre extrait ne fera pas toujours faire ce que vous voulez. Utiliser Signaux est une meilleure option pour traiter les suppressions.

Je suis allé avec ce qui suit:

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)
60
ElementalVoid

L'utilisation de clear() avant la suppression supprime tous les objets du jeu d'objets associés.

voir Django-suivantes-relations-arriérées

exemple:

group.link_set.clear() 
group.delete() 
2
panchicore

Cela ne semble avoir du sens que si un Widget est connecté à un WidgetFile exactement. Dans ce cas, vous devez utiliser un OneToOneField

from Exemples on-to-one:

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

Juste pour jeter un moyen possible autour de ce problème: pré-supprimersignaler . (Cela ne signifie nullement qu'il n'y a pas de solution réelle.)

1
che

Il devrait ressembler à ce qui est décrit sur le site Django :

class Blog(models.Model):
    name = models.CharField(max_length=100)
    tagline = models.TextField()
    def save(self, *args, **kwargs):
        do_something()
        super(Blog, self).save(*args, **kwargs) # Call the "real" save() method.
        do_something_else()

http://docs.djangoproject.com/fr/dev/topics/db/models/#overriding-predefined-model-methods

vous avez oublié de passer des arguments

1

Est-ce que some_widget_instance et une instance de Widget ou de WidgetFile? Parce que s'il s'agit d'une instance de Widget, il n'obtiendra pas votre fonction delete() personnalisée, qui se trouve dans la classe WidgetFile.

0
thornomad

À partir de Django 1.9, si vous définissez simplement on_delete=models.CASCADE pour le champ, tous les objets liés seront supprimés.

0
CLTanuki