Django donne quelques moyens de contrôler la gestion des transactions de base de données.
Le comportement par défaut de Django est de fonctionner en mode de validation automatique (« autocommit »). Chaque requête est immédiatement validée dans la base de données, sauf si une transaction est en cours. Voir ci-dessous pour plus de détails.
Django utilise automatiquement des transactions ou des points de sauvegarde pour garantir l’intégrité des opérations de l’ORM qui nécessitent plusieurs requêtes, particulièrement les requêtes delete() et update().
La classe TestCase de Django englobe aussi chaque test dans une transaction pour des raisons de performance.
Les versions précédentes de Django se comportaient par défaut de manière un peu plus compliquée.
Une façon fréquente de gérer les transactions sur le Web est d’envelopper chaque requête dans une transaction. Définissez ATOMIC_REQUESTS à True dans la configuration de chaque base de données pour laquelle vous souhaitez activer ce comportement.
Voici comment cela fonctionne. Avant d’appeler une fonction de vue, Django démarre une transaction. Si la réponse est renvoyée sans problème particulier, Django valide la transaction. Si la vue génère une exception, Django annule la transaction.
Il est possible d’effectuer des validations ou des annulations partielles dans le code de la vue, typiquement avec le gestionnaire de contexte atomic(). Cependant, quand la vue se termine, soit tous les changements sont validés, soit tous sont annulés.
Avertissement
Bien que la simplicité de ce modèle de transaction est attrayant, il devient inefficace lorsque le trafic augmente. L’ouverture d’une transaction pour chaque vue présente un certain coût. L’impact sur la performance dépend de la manière dont vos applications font usage des requêtes et de la manière dont la base de données gère les verrous.
Transactions par requête et réponses en flux
Lorsqu’une vue renvoie une réponse en flux (StreamingHttpResponse), la lecture du contenu de la réponse exécute fréquemment du code pour générer le contenu. Comme la vue s’est déjà terminée, ce code s’exécute en dehors de la transaction.
De manière générale, il n’est pas conseillé d’écrire dans la base de données durant la génération d’une réponse en flux, car il n’y a plus de méthode raisonnable pour gérer les erreurs après le début de l’envoi de la réponse.
En pratique, cette fonctionnalité ne fait qu’envelopper chaque fonction de vue dans le décorateur atomic() décrit ci-dessous.
Notez que seule l’exécution de la vue est incluse dans la transaction. Les intergiciels s’exécutent en dehors de la transaction, de même que le rendu des réponses par gabarit.
Lorsque ATOMIC_REQUESTS est actif, il est toujours possible d’empêcher les vues de s’exécuter dans une transaction.
Ce décorateur annule l’effet de ATOMIC_REQUESTS pour une vue donnée :
from django.db import transaction
@transaction.non_atomic_requests
def my_view(request):
do_stuff()
@transaction.non_atomic_requests(using='other')
def my_other_view(request):
do_stuff_on_the_other_database()
Cela ne fonctionne que lorsque le décorateur est appliqué à la vue elle-même.
Django fournissait précédemment cette fonctionnalité via l’intergiciel TransactionMiddleware qui est maintenant obsolète.
Django fournit une API unifiée pour contrôler les transactions de base de données.
L’atomicité est la propriété de base des transactions de base de données. atomic permet de créer un bloc de code à l’intérieur duquel l’atomicité est garantie au niveau de la base de données. Si le bloc de code se termine avec succès, les modifications sont validées dans la base de données. Si une exception apparaît, les modifications sont annulées en bloc.
Les blocs atomic peuvent être imbriqués. Dans ce cas, lorsqu’un bloc intérieur se termine avec succès, ses effets peuvent encore être annulés si une exception est générée plus loin dans le bloc englobant.
atomic peut être utilisé comme décorateur :
from django.db import transaction
@transaction.atomic
def viewfunc(request):
# This code executes inside a transaction.
do_stuff()
et comme gestionnaire de contexte :
from django.db import transaction
def viewfunc(request):
# This code executes in autocommit mode (Django's default).
do_stuff()
with transaction.atomic():
# This code executes inside a transaction.
do_more_stuff()
L’insertion d’atomic dans un bloc try/except est une manière naturelle de gérer les erreurs d’intégrité :
from django.db import IntegrityError, transaction
@transaction.atomic
def viewfunc(request):
create_parent()
try:
with transaction.atomic():
generate_relationships()
except IntegrityError:
handle_exception()
add_children()
Dans cet exemple, même si generate_relationships() provoque une erreur de base de données en cassant une contrainte d’intégrité, vous pouvez exécuter des requêtes dans add_children() et les modifications de create_parent() sont toujours présentes. Notez que toute opération exécutée dans generate_relationships() aura déjà été annulée proprement lorsque handle_exception() est appelée, ce qui fait que le gestionnaire d’exception peut très bien agir au niveau de la base de données si nécessaire.
Évitez d’intercepter des exceptions à l’intérieur d’atomic!
À la sortie d’un bloc atomic, Django examine si la sortie se fait normalement ou par une exception afin de déterminer s’il doit valider ou annuler la transaction. Si vous interceptez et gérez des exceptions à l’intérieur du bloc atomic, vous cachez à Django le fait qu’un problème est survenu. Cela peut aboutir à des comportements inattendus.
Ce problème concerne plus spécifiquement les exceptions DatabaseError et ses sous-classes telles que IntegrityError. Après une telle erreur, la transaction est cassée et Django procédera à son annulation dès la sortie du bloc atomic. Si vous essayez d’exécuter des requêtes en base de données avant que l’annulation intervienne, Django générera une exception TransactionManagementError. Vous pouvez également rencontrer ce comportement lorsqu’un gestionnaire de signal lié à l’ORM génère une exception.
La manière correcte d’intercepter les erreurs de base de données est de le faire autour du bloc atomic comme dans l’exemple ci-dessus. Si nécessaire, ajoutez un bloc atomic supplémentaire à cet effet. Cette stratégie présente un autre avantage : elle délimite explicitement les opérations qui seront annulées si une exception se produit.
Si vous interceptez les exceptions générées par des requêtes SQL brutes, le comportement de Django n’est pas défini et dépend de la base de données.
Afin de garantir l’atomicité, atomic désactive certaines API. Si vous tentez de valider une transaction, de l’annuler ou de modifier l’état de validation automatique de la connexion de base de données à l’intérieur d’un bloc atomic, vous obtiendrez une exception.
atomic accepte un paramètre using``devant correspondre au nom d'une base de données. Si ce paramètre n'est pas présent, Django utilise la base de données ``"default".
En arrière-plan, le code de gestion des transactions de Django :
ouvre une transaction lorsqu’il entre dans le premier bloc atomic;
crée un point de sauvegarde lorsqu’il entre dans un bloc atomic imbriqué ;
libère le point de sauvegarde ou annule la transaction jusqu’au point de sauvegarde en quittant le bloc imbriqué ;
valide ou annule la transaction en quittant le bloc de départ.
Vous pouvez désactiver la création de points de sauvegarde pour les blocs imbriqués en définissant le paramètre savepoint à False. Si une exception survient, Django procède à l’annulation de la transaction au moment de quitter le premier bloc ayant un point de sauvegarde, le cas échéant, ou le bloc initial sinon. L’atomicité est toujours garantie par la transaction du bloc initial. Cette option ne devrait être utilisée que si la création des points de sauvegarde affecte les performances de manière évidente. Le désavantage est que cela casse la gestion d’erreurs telle que décrite précédemment.
Il est possible d’utiliser atomic lorsque la validation automatique est désactivée. Seuls des points de sauvegarde seront utilisés, même pour le bloc initial, et une exception est générée si le bloc initial reçoit le paramètre savepoint=False.
Considérations sur la performance
Les transactions ouvertes constituent une pénalité de performance pour votre serveur de base de données. Pour minimiser cet impact, gardez vos transactions aussi brèves que possible. C’est particulièrement important si vous utilisez atomic() dans des processus de longue durée, en dehors du cycle requête/réponse de Django.
Dans le standard SQL, chaque requête SQL démarre une transaction, sauf s’il y en a déjà une en cours. De telles transactions doivent ensuite être explicitement soit validées (commit), soit annulées (rollback).
Ce n’est pas toujours très pratique pour les développeurs d’applications. Pour contourner ce problème, la plupart des bases de données mettent à disposition un mode « autocommit ». Lorsque ce mode est actif et qu’il n’y a pas de transaction ouverte, chaque requête SQL est englobée dans sa propre transaction. En d’autres termes, chacune de ces requêtes non seulement démarre une transaction, mais cette transaction est aussi automatiquement validée ou annulée en fonction du résultat de la requête.
PEP 249, la spécification d’API de base de données Python v2.0, exige que le mode autocommit soit initialement désactivé. Django surcharge ce comportement par défaut et active le mode autocommit.
Pour empêcher cela, vous pouvez désactiver la gestion des transactions, mais ce n’est pas recommandé.
Avant Django 1.6, le mode autocommit était désactivé et il était émulé en forçant un commit au niveau de l’ORM après les opérations d’écriture.
Vous pouvez désactiver totalement la gestion des transactions de Django pour une base de données précise en définissant AUTOCOMMIT à False dans sa configuration. Si vous faites cela, Django n’activera pas le mode autocommit et n’effectue aucune opération de commit. Vous obtenez alors le comportement habituel de la bibliothèque de base de données sous-jacente.
Cela demande que vous effectuiez un commit explicite de chaque transaction, même de celles initiées par Django ou par des bibliothèques tierces. Ainsi, cela convient mieux à des situations où vous souhaitez mettre en place votre propre intergiciel de gestion des transactions ou que vous faites des choses plutôt étranges.
Ce comportement était contrôlé par le réglage TRANSACTIONS_MANAGED.
Avertissement
Si possible, préférez toujours atomic(). Il prend en compte les particularités de chaque base de données et évite les opérations non valides.
L’API de bas niveau n’est utile que si vous implémentez votre propre gestion des transactions.
Django fournit une API basique dans le module django.db.transaction pour gérer l’état de validation automatique de chaque connexion de base de données.
Ces fonctions acceptent un paramètre using qui doit correspondre au nom d’une base de données. Si ce paramètre n’est pas présent, Django utilise la base de données "default".
La validation automatique (« autocommit ») est initialement activée. Si vous la désactivez, il est de votre responsabilité de la restaurer ensuite.
Dès que vous désactivez la validation automatique, vous obtenez le comportement par défaut de votre adaptateur de base de données et Django ne vous aide plus. Même si ce comportement fait l’objet de la PEP 249, les implémentations des adaptateurs ne sont pas toujours cohérentes entre elles. Parcourez attentivement la documentation de l’adaptateur que vous utilisez.
Vous devez vous assurer qu’aucune transaction n’est pendante, généralement en appelant commit() ou rollback() avant de réactiver la validation automatique.
Django refuse de désactiver la validation automatique lorsqu’un bloc atomic() est actif, car l’atomicité ne serait alors plus respectée.
Une transaction est un ensemble atomique de requêtes de base de données. Même si votre programme se plante, la base de données garantit que soit tous les changements seront appliqués, soit aucun.
Django n’offre pas d’API pour démarrer une transaction. La manière attendue de démarrer une transaction est de désactiver la validation automatique avec
Une fois dans la transaction, vous pouvez choisir d’appliquer les modifications effectuées jusqu’à ce point avec commit(), ou de toutes les annuler avec rollback(). Ces fonctions sont définies dans django.db.transaction.
Ces fonctions acceptent un paramètre using qui doit correspondre au nom d’une base de données. Si ce paramètre n’est pas présent, Django utilise la base de données "default".
Django refuse de valider ou d’annuler une transaction lorsqu’un bloc atomic() est actif, car l’atomicité ne serait alors plus respectée.
Un point de sauvegarde est un marqueur dans une transaction qui vous permet d’annuler une transaction en partie, plutôt que dans sa totalité. Les points de sauvegarde sont disponibles pour les moteurs SQLite (≥ 3.6.8), PostgreSQL, Oracle et MySQL (avec le moteur de stockage InnoDB). D’autres moteurs fournissent les fonctions des points de sauvegarde, mais ces fonctions sont vides, elles ne font rien du tout.
Les points de sauvegarde ne sont pas particulièrement utiles quand la validation automatique est active, ce qui est le comportement par défaut de Django. Cependant, dès que vous ouvrez une transaction avec atomic(), vous accumulez une série d’opérations de base de données en attente de validation ou d’annulation. Lorsque vous annulez avec un « rollback », toute la transaction est annulée Les points de sauvegarde permettent d’annuler des opérations de manière plus sélective, plutôt que d’annuler en bloc comme le fait transaction.rollback().
Lorsque le décorateur atomic() est imbriqué, il crée un point de sauvegarde pour permettre une validation ou une annulation partielle. Vous êtes fortement encouragé à utiliser atomic() plutôt que les fonctions présentées ci-dessous, mais elles font tout de même partie de l’API publique, et il n’est pas prévu de les rendre obsolètes.
Chacune de ces fonctions accepte un paramètre using devant correspondre au nom de la base de données pour laquelle le comportement s’applique. Si aucun paramètre using n’est transmis, c’est la base de données "default" qui est utilisée.
Les points de sauvegarde sont contrôlés par trois fonctions dans django.db.transaction:
Crée un nouveau point de sauvegarde. Un point est marqué dans la transaction, à un état qui est reconnu comme « bon ». Renvoie l’identifiant du point de sauvegarde (sid).
Libère le point de sauvegarde sid. Les modifications effectuées depuis la création du point de sauvegarde sont intégrées dans la transaction.
Annule la transaction en revenant au point de sauvegarde sid.
Ces fonctions ne font rien si les points de sauvegarde ne sont pas pris en charge ou si la base de données est en mode de validation automatique.
Une fonction utilitaire est également disponible :
Réinitialise le compteur utilisé pour générer les identifiants uniques des points de sauvegarde.
L’exemple suivant illustre l’utilisation des points de sauvegarde :
from django.db import transaction
# open a transaction
@transaction.atomic
def viewfunc(request):
a.save()
# transaction now contains a.save()
sid = transaction.savepoint()
b.save()
# transaction now contains a.save() and b.save()
if want_to_keep_b:
transaction.savepoint_commit(sid)
# open transaction still contains a.save() and b.save()
else:
transaction.savepoint_rollback(sid)
# open transaction now contains only a.save()
Les points de sauvegarde peuvent être utilisés pour se rétablir après une erreur de base de données en effectuant une annulation partielle des opérations. Si vous faites cela à l’intérieur d’un bloc atomic(), tout le bloc sera quand même annulé, car Django ne sait pas que vous avez géré la situation à un plus bas niveau ! Pour empêcher cela, vous pouvez contrôler le comportement d’annulation avec les fonctions suivantes.
En définissant le drapeau rollback à True, vous forcez une annulation lorsque vous sortez du bloc atomic le plus proche. Cela peut être utile pour provoquer une annulation sans générer d’exception.
En le définissant à False, vous empêchez une telle annulation. Avant de faire cela, assurez-vous d’avoir bien annulé la transaction jusqu’à un point de sauvegarde en bon état à l’intérieur du bloc atomic actuel. Sinon, vous cassez l’atomicité et des corruptions de données peuvent apparaître.
Même si les points de sauvegarde sont pris à charge à partir de SQLite ≥ 3.6.8, un défaut de conception dans le module sqlite3 les rend presque inutilisables.
Lorsque la validation automatique est active, les points de sauvegarde n’ont pas de raison d’être. Dans le cas contraire, sqlite3 valide implicitement la transaction avant les instructions de points de sauvegarde (en fait, il valide avant toute instruction autre que SELECT, INSERT, UPDATE, DELETE et REPLACE). Ce bogue a deux conséquences :
Si vous utilisez MySQL, la prise en charge des transactions par vos tables varie ; tout dépend de la version de MySQL et des types de tables que vous utilisez (par « type de table », nous entendons quelque chose comme « InnoDB » ou « MyISAM »). Les particularités des transactions de MySQL vont au-delà du thème de cette documentation, mais le site de MySQL possède des informations sur les transactions dans MySQL.
Si votre configuration MySQL ne gère pas les transactions, Django fonctionne toujours en mode de validation automatique : les instructions sont exécutées et validées dès qu’elles sont émises. Si votre configuration MySQL gère les transactions, Django traite les transactions comme expliqué dans ce document.
Note
Cette section n’a de sens que si vous implémentez votre propre gestion des transactions. Ce problème ne peut pas survenir dans le mode par défaut de Django et atomic() s’en charge automatiquement.
À l’intérieur d’une transaction, lorsque l’appel à un curseur PostgreSQL génère une exception (typiquement IntegrityError), toutes les commandes SQL suivantes dans la même transaction échouent avec l’erreur « current transaction is aborted, queries ignored until end of transaction block ». Bien qu’il soit improbable qu’une utilisation simple de save() génère une exception avec PostgreSQL, il y a des schémas d’utilisation plus pointus qui sont susceptibles de le faire, comme l’enregistrement d’objets avec des champs uniques, l’enregistrement avec les options force_insert/force_update ou l’appel à des instructions SQL personnalisées.
Il existe plusieurs manières de se sortir de ce genre d’erreurs.
La première option est d’annuler la totalité de la transaction. Par exemple :
a.save() # Succeeds, but may be undone by transaction rollback
try:
b.save() # Could throw exception
except IntegrityError:
transaction.rollback()
c.save() # Succeeds, but a.save() may have been undone
L’appel de transaction.rollback() annule la totalité de la transaction. Toute opération de base de données non validée sera perdue. Dans cet exemple, les modifications effectuées par a.save() seront perdues, même si cette opération n’a pas elle-même généré d’erreur.
Vous pouvez utiliser des points de sauvegarde pour contrôler l’étendue d’une annulation. Avant d’effectuer une opération de base de données potentiellement délicate, vous pouvez définir ou mettre à jour le point de sauvegarde ; de cette façon, si l’opération échoue, vous pouvez annuler précisément l’opération concernée, plutôt que la totalité de la transaction. Par exemple :
a.save() # Succeeds, and never undone by savepoint rollback
sid = transaction.savepoint()
try:
b.save() # Could throw exception
transaction.savepoint_commit(sid)
except IntegrityError:
transaction.savepoint_rollback(sid)
c.save() # Succeeds, and a.save() is never undone
Dans cet exemple, a.save() ne sera pas annulé dans le cas où b.save() génère une exception.
Les fonctionnalités décrites ci-dessous sont obsolètes à partir de Django 1.6 et seront supprimées dans Django 1.8. Elles sont documentées afin de faciliter la migration vers la nouvelle API de gestion des transactions.
Les fonctions suivantes, définies dans django.db.transaction, fournissaient une manière de contrôler les transactions par fonction ou par bloc de code. Elles pouvaient être utilisées comme décorateurs ou comme gestionnaires de contexte, et elles acceptaient un paramètre using, tout comme atomic().
Active le comportement de validation automatique par défaut de Django.
Les transactions sont validées dès que vous appelez model.save(), model.delete() ou toute autre fonction qui écrit dans la base de données.
Utilise une transaction unique pour toutes les opérations effectuées dans une fonction.
Si la fonction se termine avec succès, Django valide (dans le sens de « commit ») toutes les opérations effectuées dans la fonction jusqu’à ce point. Cependant, si la fonction génère une exception, Django annule (dans le sens de « rollback ») la transaction.
Indique à Django que vous allez gérer vous-même les transactions.
Que vous écriviez ou que vous lisiez simplement depuis la base de données, vous devez appeler explicitement commit() ou rollback() ou Django générera une exception TransactionManagementError. C’est obligatoire même en lisant depuis la base de données car les commandes SELECT peuvent appeler des fonctions modifiant potentiellement des tables, ce qui fait qu’il est impossible de savoir si des données ont été modifiées ou non.
Les trois fonctions décrites ci-dessus se basent sur un concept nommé « états des transactions ». Ce mécanisme a été rendu obsolète dans Django 1.6, mais il sera encore disponible jusqu’à Django 1.8.
À tout instant, une connexion de base de données est dans l’un de ces deux états :
mode « auto »: la validation automatique est activée ;
mode « managed »: la validation automatique est désactivée.
Django démarre en mode « auto ». TransactionMiddleware, commit_on_success() et commit_manually() activent le mode « managed » ; autocommit() active le mode « auto ».
En interne, Django conserve une pile d’états. Les activations et les désactivations doivent être équilibrées.
Par exemple, commit_on_success() bascule en mode « managed » lorsqu’on entre dans le code qu’il contrôle ; à la sortie du bloc, il valide ou annule et repasse en mode « auto ».
So commit_on_success() really has two effects: it changes the transaction state and it defines a transaction block. Nesting will give the expected results in terms of transaction state, but not in terms of transaction semantics. Most often, the inner block will commit, breaking the atomicity of the outer block.
autocommit() et commit_manually() présentent les mêmes problèmes.
Dans Django 1.6, TransactionMiddleware est obsolète et remplacé par ATOMIC_REQUESTS. Même si le fonctionnement général est le même, il y a deux différences.
Avec l’ancienne API, il était possible de passer en mode validation automatique ou de valider explicitement n’importe où dans une vue. Comme ATOMIC_REQUESTS compte sur atomic() pour garantir l’atomicité, ce n’est plus autorisé. Cependant, à un plus haut niveau, il est encore possible d’éviter d’envelopper toute la vue dans une transaction. À cet effet, décorez la vue avec non_atomic_requests() au lieu de autocommit().
L’intergiciel de transaction ne s’appliquait pas qu’aux fonctions de vue, mais aussi aux modules d’intergiciel qui lui succédaient. Par exemple, si vous aviez placé l’intergiciel de session après l’intergiciel de transaction, la création des sessions faisaient partie de la transaction. ATOMIC_REQUESTS ne s’applique qu’à la vue elle-même.
À partir de Django 1.6, atomic() est la seule API prise en charge pour définir une transaction. Au contraire de l’API obsolète, l’imbrication est possible et garantit toujours l’atomicité.
Dans la plupart des cas, il s’agira simplement de remplacer commit_on_success() par atomic().
Durant la période d’obsolescence, il est possible d’utiliser atomic() à l’intérieur de autocommit(), commit_on_success() ou commit_manually(). Cependant, l’inverse est défendu, car l’imbrication des anciens décorateurs/gestionnaires de contexte casse l’atomicité.
Django 1.6 introduit une API explicite pour la gestion de la validation automatique.
Pour désactiver temporairement la validation automatique, au lieu de :
with transaction.commit_manually():
# do stuff
il faut dorénavant utiliser :
transaction.set_autocommit(False)
try:
# do stuff
finally:
transaction.set_autocommit(True)
Pour activer temporairement la validation automatique, au lieu de :
with transaction.autocommit():
# do stuff
il faut dorénavant utiliser :
transaction.set_autocommit(True)
try:
# do stuff
finally:
transaction.set_autocommit(False)
Sauf dans le cas où vous implémentez un système de gestion des transactions, vous ne devriez jamais avoir besoin de faire cela.
Au lieu de définir TRANSACTIONS_MANAGED = True, définissez la clé AUTOCOMMIT à False dans la configuration de chaque base de données, comme expliqué dans Désactivation de la gestion des transaction.
Depuis la version 1.6, Django utilise la validation automatique au niveau de la base de données en mode automatique. Précédemment, il utilisait la validation automatique au niveau applicatif en provoquant une validation (« commit ») après chaque écriture de l’ORM.
Par conséquent, chaque requête de base de données (par exemple, une lecture par l’ORM) démarrait une transaction qui durait jusqu’à l’écriture suivante par l’ORM. De telles « transactions automatiques » n’existent plus dans Django 1.6.
Il y a quatre scénarios pour lesquels ce nouveau comportement est incompatible.
Notez que le mode « managed » n’est pas touché du tout. Cette section présuppose l’utilisation du mode automatique. Voir la ref:description des modes <transaction-states> ci-dessus.
Si vous exécutez plusieurs requêtes SQL personnalisées à la suite, chacune s’exécute dorénavant dans sa propre transaction, au lieu de partager la même « transaction automatique ». Si vous avez besoin de garantir l’atomicité, vous devez entourer la suite de requêtes par un bloc atomic().
Pour savoir si ce problème existe, faites une recherche de cursor.execute(). Ces appels sont généralement suivis par un appel à transaction.commit_unless_managed(), qui ne sert plus à rien et qui devrait être enlevé.
Si vous comptiez sur les « transactions automatiques » pour se charger du verrouillage entre select_for_update() et l’opération d’écriture qui suit, une structure très fragile, mais néanmoins possible, vous devez maintenant envelopper le code concerné dans atomic(). À partir de Django 1.6.3, l’exécution d’une requête avec select_for_update() en mode autocommit génère une exception TransactionManagementError.
Si vous utilisiez le niveau d’isolation « repeatable read » ou plus élevé et que vous comptiez sur les « transactions automatiques » pour garantir la cohérence entre plusieurs lectures successives, le nouveau comportement modifie votre attente de manière incompatible. Pour garantir cette cohérence des lectures, vous devez envelopper ces instructions successives dans un bloc
Le niveau d’isolation par défaut de MySQL est « repeatable read » et celui de SQLite est « serializable » ; ils peuvent donc être concernés par ce problème.
Au niveau d’isolation « read committed » ou plus bas, les « transactions automatiques » n’ont aucun effet sur la sémantique de suites d’opérations de l’ORM.
Le niveau d’isolation par défaut de PostgreSQL et Oracle est « read committed » ; ils ne sont donc pas concernés pour autant que vous n’ayez pas changé le niveau d’isolation.
Avec les déclencheurs (triggers), les vues ou les fonctions, il est possible que des lectures par l’ORM aboutissent à des modifications en base de données. Django 1.5 et les versions précédentes ne se préoccupaient pas de cette question, et il est théoriquement possible d’observer un comportement différent après avoir passé à Django 1.6. Dans le doute, utilisez atomic() pour garantir l’intégrité.
Jan 13, 2016