I’ve worked with various web frameworks, and Django has always stood out for its robustness and simplicity. One of the most common tasks in web development is implementing CRUD (Create, Read, Update, Delete) operations. Pairing Django with a sleek Bootstrap template makes your app not only functional but also visually appealing.
In this article, I’ll walk you through building a complete Django CRUD application using Bootstrap 5 for styling. Along the way, I’ll share practical tips and best practices to help you create modern, responsive web applications tailored for real-world use cases.
Let’s get right in!
What is Django CRUD, and Why Use Bootstrap?
CRUD represents the four basic operations you perform on data in any app: Create, Read, Update, and Delete. Django’s built-in ORM and views make these operations straightforward. However, the default Django admin interface, while powerful, isn’t always suitable for end users.
This is where Bootstrap comes in. Bootstrap provides a responsive, mobile-first CSS framework that helps you quickly design clean, professional-looking interfaces without writing tons of custom CSS.
Combining Django CRUD with Bootstrap templates means you get the best of both worlds: powerful backend functionality and modern frontend design.
Check out Python Django Round to Two Decimal Places
Project Setup: Get Started with Django and Bootstrap
Before we build the CRUD app, let’s set up the project environment.
Step 1: Create a Virtual Environment and Install Django
python -m venv env
source env/bin/activate # On Windows use: env\Scripts\activate
pip install djangoStep 2: Create a Django Project and App
django-admin startproject django_bootstrap_crud
cd django_bootstrap_crud
python manage.py startapp employeesStep 3: Add the App to Installed Apps
In django_bootstrap_crud/settings.py, add 'employees' to the INSTALLED_APPS list:
INSTALLED_APPS = [
# ...
'employees',
]Read Python Django Concatenate String
Build a Simple Employee Management CRUD App
For this tutorial, we’ll build an Employee Management system — a common use case in the USA for HR or small business apps.
Step 4: Define the Employee Model
In employees/models.py:
from django.db import models
class Employee(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
email = models.EmailField(unique=True)
position = models.CharField(max_length=100)
salary = models.DecimalField(max_digits=10, decimal_places=2)
hire_date = models.DateField()
def __str__(self):
return f"{self.first_name} {self.last_name}"Run migrations:
python manage.py makemigrations
python manage.py migrateStep 5: Create Forms for Employee
In employees/forms.py:
from django import forms
from .models import Employee
class EmployeeForm(forms.ModelForm):
class Meta:
model = Employee
fields = '__all__'Step 6: Set Up URLs
Create employees/urls.py:
from django.urls import path
from . import views
urlpatterns = [
path('', views.employee_list, name='employee_list'),
path('employee/add/', views.employee_create, name='employee_add'),
path('employee/<int:id>/edit/', views.employee_update, name='employee_edit'),
path('employee/<int:id>/delete/', views.employee_delete, name='employee_delete'),
]Include these URLs in the main project urls.py (django_bootstrap_crud/urls.py):
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('employees.urls')),
]Step 7: Build Views for CRUD Operations
In employees/views.py:
from django.shortcuts import render, get_object_or_404, redirect
from .models import Employee
from .forms import EmployeeForm
def employee_list(request):
employees = Employee.objects.all()
return render(request, 'employees/employee_list.html', {'employees': employees})
def employee_create(request):
if request.method == 'POST':
form = EmployeeForm(request.POST)
if form.is_valid():
form.save()
return redirect('employee_list')
else:
form = EmployeeForm()
return render(request, 'employees/employee_form.html', {'form': form, 'title': 'Add Employee'})
def employee_update(request, id):
employee = get_object_or_404(Employee, id=id)
if request.method == 'POST':
form = EmployeeForm(request.POST, instance=employee)
if form.is_valid():
form.save()
return redirect('employee_list')
else:
form = EmployeeForm(instance=employee)
return render(request, 'employees/employee_form.html', {'form': form, 'title': 'Edit Employee'})
def employee_delete(request, id):
employee = get_object_or_404(Employee, id=id)
if request.method == 'POST':
employee.delete()
return redirect('employee_list')
return render(request, 'employees/employee_confirm_delete.html', {'employee': employee})Read How to Encrypt and Decrypt Passwords in Django
Step 8: Create Bootstrap Templates
Create a folder employees/templates/employees/ and add the following files.
Base Template: base.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Django Employee Management</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-primary mb-4">
<div class="container">
<a class="navbar-brand" href="{% url 'employee_list' %}">Employee Management</a>
</div>
</nav>
<div class="container">
{% block content %}
{% endblock %}
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>Employee List Template: employee_list.html
{% extends 'employees/base.html' %}
{% block content %}
<div class="d-flex justify-content-between align-items-center mb-3">
<h2>Employee List</h2>
<a href="{% url 'employee_add' %}" class="btn btn-success">Add Employee</a>
</div>
<table class="table table-striped table-bordered">
<thead class="table-primary">
<tr>
<th>Name</th>
<th>Email</th>
<th>Position</th>
<th>Salary ($)</th>
<th>Hire Date</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{% for employee in employees %}
<tr>
<td>{{ employee.first_name }} {{ employee.last_name }}</td>
<td>{{ employee.email }}</td>
<td>{{ employee.position }}</td>
<td>{{ employee.salary }}</td>
<td>{{ employee.hire_date }}</td>
<td>
<a href="{% url 'employee_edit' employee.id %}" class="btn btn-sm btn-warning">Edit</a>
<a href="{% url 'employee_delete' employee.id %}" class="btn btn-sm btn-danger">Delete</a>
</td>
</tr>
{% empty %}
<tr>
<td colspan="6" class="text-center">No employees found.</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}Employee Form Template: employee_form.html
{% extends 'employees/base.html' %}
{% block content %}
<h2>{{ title }}</h2>
<form method="POST" novalidate>
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-primary">Save</button>
<a href="{% url 'employee_list' %}" class="btn btn-secondary">Cancel</a>
</form>
{% endblock %}Employee Delete Confirmation Template: employee_confirm_delete.html
{% extends 'employees/base.html' %}
{% block content %}
<h2>Delete Employee</h2>
<p>Are you sure you want to delete <strong>{{ employee.first_name }} {{ employee.last_name }}</strong>?</p>
<form method="POST">
{% csrf_token %}
<button type="submit" class="btn btn-danger">Yes, Delete</button>
<a href="{% url 'employee_list' %}" class="btn btn-secondary">Cancel</a>
</form>
{% endblock %}Step 9: Run Your Django App
Start the development server:
python manage.py runserverYou can refer to the screenshot below to see the output:


Open your browser and navigate to http://127.0.0.1:8000/. You should see a clean, responsive employee list with options to add, edit, and delete employees.
Check out Python Django Form Validation
Alternative Method: Use Django Class-Based Views (CBVs)
If you prefer a more concise and reusable approach, Django’s generic class-based views can simplify CRUD operations.
Here’s how you can replace the function-based views with CBVs:
In employees/views.py:
from django.urls import reverse_lazy
from django.views.generic import ListView, CreateView, UpdateView, DeleteView
from .models import Employee
class EmployeeListView(ListView):
model = Employee
template_name = 'employees/employee_list.html'
context_object_name = 'employees'
class EmployeeCreateView(CreateView):
model = Employee
form_class = EmployeeForm
template_name = 'employees/employee_form.html'
success_url = reverse_lazy('employee_list')
class EmployeeUpdateView(UpdateView):
model = Employee
form_class = EmployeeForm
template_name = 'employees/employee_form.html'
success_url = reverse_lazy('employee_list')
class EmployeeDeleteView(DeleteView):
model = Employee
template_name = 'employees/employee_confirm_delete.html'
success_url = reverse_lazy('employee_list')Update employees/urls.py:
from django.urls import path
from .views import EmployeeListView, EmployeeCreateView, EmployeeUpdateView, EmployeeDeleteView
urlpatterns = [
path('', EmployeeListView.as_view(), name='employee_list'),
path('employee/add/', EmployeeCreateView.as_view(), name='employee_add'),
path('employee/<int:pk>/edit/', EmployeeUpdateView.as_view(), name='employee_edit'),
path('employee/<int:pk>/delete/', EmployeeDeleteView.as_view(), name='employee_delete'),
]This method reduces boilerplate and leverages Django’s powerful generic views.
Read Login system in Python Django
Conclusion
Building a CRUD app with Django and Bootstrap is a practical way to create modern, responsive web applications quickly. From my experience, using Bootstrap templates not only speeds up frontend development but also ensures your app looks professional across all devices.
Whether you choose function-based views or class-based views depends on your project’s complexity and your coding style. Both methods work well and can be adapted for larger applications.
Feel free to expand this example by adding user authentication, search functionality, or pagination to make it production-ready.
Other articles you may like:

I am Bijay Kumar, a Microsoft MVP in SharePoint. Apart from SharePoint, I started working on Python, Machine learning, and artificial intelligence for the last 5 years. During this time I got expertise in various Python libraries also like Tkinter, Pandas, NumPy, Turtle, Django, Matplotlib, Tensorflow, Scipy, Scikit-Learn, etc… for various clients in the United States, Canada, the United Kingdom, Australia, New Zealand, etc. Check out my profile.