2011-01-21 4 views
0

Dans mon application Django, j'ai un code qui supprime une seule instance d'un modèle de la base de données. Il est possible que deux demandes simultanées tentent toutes deux de supprimer le même modèle en même temps. Dans ce cas, je veux qu'une demande réussisse et que l'autre échoue. Comment puis-je faire ceci?Suppression en toute sécurité d'un modèle Django de la base de données à l'aide d'une transaction

Le problème est que lors de la suppression d'une instance avec delete(), Django ne renvoie aucune information indiquant si la commande a réussi ou non. Ce code illustre le problème:

b0 = Book.objects.get(id=1) 
b1 = Book.objects.get(id=1) 
b0.delete() 
b1.delete() 

Un seul de ces deux commandes delete() effectivement supprimé l'objet, mais je ne sais pas lequel. Aucune exception n'est levée et rien n'est retourné pour indiquer le succès de la commande. En SQL pur, la commande renverrait le nombre de lignes supprimées et si la valeur était 0, je saurais que ma suppression a échoué. J'utilise PostgreSQL avec le niveau d'isolation Read Commited par défaut. Ma compréhension de ce niveau est que chaque commande (SELECT, DELETE, etc.) voit un instantané de la base de données, mais que la commande suivante pourrait voir un instantané différent de la base de données. Je crois que cela signifie que je ne peux pas faire quelque chose comme ceci:

# I believe this wont work 
@commit_on_success 
def view(request): 
    try: 
    book = Book.objects.get(id=1) 
    # Possibility that the instance is deleted by the other request 
    # before we get to the next delete() 
    book.delete() 
    except ObjectDoesntExist: 
    # Already been deleted 

Toutes les idées?

Répondre

4

Vous pouvez mettre la contrainte à droite dans l'instruction SQL supprimer à l'aide QuerySet.delete au lieu de Model.delete:

Book.objects.filter(pk=1).delete() 

Ce ne sera jamais émettre la requête SELECT du tout, juste quelque chose le long des lignes de:

DELETE FROM Book WHERE id=1; 

qui gère la condition de course de deux requêtes simultanées suppression du même enregistrement en même temps, mais il ne sait pas si vous laissez votre suppression est arrivé en premier. Pour cela, vous devez obtenir le curseur brut (django lets you do), .execute() ci-dessus DELETEZ-vous, puis sélectionnez l'attribut rowcount du curseur, qui sera 0 si vous n'avez rien supprimé.

Questions connexes