Paramclasses Academy - Blog

Tutorials Details

Django CRUD Operations: Create, Read, Update and Delete with Practical Examples

Django CRUD Operations: Create, Read, Update and Delete with Practical Examples

October 19, 2026

Django CRUD Operations: Create, Read, Update and Delete with Practical Examples

1. Introduction to Django CRUD Operations

CRUD stands for Create, Read, Update, and Delete. These are the four fundamental operations used to manage data in a database.

In Django, CRUD operations allow you to build applications where users can add records, view existing information, update records, and remove data when necessary.

For example, in a Student Management System:

  • Create: Add a new student.

  • Read: Display a list of students or view individual student details.

  • Update: Edit a student's information.

  • Delete: Remove a student record.

Django provides models, views, URL routing, templates, and its Object-Relational Mapper (ORM) to implement CRUD functionality.

What You Will Learn

  • Create and configure a Django model.

  • Display database records in HTML templates.

  • Add new records using ModelForm.

  • Update existing records.

  • Delete records safely using POST requests.

  • Configure URL patterns for CRUD operations.

  • Display success messages and handle missing records.

  • Build a complete Student Management CRUD application.

2. Project Structure

Assume that your Django project is named school_project and your application is named students.

Your project structure should look like this:

school_project/
├── manage.py
├── school_project/
│   ├── settings.py
│   └── urls.py
└── students/
    ├── models.py
    ├── forms.py
    ├── views.py
    ├── urls.py
    └── templates/
        └── students/
            ├── base.html
            ├── student_list.html
            ├── student_form.html
            └── student_confirm_delete.html

Ensure that the students app is included in INSTALLED_APPS inside settings.py.

3. Creating the Student Model

Open students/models.py and add the following code:

from django.db import models


class Student(models.Model):
    name = models.CharField(max_length=100)
    email = models.EmailField(unique=True)
    phone = models.CharField(max_length=15)
    course = models.CharField(max_length=100)
    city = models.CharField(max_length=100)
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.name

Understanding the Model

  • models.Model makes the class a Django model.

  • CharField stores text with a defined maximum length.

  • EmailField stores an email address and performs basic format validation.

  • unique=True prevents duplicate email values at the database level.

  • DateTimeField stores date and time information.

  • auto_now_add=True records the creation timestamp.

  • __str__() provides a readable representation of the student.

Apply Database Migrations

Run these commands in your terminal:

python manage.py makemigrations
python manage.py migrate

The first command generates migration files for model changes. The second applies pending migrations to the database.

4. Creating a ModelForm

A ModelForm makes it easier to create and validate forms based on a Django model.

Create or update students/forms.py:

from django import forms
from .models import Student


class StudentForm(forms.ModelForm):
    class Meta:
        model = Student
        fields = [
            'name',
            'email',
            'phone',
            'course',
            'city',
        ]

Why Use ModelForm?

  • It generates form fields from the model.

  • It applies relevant field validation.

  • It supports model-related validation.

  • It makes saving validated data easier.

  • It reduces repetitive form code.

Explicitly listing the fields helps prevent unintended model fields from being exposed in the form.

5. Creating the CRUD Views

Open students/views.py and add the following complete example:

from django.contrib import messages
from django.shortcuts import (
    render,
    redirect,
    get_object_or_404
)

from .models import Student
from .forms import StudentForm


def student_list(request):
    students = Student.objects.all().order_by('-id')

    return render(
        request,
        'students/student_list.html',
        {'students': students}
    )


def student_create(request):
    if request.method == 'POST':
        form = StudentForm(request.POST)

        if form.is_valid():
            form.save()

            messages.success(
                request,
                'Student added successfully.'
            )

            return redirect('student_list')
    else:
        form = StudentForm()

    return render(
        request,
        'students/student_form.html',
        {
            'form': form,
            'page_title': 'Add Student',
        }
    )


def student_update(request, student_id):
    student = get_object_or_404(Student, id=student_id)

    if request.method == 'POST':
        form = StudentForm(request.POST, instance=student)

        if form.is_valid():
            form.save()

            messages.success(
                request,
                'Student updated successfully.'
            )

            return redirect('student_list')
    else:
        form = StudentForm(instance=student)

    return render(
        request,
        'students/student_form.html',
        {
            'form': form,
            'page_title': 'Edit Student',
        }
    )


def student_delete(request, student_id):
    student = get_object_or_404(Student, id=student_id)

    if request.method == 'POST':
        student.delete()

        messages.success(
            request,
            'Student deleted successfully.'
        )

        return redirect('student_list')

    return render(
        request,
        'students/student_confirm_delete.html',
        {'student': student}
    )

Understanding Each View

student_list()

Retrieves student records from the database and passes them to the list template.

student_create()

Displays an empty form for GET requests. For POST requests, it validates the submitted data and saves a new student if validation succeeds.

student_update()

Retrieves an existing student and uses instance=student to populate the form with the current values. A valid submission updates the existing record instead of creating a new one.

student_delete()

Displays a confirmation page for GET requests. It deletes the record only after receiving a POST request.

get_object_or_404()

Retrieves the requested object or returns an HTTP 404 response if the object does not exist.

Django messages

The messages framework displays temporary feedback, such as successful creation, updating, or deletion. Django's default messages app and middleware should remain enabled in settings.py.

6. Configuring CRUD URLs

Create or update students/urls.py:

from django.urls import path
from . import views

urlpatterns = [
    path(
        'students/',
        views.student_list,
        name='student_list'
    ),

    path(
        'students/add/',
        views.student_create,
        name='student_create'
    ),

    path(
        'students/<int:student_id>/edit/',
        views.student_update,
        name='student_update'
    ),

    path(
        'students/<int:student_id>/delete/',
        views.student_delete,
        name='student_delete'
    ),
]

Now include the app URLs in school_project/urls.py:

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('students.urls')),
]

Understanding the URL Patterns

URL Purpose
/students/ Display all students
/students/add/ Create a new student
/students/1/edit/ Edit student with ID 1
/students/1/delete/ Confirm deletion of student with ID 1

The number in the edit and delete URLs represents the student's database ID.

7. Creating a Base Template

Create students/templates/students/base.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <title>
        {% block title %}Student Management System{% endblock %}
    </title>

    <style>
        body {
            font-family: Arial, sans-serif;
            background: #f4f7fb;
            margin: 0;
            padding: 24px;
        }

        .container {
            max-width: 1100px;
            margin: auto;
            background: white;
            padding: 24px;
            border-radius: 10px;
        }

        a, button {
            cursor: pointer;
        }

        .btn {
            display: inline-block;
            padding: 9px 14px;
            margin: 4px;
            border: none;
            border-radius: 5px;
            text-decoration: none;
            background: #2563eb;
            color: white;
        }

        .messages {
            padding: 12px;
            margin-bottom: 16px;
            background: #dcfce7;
            color: #166534;
            border-radius: 5px;
        }

        table {
            width: 100%;
            border-collapse: collapse;
            margin-top: 18px;
        }

        th, td {
            padding: 12px;
            border-bottom: 1px solid #ddd;
            text-align: left;
        }

        input {
            padding: 9px;
            width: 100%;
            max-width: 450px;
            box-sizing: border-box;
        }
    </style>
</head>
<body>

    <div class="container">

        {% if messages %}
            {% for message in messages %}
                <div class="messages">
                    {{ message }}
                </div>
            {% endfor %}
        {% endif %}

        {% block content %}
        {% endblock %}

    </div>

</body>
</html>

This base template provides a shared layout, basic styling, and a place to display Django messages.

For a production website, keep CSS in a separate static file rather than embedding all styles in the template.

8. READ: Displaying Student Records

Create students/templates/students/student_list.html:

{% extends 'students/base.html' %}

{% block title %}Student List{% endblock %}

{% block content %}

    <h1>Student Management System</h1>

    <a class="btn" href="{% url 'student_create' %}">
        Add New Student
    </a>

    <table>
        <thead>
            <tr>
                <th>ID</th>
                <th>Name</th>
                <th>Email</th>
                <th>Course</th>
                <th>City</th>
                <th>Actions</th>
            </tr>
        </thead>

        <tbody>
            {% for student in students %}
                <tr>
                    <td>{{ student.id }}</td>
                    <td>{{ student.name }}</td>
                    <td>{{ student.email }}</td>
                    <td>{{ student.course }}</td>
                    <td>{{ student.city }}</td>

                    <td>
                        <a
                            href="{% url 'student_update' student.id %}"
                        >
                            Edit
                        </a>

                        |

                        <a
                            href="{% url 'student_delete' student.id %}"
                        >
                            Delete
                        </a>
                    </td>
                </tr>
            {% empty %}
                <tr>
                    <td colspan="6">No students found.</td>
                </tr>
            {% endfor %}
        </tbody>
    </table>

{% endblock %}

How Reading Works

  1. The browser opens /students/.

  2. Django calls student_list().

  3. The view retrieves records using Student.objects.all().

  4. The records are passed to the template.

  5. The template loops through the records and displays them in a table.

The {% empty %} block displays a message if the database contains no student records.

9. CREATE and UPDATE: Student Form Template

Create students/templates/students/student_form.html:

{% extends 'students/base.html' %}

{% block title %}{{ page_title }}{% endblock %}

{% block content %}

    <h1>{{ page_title }}</h1>

    <form method="post">
        {% csrf_token %}

        {{ form.as_p }}

        <button class="btn" type="submit">
            Save Student
        </button>

        <a class="btn" href="{% url 'student_list' %}">
            Cancel
        </a>
    </form>

{% endblock %}

How the Same Template Supports Both Operations

When the user visits /students/add/, Django creates an empty form.

When the user visits /students/1/edit/, Django loads the student with ID 1 and populates the form with the existing data.

The key difference is:

form = StudentForm()

This creates a form for a new record.

form = StudentForm(instance=student)

This creates a form for updating an existing record.

When the form is valid, form.save() creates or updates the appropriate model instance.

10. DELETE: Confirming Student Deletion

Create students/templates/students/student_confirm_delete.html:

{% extends 'students/base.html' %}

{% block title %}Delete Student{% endblock %}

{% block content %}

    <h1>Delete Student</h1>

    <p>
        Are you sure you want to delete
        <strong>{{ student.name }}</strong>?
    </p>

    <form method="post">
        {% csrf_token %}

        <button class="btn" type="submit">
            Confirm Delete
        </button>

        <a class="btn" href="{% url 'student_list' %}">
            Cancel
        </a>
    </form>

{% endblock %}

Why Use POST for Deletion?

Deleting data is a state-changing operation. A GET request should not delete a record because links can be opened accidentally, crawled, or preloaded.

This implementation follows a safer pattern:

  1. GET displays the confirmation page.

  2. The user confirms the action.

  3. The browser submits a POST request with a CSRF token.

  4. The view deletes the record.

  5. Django redirects the user to the student list.

In real applications, deletion should also be restricted to authorized users.

11. Testing the Complete CRUD Application

Start the development server:

python manage.py runserver

Open:

http://127.0.0.1:8000/students/

Test the following operations.

Test 1: Create

  1. Click Add New Student.

  2. Enter a name, unique email, phone, course, and city.

  3. Submit the form.

  4. Verify that the student appears in the list.

Test 2: Read

  1. Open the student list.

  2. Verify that the saved information is displayed correctly.

  3. Check the empty-list message if there are no records.

Test 3: Update

  1. Click Edit for an existing student.

  2. Change the city or course.

  3. Save the form.

  4. Verify that the updated values appear in the list.

Test 4: Delete

  1. Click Delete for a test student.

  2. Verify that the confirmation page displays the correct student.

  3. Cancel and confirm that the record remains.

  4. Repeat the process and confirm deletion.

  5. Verify that the deleted record no longer appears.

Use test data while learning. Deletion permanently removes the record unless your application implements a recovery mechanism.

12. Common Django CRUD Errors

Error 1: TemplateDoesNotExist

Cause: Django cannot find the requested template.

Solution:

  • Verify the templates/students/ directory.

  • Check the template path used in render().

  • Ensure the app is registered in INSTALLED_APPS.

Error 2: NoReverseMatch

Cause: A template or view refers to a URL name that does not exist or supplies incorrect arguments.

Solution: Verify the URL names and required parameters in students/urls.py.

For example:

<a href="{% url 'student_update' student.id %}">
    Edit
</a>

The URL pattern must accept the student_id argument.

Error 3: IntegrityError

Cause: A database constraint has been violated, such as trying to save a duplicate email address.

Solution: Display form validation errors and handle database exceptions appropriately where necessary.

Error 4: Student Record Not Found

Cause: The requested student ID does not exist.

Solution: Use get_object_or_404() to return an HTTP 404 response.

Error 5: CSRF Verification Failed

Cause: A POST form is missing a valid CSRF token or the request is configured incorrectly.

Solution: Include {% csrf_token %} in the POST form and verify Django's CSRF middleware configuration.

Error 6: Changes Are Not Saved

Cause: The form may be invalid, form.save() may not be called, or the application may be using a different database than expected.

Solution: Check form.errors, verify the save operation, and confirm the database configuration.

13. Frequently Asked Questions (FAQs)

Q1. What does CRUD stand for?

CRUD stands for Create, Read, Update, and Delete. These operations cover the basic lifecycle of database records.

Q2. What is the role of a Django model in CRUD?

A model defines the data structure and provides ORM operations for creating, retrieving, updating, and deleting records.

Q3. Why is ModelForm useful for CRUD applications?

ModelForm generates fields from a model, validates submitted data, and simplifies saving new or updated model instances.

Q4. What is the purpose of get_object_or_404()?

It retrieves an object or returns an HTTP 404 response if the object cannot be found.

Q5. Why should deletion use POST instead of GET?

Deletion changes server-side data. POST is appropriate for state-changing operations, while GET should remain safe and should not delete records.

Q6. How can a success message be displayed after saving a record?

Use Django's messages framework, then display the messages in a template.

Q7. Can the same template be used for creating and updating records?

Yes. The view can pass either an empty form or a form populated with an existing model instance.

Q8. How can duplicate email addresses be prevented?

Use unique=True on the model field and allow Django's form validation to check the constraint. The database remains the final enforcement layer.

14. Important Django CRUD Interview Questions and Answers

Q1. What is CRUD in Django?

CRUD refers to Create, Read, Update, and Delete operations performed on database records.

Q2. Which Django method retrieves all records?

Student.objects.all()

Q3. How do you create a record using ModelForm?

Validate the submitted form with form.is_valid() and call form.save().

Q4. How do you update an existing record?

Retrieve the instance and pass it to the form:

form = StudentForm(request.POST, instance=student)

Then validate and save the form.

Q5. What is get_object_or_404()?

A Django shortcut that retrieves an object or returns a 404 response if the object does not exist.

Q6. Why is CSRF protection required?

It helps protect against forged cross-site requests that attempt to perform actions using a user's authenticated session.

Q7. What is the purpose of URL names?

Named URLs allow templates and views to refer to routes using Django's URL reversing system instead of hardcoding paths.

Q8. How do you handle invalid form submissions?

Check form.is_valid(). If validation fails, render the bound form again so that its errors can be displayed.

Q9. Why should delete operations require authorization?

Without access controls, unauthorized users might delete records they should not be allowed to manage.

Q10. What is the difference between Student.objects.all() and Student.objects.get()?

all() returns a QuerySet containing matching records. get() expects exactly one matching record and raises an exception if none or multiple records match.

15. Practical Assignment

Build a complete Student Management CRUD application with the following requirements:

  1. Create a Student model with name, email, phone, course, city, and creation date.

  2. Create a ModelForm with explicit fields.

  3. Display all students in a table.

  4. Add a form to create new students.

  5. Add an edit page to update existing student information.

  6. Add a confirmation page before deleting a student.

  7. Use named URLs and dynamic student IDs.

  8. Include CSRF tokens in all POST forms.

  9. Display success messages after successful operations.

  10. Test empty lists, invalid emails, duplicate emails, missing IDs, and delete cancellation.

  11. Verify that unauthorized users cannot modify or delete records in a real deployment.

  12. Test all four CRUD operations using sample data.

16. Conclusion

In this module, you learned how to implement Create, Read, Update, and Delete operations using Django models, ModelForms, views, URLs, and templates.

You also learned how to handle validation errors, display success messages, confirm deletions, and respond when a requested record does not exist.

CRUD operations are essential for building practical applications such as student portals, inventory systems, employee management software, and administrative dashboards.

In the next module, we will learn Django Class-Based Views (CBVs) and explore how they can simplify common web application patterns.