Django CRUD Operations: Step-by-Step Guide

November 19, 2025
25 min read
Lalit Mahato
Django CRUD Operations: Step-by-Step Guide

Django CRUD Operations: Step-by-Step Guide

This tutorial assumes you have already created your project (todo_site) and your app (tasks), and registered the app in settings.py. We will now build the CRUD functionality one operation at a time.

Step 0: The Foundation (Model)

Before we can do any CRUD operations, we need a database table to hold our data.

  1. Define the Model in tasks/models.py:

    from django.db import models
    
    class Task(models.Model):
        title = models.CharField(max_length=200)
        completed = models.BooleanField(default=False)
        created_at = models.DateTimeField(auto_now_add=True)
    
        def __str__(self):
            return self.title
    
  2. Create the Database Table: Run this in your terminal:

    python manage.py makemigrations
    python manage.py migrate
    

Operation 1: READ (Displaying the List)

The "R" in CRUD. Let's just get a list of tasks showing up on the screen.

  1. Create the View (tasks/views.py): We fetch all tasks from the database and send them to the template.

    from django.shortcuts import render
    from .models import Task
    
    def task_list(request):
        tasks = Task.objects.all()  # Fetch all data
        return render(request, 'tasks/list.html', {'tasks': tasks})
    
  2. Create the URL (todo_list/urls.py): Map the empty path '' to our view.

    from django.urls import path, include
    from . import views
    
    urlpatterns = [
        path('', include('tasks.urls')),
    ]
    
  3. Create the URL (tasks/urls.py): Map the empty path '' to our view.

    from django.urls import path
    from . import views
    
    urlpatterns = [
        path('', views.task_list, name='list'),
    ]
    
  4. Create the Template (templates/tasks/list.html): A simple HTML loop to display data.

    <h1>My To-Do List</h1>
    <ul>
        {% for task in tasks %}
            <li>{{ task.title }}</li>
        {% empty %}
            <li>No tasks yet!</li>
        {% endfor %}
    </ul>
    

Checkpoint: Run python manage.py runserver and go to http://127.0.0.1:8000/. You should see "My To-Do List" and "No tasks yet!".

Operation 2: CREATE (Adding Data)

The "C" in CRUD. Now we need a form to add new tasks.

  1. Define the Form (tasks/forms.py): Create this file to let Django handle the HTML form generation.

    from django import forms
    from .models import Task
    
    class TaskForm(forms.ModelForm):
        class Meta:
            model = Task
            fields = ['title', 'completed']
    
  2. Update the View (tasks/views.py): Modify task_list to handle data submission (POST requests).

    from django.shortcuts import render, redirect # Import redirect
    from .models import Task
    from .forms import TaskForm # Import the Form
    
    def task_list(request):
        tasks = Task.objects.all()
        form = TaskForm() # Empty form for GET request
    
        if request.method == 'POST':
            form = TaskForm(request.POST) # Fill form with data
            if form.is_valid():
                form.save()  # Save to database
                return redirect('list') # Refresh page
    
        return render(request, 'tasks/list.html', {'tasks': tasks, 'form': form})
    
  3. Update the Template (templates/tasks/list.html): Add the form code above the list.

    <h1>My To-Do List</h1>
    
    <!-- New Form Section -->
    <form method="POST">
        {% csrf_token %}
        {{ form.as_p }}
        <button type="submit">Add Task</button>
    </form>
    
    <hr>
    
    <ul>
        {% for task in tasks %}
            <li>{{ task.title }}</li>
        {% endfor %}
    </ul>
    

Checkpoint: Refresh your browser. You can now type a task title, click "Add Task", and see it appear in the list immediately.

Operation 3: UPDATE (Editing Data)

The "U" in CRUD. We need a dedicated page to edit a specific task.

  1. Create the View (tasks/views.py): We need a new view that finds a specific task by its ID (pk) and fills the form with existing data.

    # Add 'get_object_or_404' to imports
    from django.shortcuts import render, redirect, get_object_or_404
    
    # ... existing task_list view ...
    
    def task_update(request, pk):
        task = get_object_or_404(Task, id=pk) # Find task by ID
        form = TaskForm(instance=task) # Fill form with existing data
    
        if request.method == 'POST':
            form = TaskForm(request.POST, instance=task)
            if form.is_valid():
                form.save()
                return redirect('list')
    
        return render(request, 'tasks/update.html', {'form': form})
    
  2. Create the URL (tasks/urls.py): We need a URL that accepts an ID number (like update/1/).

    urlpatterns = [
        path('', views.task_list, name='list'),
        # New URL pattern
        path('update/<int:pk>/', views.task_update, name='update'),
    ]
    
  3. Create the Template (templates/tasks/update.html): A separate page just for editing.

    <h2>Update Task</h2>
    <form method="POST">
        {% csrf_token %}
        {{ form.as_p }}
        <button type="submit">Update</button>
    </form>
    
  4. Link it in the List (templates/tasks/list.html): Add an "Edit" link next to each item.

    <li>
        {{ task.title }}
        <a href="{% url 'update' task.id %}">Edit</a> <!-- New Link -->
    </li>
    

Checkpoint: Refresh the home page. Click "Edit" next to a task. You will go to a new page, change the title or checkbox, click Update, and return to the home page with the changes saved.

Operation 4: DELETE (Removing Data)

The "D" in CRUD. Ideally, we ask for confirmation before deleting.

  1. Create the View (tasks/views.py): Find the task, wait for a POST (confirmation) request, then delete.

    # ... existing views ...
    
    def task_delete(request, pk):
        task = get_object_or_404(Task, id=pk)
    
        if request.method == 'POST':
            task.delete() # Delete from database
            return redirect('list')
    
        return render(request, 'tasks/delete_confirm.html', {'task': task})
    
  2. Create the URL (tasks/urls.py):

    urlpatterns = [
        path('', views.task_list, name='list'),
        path('update/<int:pk>/', views.task_update, name='update'),
        # New URL pattern
        path('delete/<int:pk>/', views.task_delete, name='delete'),
    ]
    
  3. Create the Template (templates/tasks/delete_confirm.html): A warning page.

    <h2>Are you sure?</h2>
    <p>Do you want to delete "{{ task.title }}"?</p>
    
    <form method="POST">
        {% csrf_token %}
        <button type="submit">Yes, Delete</button>
        <a href="{% url 'list' %}">Cancel</a>
    </form>
    
  4. Link it in the List (templates/tasks/list.html): Add a "Delete" link next to the Edit link.

    <li>
        {{ task.title }}
        <a href="{% url 'update' task.id %}">Edit</a>
        <a href="{% url 'delete' task.id %}">Delete</a> <!-- New Link -->
    </li>
    

 

Tags

Django Python
Lalit Mahato

Lalit Mahato

Software Engineer | Machine Learning Enthusiast

Innovative and results-driven software developer with 5+ years of experience in designing, developing, and deploying high-quality software solutions. Proficient in various programming languages and technologies, with a keen interest in …

Comments (0)

No comments yet. Be the first to comment!

Leave a Comment

Search

Categories

Related Posts

Mastering Custom Pagination in Django Rest Framework
Mastering Custom Pagination in Django Rest Framework

Jan 08, 2026

Read More
Mastering Token Authentication with Django Rest Framework & Swagger
Mastering Token Authentication with Django Rest Framework & Swagger

Jan 08, 2026

Read More
Data Validation in Django REST Framework (DRF)
Data Validation in Django REST Framework (DRF)

Jan 07, 2026

Read More