Overview
En esta guía, aprenderá a usar Django MongoDB Backend para realizar transacciones. Las transacciones permiten ejecutar una serie de operaciones que modifican los datos solo si se confirma la transacción completa. Si alguna operación de la transacción no se realiza correctamente, Django MongoDB Backend la detiene y descarta todos los cambios en los datos antes de que sean visibles. Esta característica se denomina atomicidad.
En MongoDB, las transacciones se ejecutan dentro de sesiones lógicas. Una sesión es una agrupación de operaciones de lectura o escritura relacionadas que se ejecutan secuencialmente. Las sesiones permiten la consistencia causal de un grupo de operaciones y ejecutarlas en una transacción compatible con ACID, que cumple con los requisitos de atomicidad, consistencia, aislamiento y durabilidad.
La API de transacciones nativa de Django no es compatible, pero Django MongoDB Backend ofrece una API de transacciones personalizada que habilita la misma funcionalidad. Para ejecutar operaciones dentro de una transacción, defínalas dentro de un bloque de código atómico. Django MongoDB Backend gestiona la lógica de la sesión internamente, por lo que no es necesario iniciar una sesión manualmente antes de ejecutar una transacción.
Importante
Limitaciones de las transacciones
La API de transacciones del backend de Django MongoDB tiene varias limitaciones. Para ver una lista de limitaciones, consulte Compatibilidad de bases de datos y colecciones en la guía de compatibilidad de funciones de Django y MongoDB.
Datos de muestra
Los ejemplos de esta guía utilizan el Movie modelo, que representa la colección sample_mflix.movies de la Conjuntos de datos de muestra de Atlas. La Movie clase de modelo tiene la siguiente definición:
from django.db import models from django_mongodb_backend.fields import ArrayField class Movie(models.Model): title = models.CharField(max_length=200) plot = models.TextField(blank=True) runtime = models.IntegerField(default=0) released = models.DateTimeField("release date", null=True, blank=True) genres = ArrayField(models.CharField(max_length=100), null=True, blank=True) class Meta: db_table = "movies" managed = False def __str__(self): return self.title
El Movie modelo incluye una Meta clase interna, que especifica los metadatos del modelo, y un __str__() método, que define la representación de cadena del modelo. Para obtener más información sobre estas características del modelo,consulte "Definir un modelo" en la guía "Crear modelos".
Ejecutar ejemplos de código
Puedes usar el shell interactivo de Python para ejecutar los ejemplos de código. Para acceder al shell, ejecuta el siguiente comando desde el directorio raíz de tu proyecto:
python manage.py shell
Después de ingresar al shell de Python, asegúrese de importar los siguientes modelos y módulos:
from <your application name>.models import Movie from django.utils import timezone from datetime import datetime
Para aprender a crear una aplicación Django que use el Movie modelo y el shell interactivo de Python para interactuar con documentos MongoDB, visita el tutorial Primeros pasos.
Iniciar una transacción
Para iniciar una transacción de base de datos, llame a la función django_mongodb_backend.transaction.atomic(). Puede usar esta función como decorador o gestor de contexto.
Asegúrese de importar el módulo transaction mediante la siguiente declaración de importación:
from django_mongodb_backend import transaction
Utilice un decorador
Puede iniciar una transacción de base de datos añadiendo el decorador @transaction.atomic encima de su función. Este decorador garantiza la atomicidad de cualquier operación de base de datos dentro de la función. Si la función se completa correctamente, los cambios se confirman en MongoDB.
El siguiente ejemplo llama al método create() dentro de una transacción, que inserta un documento en la colección sample_mflix.movies si la transacción tiene éxito:
def insert_movie_transaction(): Movie.objects.create( title="Poor Things", runtime=141, genres=["Comedy", "Romance"] )
Utilice un administrador de contexto
Como alternativa, puede usar el administrador de contexto transaction.atomic() para crear un bloque de código atómico. Este ejemplo ejecuta la misma operación que el ejemplo anterior, pero usa un administrador de contexto para iniciar una transacción:
def insert_movie_transaction(): with transaction.atomic(): Movie.objects.create( title="Poor Things", runtime=141, genres=["Comedy", "Romance"] )
Ejecutar devoluciones de llamadas después de una transacción
Para realizar ciertas acciones solo si una transacción se completa correctamente, puede usar la función transaction.on_commit(). Esta función permite registrar devoluciones de llamada que se ejecutan después de confirmar una transacción en la base de datos. Pase una función, o cualquier objeto invocable, como argumento a on_commit().
El siguiente ejemplo busca películas que tengan un valor genre de ["Horror", "Comedy"] solo después de que se complete una transacción de base de datos relacionada:
def get_horror_comedies(): movies = Movie.objects.filter(genres=["Horror", "Comedy"]) for m in movies: print(f"Title: {m.title}, runtime: {m.runtime}") def insert_movie_with_callback(): with transaction.atomic(): Movie.objects.create( title="The Substance", runtime=140, genres=["Horror", "Comedy"] ) transaction.on_commit(get_horror_comedies)
Gestiona los errores de las transacciones
Para gestionar las excepciones que ocurren durante una transacción, agrega lógica de manejo de errores alrededor de tu bloque de código atómico. Si decides gestionar los errores dentro del bloque atómico, podrías ocultar esos errores a Django. Puesto que Django utiliza errores para determinar si se debe confirmar o revertir una transacción, esto puede causar un comportamiento inesperado.
Si una transacción no se completa correctamente, Django no revierte los cambios realizados en los campos de un modelo. Para evitar inconsistencias entre los modelos y los documentos de la base de datos, es posible que deba restaurar manualmente los valores originales de los campos.
Ejemplo
El siguiente ejemplo incluye lógica de manejo de errores que revierte el valor title modificado del documento recuperado si falla la transacción de la base de datos:
movie = Movie.objects.get(title="Jurassic Park") movie.title = "Jurassic Park I" try: with transaction.atomic(): movie.save() except DatabaseError: movie.title = "Jurassic Park" if movie.title == "Jurassic Park I": movie.plot = "An industrialist invites experts to visit his theme park of cloned dinosaurs. After a power failure," \ " the creatures run loose, putting everyone's lives, including his grandchildren's, in danger." movie.save()
Dado que el código realiza una segunda operación de base de datos basada en el valor title del modelo, revertir el cambio si la transacción falla evita más inconsistencias en los datos.
Información Adicional
Para obtener más información sobre la API de transacciones de Django, consulte Transacciones de base de datos en la documentación de Django.