Open In App

What are transactions in Django?

Last Updated : 08 Jan, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

In this article, we will explore the concept of transactions in Django, using a specific project as our reference point. We will delve into the process of executing transactions in Django and discuss the implementation of the same on the backend of the Django framework the end of this article, readers will gain a comprehensive understanding of handling transactions in Django and be equipped to apply this knowledge to their own projects.

Overview of Transactions in Django

Here we will explain the transaction complete overview below points :

Introduction

Django, a high-level web framework written in Python, offers a robust and efficient way to handle database operations. One essential aspect of managing databases is transactions. In the realm of Django, transactions play a crucial role in ensuring data consistency and reliability. In this article, we will explore the concept of transactions in Django, delving into their advantages, disadvantages, autocommit, savepoints, automatic and non_atomic modes, and the handling of data errors and integrity errors.

What are Transactions in Django?

In Django, transactions refer to a set of operations that are executed as a single unit, ensuring data consistency and integrity in the database. Transactions allow developers to group multiple database queries into a single atomic operation, where either all the changes are committed or none at all. This helps in avoiding partial updates and maintaining a coherent state in case of failures. Django provides a high-level transaction management API, allowing developers to commit or roll back transactions explicitly. By using transactions, developers can safeguard against potential data inconsistencies and ensure that database operations are reliably executed in a controlled manner within the Django framework.

Django Transactions: Advantages & Disadvantages

Django transactions offer significant advantages by providing a mechanism to group multiple database operations into a single atomic unit, ensuring data integrity. The main benefit lies in the ability to maintain consistency in the database state, as if any part of the transaction fails, the entire operation is rolled back. This atomicity guarantees that the database remains in a reliable state even in the face of errors. However, the use of transactions comes with potential disadvantages, particularly in the case of large transactions, which can lead to performance issues, and an extensive reliance on transactions may result in deadlocks, where multiple transactions are unable to proceed, impacting overall system efficiency. Careful consideration of the trade-offs is necessary to strike a balance between ensuring data consistency and minimizing potential performance drawbacks.

Autocommit in Django

In Django, the default behavior for database transactions is autocommit mode. In autocommit mode, each database operation is treated as a separate transaction, and the changes are immediately committed to the database. This is suitable for simple operations, but for more complex tasks that require a group of operations to be executed atomically, developers may need to explicitly manage transactions.

Here’s how autocommit mode is expressed in Django using the @transaction.autocommit decorator:

from django.db import transaction
@transaction.autocommit
def my_function():
# Your code here

In the example above, the my_function will operate in autocommit mode. This means that each database operation within the function will be treated as a separate transaction, and changes will be committed immediately. If an exception occurs during any database operation, the changes made before the exception will still be committed.

Savepoints in Django Transactions

Savepoints in Django transactions allow you to set points within a transaction to which you can later roll back. This provides a level of granularity in managing transactions. The syntax to create a savepoint is as follows:

from django.db import transaction
# Set a savepoint
sid = transaction.savepoint()

Automatic and Non-atomic Transactions

Django transactions can be categorized into automatic and non-atomic. In automatic transactions, the entire operation is treated as a single transaction, and if any part fails, the entire operation is rolled back. The syntax for an automatic transaction is as follows:

from django.db import transaction
@transaction.atomic
def my_view(request):
# Your transactional code here


In contrast, non-atomic transactions do not guarantee atomicity. If an exception occurs within a non-atomic block, the changes made before the exception will be committed. The syntax for a non-atomic transaction is as follows:

from django.db import transaction
@transaction.non_atomic_requests
def my_view(request):
# Your non-atomic code here


Data Errors and Integrity Errors in Django Transactions

Data errors and integrity errors are common issues that can occur during transactions. Data errors include situations where incorrect or unexpected data is encountered, while integrity errors involve violations of database constraints. Handling these errors is essential for maintaining a reliable database system.

The syntax for catching and handling these errors is as follows:

from django.db import IntegrityError, transaction
try:
with transaction.atomic():
# Your transactional code here
except IntegrityError:
# Handle integrity error
except Exception as e:
# Handle other exceptions


Transactions automic, non_atomic Function & handle DatabaseError and IntegrityError

Remember, in a production setting, you might want to log errors or handle them more robustly, but this example illustrates the basic concepts of atomic and non-atomic transactions in Django.

Starting the Project Folder

To install Django follow these steps. To start the project use this command

django-admin startproject myproject
cd myproject


To start the app use this command

python manage.py startapp myapp


Add the app in settings.py file

settings.py

INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"myapp", #app name
]


Setting Necessary Files

models.py : This Django code defines a model named “Book” with three fields: “title” as a character field with a maximum length of 100 characters, “author” as a character field with a maximum length of 50 characters, and “published_date” as a date field.

Python3




from django.db import models
 
class Book(models.Model):
    title = models.CharField(max_length=100)
    author = models.CharField(max_length=50)
    published_date = models.DateField()


views.py: This Django view demonstrates transactions. It creates a book (‘Sample Book’) within an atomic transaction and another book (‘Another Book’) outside an atomic transaction. If any database integrity error occurs, it catches the exception and returns an error message; otherwise, it confirms a successful transaction with an HTTP response.

Python3




from django.db import transaction
from django.db.utils import IntegrityError, DatabaseError
from django.http import HttpResponse
from .models import Book
 
def transaction_example(request):
    try:
        with transaction.atomic():
            # Atomic transaction
            Book.objects.create(title='Sample Book', author='John Doe', published_date='2023-01-01')
 
        # Non-atomic transaction
        book = Book(title='Another Book', author='Jane Doe', published_date='2023-02-01')
        book.save()
 
        return HttpResponse('Transaction successful')
 
    except (IntegrityError, DatabaseError) as e:
        return HttpResponse(f'Transaction failed: {e}')


urls.py: This Django URL configuration maps the path ‘/admin/’ to the Django admin interface and ‘/transaction/’ to the `transaction_example` view from the ‘myapp’ app. The ‘name’ parameter assigns the name ‘transaction_example’ to the URL pattern.

Python3




from django.contrib import admin
from django.urls import path
from myapp.views import *
 
urlpatterns = [
    path('admin/', admin.site.urls),
    path('transaction/', transaction_example, name='transaction_example'),
]


Deployment of the Project

Run these commands to apply the migrations:

python3 manage.py makemigrations
python3 manage.py migrate


createsuperuser using Below command

python3 manage.py createsuperuser


Run the server with the help of following command:

python3 manage.py runserver


Output

Implementation of Transactions in Django

To install Django follow these steps.

Starting the Project Folder

To start the project use this command

django-admin startproject core 
cd core


To start the app use this command

pythom manage.py startapp home


Add the app in settings.py file

Settings.py:

INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"home", #app name
]


File Structure:

file-one-

Setting Necessary Files

models.py: Here, model defines a “Transaction” with two fields: “user” as a character field with a maximum length of 100 characters and a unique constraint, and “amount” as an integer field with a default value of 100. The `__str__` method specifies that the string representation of an instance should be its “user” attribute. This model is designed to store information about transactions, including the user and the transaction amount.

Python3




from django.db import models
 
class Transaction(models.Model):
    user = models.CharField(max_length=100, unique=True)
    amount = models.IntegerField(default=100)
     
    def __str__(self):
        return self.user


views.py : In this file view function, named “home,” handles a POST request to transfer amounts between two user transactions. It retrieves the user input for transaction names (`trans1` and `trans2`) and the transfer amount from the request. Inside a database transaction block, it fetches the corresponding `Transaction` objects, updates their amounts accordingly, and saves the changes. If successful, it displays a success message; otherwise, it displays an error message with details of the exception. The function renders the ‘home.html’ template, likely used for user input and displaying messages.

Python3




from django.shortcuts import render
from django.contrib import messages
from .models import Transaction
from django.db import transaction
  
def home(request):
    if request.method == 'POST':
        try:
            trans1 = request.POST.get('trans1')
            trans2 = request.POST.get('trans2')
            amount = int(request.POST.get('amount'))
              
            # Start a database transaction block
            with transaction.atomic():
                trans1_payment_obj = Transaction.objects.get(user=trans1)
                trans2_payment_obj = Transaction.objects.get(user=trans2)
                      
                trans1_payment_obj.amount -= amount
                trans1_payment_obj.save()
                      
                trans2_payment_obj.amount += amount
                trans2_payment_obj.save()
              
            messages.success(request, "Amount transferred successfully")
        except Exception as e:
            messages.error(request, f"An error occurred: {e}")
      
    return render(request, 'home.html')


Creating GUI

templates/home.html :Here, HTML template presents a form for transferring amounts between two user transactions in a Django app. It includes input fields for “Input One,” “Input Two,” and “Amount.” Success and error messages are styled accordingly. The form uses the POST method with a CSRF token for security. Messages are displayed below the Geeksforgeeks heading in a designated container.

Python3




<!DOCTYPE html>
<html lang="en">
 
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Django Transactions</title>
</head>
<style>
    .gfg{
        color: green;
    }
    .message{
        color: red;
    }
</style>
 
<body>
    <div class="container">
        <h1 class="gfg">Geeksforgeeks</h1>
        {% if messages %}
        {% for message in messages %}
        <div class="message">
            {{message}}
        </div>
        {% endfor %}
        {% endif %}
        <br>
        <form method="POST">
            {% csrf_token %}
            <div class="form-group">
                <label for="userOne">Input One</label>
                <input type="text" name="trans1" id="userOne" placeholder="Enter Input One ">
            </div>
            <br>
            <div class="form-group">
                <label for="userTwo">Input Two</label>
                <input type="text" name="trans2" id="userTwo" placeholder="Enter Input Two">
            </div>
            <br>
            <div class="form-group">
                <label for="amount">Amount</label>
                <input type="text" name="amount" id="amount" placeholder="Enter Amount">
            </div>
            <br>
            <button type="submit">Submit</button>
        </form>
    </div>
</body>
 
</html>


admin.py :Here we are registering our models.

Python3




from django.contrib import admin
from .models import Transaction
  
admin.site.register(Transaction)


urls.py : here, we connect all files in urls.py file

Python3




from django.contrib import admin
from django.urls import path
from home import views
  
urlpatterns = [
    path("admin/", admin.site.urls),  # Admin URL
    path("", views.home),
]


Deployment of the Project

Run these commands to apply the migrations:

python3 manage.py makemigrations
python3 manage.py migrate


createsuperuser using Below command

python3 manage.py createsuperuser


Run the server with the help of following command:

python3 manage.py runserver


Output

final

Video Demonstration

Conclusion

In conclusion, transactions in Django play a crucial role in ensuring the integrity and consistency of the database. They provide a mechanism to group multiple database operations into a single atomic unit, allowing for either the successful completion of all operations or the rollback of any changes in case of an error. Transactions help maintain data integrity and prevent situations where the database is left in an inconsistent state.By using Django’s transaction management features, developers can create robust and reliable applications that can handle concurrent access to the database without risking data corruption.

FAQ’s

1) What is a transaction in Django?

A transaction in Django is a sequence of database operations treated as a single unit of work, ensuring data consistency and integrity.

2) How are transactions managed in Django?

Django manages transactions automatically for each view. Developers can also use @transaction.atomic decorator or with transaction.atomic() for explicit control.

3) What is the purpose of the @transaction.atomic decorator in Django?

It wraps a function in a database transaction, ensuring either the entire block succeeds or fails as a single atomic operation.

4) Can transactions be nested in Django?

Yes, using the @transaction.atomic decorator or with transaction.atomic(). Nested transactions roll back to a savepoint if an exception occurs, allowing the outer transaction to continue

5) How can I handle exceptions and errors within a transaction in Django?

Exceptions within a transaction trigger a rollback. Developers can use try-except blocks for error handling. @transaction.on_commit can execute functions after a successful commit



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads