Create CRUD Application with Django | Easy Tutorial

Faraz

By Faraz - August 05, 2024

Learn how to create and manage CRUD operations in Django with this easy-to-follow guide. Perfect for beginners looking to build web applications.


create-crud-application-with-django-easy-tutorial.webp

Creating a CRUD (Create, Read, Update, Delete) application is a fundamental skill in web development. Django, a powerful web framework, makes this process easy and efficient. In this tutorial, you'll learn how to create a complete CRUD application using Django. This guide is perfect for beginners who want to understand how to manage data in web applications. With clear steps and practical examples, you'll be able to set up your own CRUD app in no time.

Prerequisites

Before we dive in, make sure you have a basic understanding of Django and web development. You'll need the following tools and libraries installed on your machine:

  • Python (version 3.6 or higher)
  • Django (version 3.0 or higher)
  • A text editor or IDE (such as VS Code or PyCharm)
  • Basic knowledge of HTML and CSS

Setting Up the Development Environment

Installing Django

Before starting, ensure you have Python installed. You can install Django using pip:

pip install django

Creating a new Django project

Create a new Django project using the following command:

django-admin startproject crudoperation

Setting up the project structure

Navigate into your project directory:

cd crudoperation

Create a Django App

Create a new app within your project:

python manage.py startapp myapp

Adding the app to the project

In crudoperation/settings.py, add myapp to the INSTALLED_APPS list:

INSTALLED_APPS = [
    'myapp',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

Creating the ToDo App

Create Models

In myapp/models.py, Create models with fields that you want to manage through CRUD operations. For this example, let’s use a Book model:

from django.db import models

class Book(models.Model):
    title = models.CharField(max_length=200)
    author = models.CharField(max_length=200)
    description = models.TextField(default='')

    def __str__(self):
        return self.title

Create Forms

In myapp, create a new file named forms.py for the CRUD model and add the following function:

from django import forms
from .models import Book

class BookForm(forms.ModelForm):
    class Meta:
        model = Book
        fields = ['title', 'author', 'description']
        widgets = {
            'title': forms.TextInput(attrs={
                'class': 'form-input mt-1 block w-full rounded-md border-2 p-2 border-gray-300 shadow-sm',
                'placeholder': 'Enter the book title'
            }),
            'author': forms.TextInput(attrs={
                'class': 'form-input mt-1 block w-full rounded-md border-2 p-2 border-gray-300 shadow-sm',
                'placeholder': 'Enter the author name'
            }),
            'description': forms.Textarea(attrs={
                'class': 'form-textarea resize-none mt-1 block w-full rounded-md border-2 p-2 border-gray-300 shadow-sm',
                'rows': 4,
                'placeholder': 'Enter a brief description of the book'
            }),
        }

Create Views

Next, we’ll create views for creating, updating, and deleting Book items. Open myapp/views.py and add the following:

from django.shortcuts import render, redirect, get_object_or_404
from django.contrib import messages
from django.http import JsonResponse
from .models import Book
from .forms import BookForm

def create_book(request):
    if request.method == 'POST':
        form = BookForm(request.POST)
        if form.is_valid():
            form.save()
            return JsonResponse({'success': True})
        else:
            return JsonResponse({'success': False, 'errors': form.errors})
    return JsonResponse({'success': False})

def edit_book(request, book_id):
    book = get_object_or_404(Book, id=book_id)
    if request.method == 'POST':
        form = BookForm(request.POST, instance=book)
        if form.is_valid():
            form.save()
            messages.success(request, 'Book updated successfully.')
            return redirect('book_list')
    else:
        form = BookForm(instance=book)
    return render(request, 'book_form.html', {'form': form, 'is_edit': True})

def delete_book(request, book_id):
    book = get_object_or_404(Book, id=book_id)
    book.delete()
    return redirect('book_list')

def book_list(request):
    books = Book.objects.all()
    form = BookForm()
    return render(request, 'book_list.html', {'books': books, 'form': form})

Set Up URL Routing

Add a URL pattern for your view. In myapp/urls.py (create this file if it doesn't exist), add:

from django.urls import path
from . import views

urlpatterns = [
    path('books/', views.book_list, name='book_list'),
    path('book/create/', views.create_book, name='create_book'),
    path('book/<int:book_id>/edit/', views.edit_book, name='edit_book'),
    path('book/<int:book_id>/delete/', views.delete_book, name='delete_book'),
]

Include the app's URLs in your project's URL configuration. Open crudoperation/urls.py and include the CRUD app URLs:

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

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

Create Templates

Create a templates directory within the CRUD app and then create base.html, book_list.html and book_form.html inside this directory.

Base Template (base.html):

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Django CRUD with Tailwind CSS</title>
      <script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="bg-gray-100">
    {% block content %}{% endblock %}
<script>
    document.addEventListener('DOMContentLoaded', function () {
    const addBookBtn = document.getElementById('addBookBtn');
    const addBookModal = document.getElementById('addBookModal');
    addBookBtn.addEventListener('click', function () {
        addBookModal.classList.remove('hidden');
    });
    document.querySelectorAll('.cancelButton').forEach(button => {
        button.addEventListener('click', function () {
            addBookModal.classList.add('hidden');
        });
    });
    const bookForm = document.getElementById('bookForm');
    bookForm.addEventListener('submit', function (e) {
        e.preventDefault();
        const formData = new FormData(bookForm);
        fetch(bookForm.action, {
            method: 'POST',
            body: formData,
            headers: {
                'X-CSRFToken': formData.get('csrfmiddlewaretoken')
            }
        })
        .then(response => response.json())
        .then(data => {
            if (data.success) {
                location.reload();
            } else {
                console.error('Error:', data.errors);
            }
        })
        .catch(error => console.error('Error:', error));
    });
});

</script>
</body>
</html>

Book List Template (book_list.html):

{% extends 'base.html' %}

{% block content %}
<div class="container mx-auto mt-10">
    <h1 class="text-4xl font-extrabold text-gray-900 mb-8">List of Python Books</h1>

    <button id="addBookBtn" class="bg-blue-600 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded-lg mb-6">
        Add Book
    </button>

    <div id="addBookModal" class="hidden fixed inset-0 bg-gray-800 bg-opacity-75 flex justify-center items-center">
        <div class="bg-white rounded-lg overflow-hidden shadow-xl w-full max-w-lg">
            <div class="px-6 py-4">
                <h2 class="text-xl font-bold mb-4">Add Book</h2>
                <form id="bookForm" action="{% url 'create_book' %}" method="POST">
                    {% csrf_token %}
                    <div class="form-group">
                        <label for="{{ form.title.id_for_label }}" class="block text-gray-700 font-semibold mb-2">Title</label>
                        {{ form.title }}
                    </div>

                    <div class="form-group">
                        <label for="{{ form.author.id_for_label }}" class="block text-gray-700 font-semibold mb-2">Author</label>
                        {{ form.author }}
                    </div>

                    <div class="form-group">
                        <label for="{{ form.description.id_for_label }}" class="block text-gray-700 font-semibold mb-2">Description</label>
                        {{ form.description }}
                    </div>

                    <div class="flex justify-between mt-6">
                        <button type="button" class="cancelButton bg-gray-500 hover:bg-gray-600 text-white font-bold py-2 px-4 rounded-lg">
                            Cancel
                        </button>
                        <button type="submit" class="bg-blue-600 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded-lg">
                            Save
                        </button>
                    </div>
                </form>
            </div>
        </div>
    </div>

    <table class="min-w-full bg-white shadow-md rounded-lg overflow-hidden">
        <thead class="bg-gray-800 text-white">
            <tr>
                <th class="w-1/3 text-left py-3 px-4 uppercase font-semibold text-sm">Title</th>
                <th class="w-1/3 text-left py-3 px-4 uppercase font-semibold text-sm">Author</th>
                <th class="text-left py-3 px-4 uppercase font-semibold text-sm">Actions</th>
            </tr>
        </thead>
        <tbody class="text-gray-700">
            {% for book in books %}
            <tr>
                <td class="w-1/3 text-left py-3 px-4">{{ book.title }}</td>
                <td class="w-1/3 text-left py-3 px-4">{{ book.author }}</td>
                <td class="flex gap-5 py-3 px-4">
                    <a href="{% url 'edit_book' book.id %}" class="bg-yellow-500 hover:bg-yellow-600 text-white font-bold py-2 px-4 rounded-lg">
                        Edit
                    </a>
                    <a href="{% url 'delete_book' book.id %}" class="bg-red-600 hover:bg-red-700 text-white font-bold py-2 px-4 rounded-lg">
                        Delete
                    </a>
                </td>
            </tr>
            {% endfor %}
        </tbody>
    </table>
</div>
{% endblock %}

Book Form Template (book_form.html):

{% extends 'base.html' %}

{% block content %}
<div class="container mx-auto mt-10">
    <h1 class="text-4xl font-extrabold text-gray-900 mb-8">{{ is_edit|yesno:"Edit Book,Add Book" }}</h1>

    <div class="max-w-lg mx-auto bg-white shadow-lg rounded-lg overflow-hidden">
        <div class="px-6 py-4">
            <form id="bookForm" action="{% if is_edit %}{% url 'edit_book' form.instance.id %}{% else %}{% url 'create_book' %}{% endif %}" method="POST" class="space-y-6">
                {% csrf_token %}
                <div class="form-group">
                    <label for="{{ form.title.id_for_label }}" class="block text-gray-700 font-semibold mb-2">Title</label>
                    {{ form.title }}
                </div>

                <div class="form-group">
                    <label for="{{ form.author.id_for_label }}" class="block text-gray-700 font-semibold mb-2">Author</label>
                    {{ form.author }}
                </div>

                <div class="form-group">
                    <label for="{{ form.description.id_for_label }}" class="block text-gray-700 font-semibold mb-2">Description</label>
                    {{ form.description }}
                </div>

                <div class="flex justify-between mt-6">
                    <a type="button" href="http://127.0.0.1:8000/books/" class="bg-gray-500 hover:bg-gray-600 text-white font-bold py-2 px-4 rounded-lg">
                        Cancel
                    </a>
                    <button type="submit" class="bg-blue-600 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded-lg">
                        Save
                    </button>
                </div>
            </form>
        </div>
    </div>
</div>
{% endblock %}

Run Your Server

Run migrations:

python manage.py makemigrations
python manage.py migrate

Run the development server:

python manage.py runserver

Open your browser and go to http://127.0.0.1:8000/books to see your CRUD app in action.

Full Crud App Project Structure

crudoperation/
│
├── myapp/
│   ├── migrations/
│   │   └── __init__.py
│   ├── templates/
│   │   ├── base.html
│   │   ├── book_form.html
│   │   └── book_list.html
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── forms.py
│   ├── models.py
│   ├── tests.py
│   ├── urls.py
│   └── views.py
│
├── crudoperation/
│   ├── __init__.py
│   ├── asgi.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
│
├── db.sqlite3
└── manage.py

Conclusion

Implementing CRUD operations in Django is straightforward and efficient, thanks to its robust framework and tools. By following this guide, you can easily set up and manage your data, creating a seamless user experience. With Django’s built-in functionalities and our step-by-step instructions, you can quickly build and maintain web applications that handle data effectively. Start applying these concepts to your projects and see how Django can streamline your development process.

That’s a wrap!

I hope you enjoyed this article

Did you like it? Let me know in the comments below 🔥 and you can support me by buying me a coffee.

And don’t forget to sign up to our email newsletter so you can get useful content like this sent right to your inbox!

Thanks!
Faraz 😊

End of the article

Subscribe to my Newsletter

Get the latest posts delivered right to your inbox


Latest Post

Please allow ads on our site🥺