web-dev-qa-db-fra.com

Django - Rollback save avec transaction atomic

J'essaie de créer une vue où j'enregistre un objet mais je voudrais annuler que enregistrer si une exception est levée. Voici ce que j'ai essayé:

class MyView(View):

    @transation.atomic
    def post(self, request, *args, **kwargs):
        try:
            some_object = SomeModel(...)
            some_object.save()

            if something:
                raise exception.NotAcceptable()
                # When the workflow comes into this condition, I think the previous save should be undome
                # Whant am I missing?

        except exception.NotAcceptable, e:
            # do something

Qu'est-ce que je fais mal? même lorsque l'exception est levée some_object est toujours dans DataBase.

24
Gocht

Documentation d'atomicité

Résumer, @transaction.atomic exécutera une transaction sur la base de données si votre vue produit une réponse sans erreur. Parce que vous interceptez l'exception vous-même, il semble Django que votre vue s'est bien exécutée.

Si vous interceptez l'exception, vous devez la gérer vous-même: Contrôle des transactions

Si vous devez produire une réponse json appropriée en cas d'échec:

from Django.db import SomeError, transaction

def viewfunc(request):
    do_something()

    try:
        with transaction.atomic():
            thing_that_might_fail()
    except SomeError:
        handle_exception()

    render_response()
30
jlucier

Cependant, si une exception se produit dans une fonction décorée avec transaction.atomic, alors vous n'avez rien à faire, cela va revenir automatiquement au point de sauvegarde créé par le décorateur avant d'exécuter votre fonction , comme documenté :

atomic nous permet de créer un bloc de code au sein duquel l'atomicité sur la base de données est garantie. Si le bloc de code est terminé avec succès, les modifications sont validées dans la base de données. S'il existe une exception, les modifications sont annulées.

Si l'exception est interceptée dans un bloc excepté, alors elle devrait être re-augmentée pour qu'atomic l'attrape et fasse le rollback, c'est-à-dire:

    try:
        some_object = SomeModel(...)
        some_object.save()

        if something:
            raise exception.NotAcceptable()
            # When the workflow comes into this condition, I think the previous save should be undome
            # Whant am I missing?

    except exception.NotAcceptable, e:
        # do something
        raise  # re-raise the exception to make transaction.atomic rollback

De plus, si vous voulez plus de contrôle, vous pouvez revenir manuellement à point de sauvegarde précédemment défini , c'est-à-dire:

class MyView(View):
    def post(self, request, *args, **kwargs):
        sid = transaction.savepoint()
        some_object = SomeModel(...)
        some_object.save()

        if something:
            transaction.savepoint_rollback(sid)
        else:
            try:
                # In worst case scenario, this might fail too
                transaction.savepoint_commit(sid)
            except IntegrityError:
                transaction.savepoint_rollback(sid)
14
jpic