Training Menu

Building a Professional Django CRUD Application with Class-Based Views and a Single URL

Fotsing Tchoupe
Fotsing Tchoupe
Oct. 23, 2024 · 52.72 min read
39
Django
Building a Professional Django CRUD Application with Class-Based Views and a Single URL

Introduction:

Creating a robust CRUD (Create, Read, Update, Delete) application is essential in most web development projects, and Django makes it easy to do so using Class-Based Views (CBVs). In this tutorial, we’ll walk through how to develop a professional Python CRUD application in Django, using CBVs and a single URL pattern to handle all actions. Additionally, we’ll integrate Bootstrap and Django’s messaging framework for enhanced user experience and feedback.


Outline for the Blog:


1. Setting Up the Django Project

Install Django:

First, install Django and create a new project.

```

pip install django
django-admin startproject crud_project
cd crud_project
django-admin startapp products


```


2. Configure the settings.py

Configure Installed Apps:

In settings.py, add 'products' to the INSTALLED_APPS.

```

INSTALLED_APPS = [
    # Other apps
    'products',
]

```

In settings.py, configure the message tags to map Django message levels to Bootstrap classes:

```

from django.contrib import messages

MESSAGE_TAGS = {
    messages.DEBUG: 'alert-secondary',
    messages.INFO: 'alert-info',
    messages.SUCCESS: 'alert-success',
    messages.WARNING: 'alert-warning',
    messages.ERROR: 'alert-danger',
}

```


3. Define the Product Model

Define a Product model in products/models.py:

```

 

from django.db import models

class Product(models.Model):
    name = models.CharField(max_length=100)
    description = models.TextField()
    price = models.DecimalField(max_digits=10, decimal_places=2)
    stock = models.IntegerField()

    def __str__(self):
        return self.name
```


4. Setup the Database:

After defining the model, run migrations to set up the database.

```

python manage.py makemigrations
python manage.py migrate

```


5. Create the Class-Based View (CBV)

In products/views.py, create a ProductView class that will handle all CRUD operations using a single view. Use Django’s messaging system to provide feedback.

```

from django.shortcuts import render
from django.views import View
from .models import Product
from django.contrib import messages
from django.db import transaction

class ProductView(View):
    template_name = 'products/index.html'

    def get(self, request):
        products = Product.objects.all()
        context = {
            'products': products,
        }
        return render(request, self.template_name, context)

    def post(self, request):
        action = request.POST.get('action')
        id = request.POST.get('id')
        name = request.POST.get('name')
        description = request.POST.get('description')
        price = request.POST.get('price')
        stock = request.POST.get('stock')

        try:
            with transaction.atomic():
                if action == 'create':
                    Product.objects.create(name=name, description=description, price=price, stock=stock)
                    messages.success(request, 'Product created successfully.')

                elif action == 'update':
                    product = Product.objects.get(id=id)
                    product.name = name
                    product.description = description
                    product.price = price
                    product.stock = stock
                    product.save()
                    messages.success(request, 'Product updated successfully.')

                elif action == 'delete':
                    product = Product.objects.get(id=id)
                    product.delete()
                    messages.success(request, 'Product deleted successfully.')

                else:
                    messages.error(request, 'Invalid action.')

        except Exception as e:
            messages.error(request, f'Error: {e}')

        return redirect('product-list')

```


6. Create the URL Configuration

Instead of using multiple URLs for different actions, we can manage everything through a single URL.

In products/urls.py:

```

from django.urls import path
from .views import ProductView

urlpatterns = [
    path('products/', ProductView.as_view(), name='product-list'),
]

```

In crud_project/urls.py, include the products app URL:

```

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

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

```


7. Create the HTML Template (Bootstrap Integrated)

Create a template products/index.html and use Bootstrap for styling. Display products and provide forms for creating, updating, and deleting products.

```

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Product Management</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>

<div class="container">
    <div class="row mb-8">
        <div class="col-md-12">
            <!-- page header -->
            <div class="d-md-flex justify-content-between align-items-center">
                <div>
                    <h2>Product</h2>
                    <!-- breadcrumb -->
                    <nav aria-label="breadcrumb">
                        <ol class="breadcrumb mb-0">
                            <li class="breadcrumb-item"><a href="#" class="text-inherit">Dashboard</a></li>
                            <li class="breadcrumb-item active" aria-current="page">Product</li>
                        </ol>
                    </nav>
                </div>
                <!-- button -->
                <button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#createProductModal">
                    Add Product
                </button>
                
                <!-- Create Product Modal -->
                <div class="modal fade" id="createProductModal" tabindex="-1" role="dialog" aria-labelledby="createProductModalLabel" aria-hidden="true">
                    <div class="modal-dialog mt-6" role="document">
                        <div class="modal-content">
                            <div class="modal-header">
                                <h5 class="modal-title">Create a Product</h5>
                                <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
                            </div>
                            <div class="modal-body">
                                <form method="post" action="#" enctype="multipart/form-data">
                                    <input type="hidden" name="action" value="create">
                                    
                                    <div class="row">
                                        <div class="mb-3 col-md-12">
                                            <label for="name" class="form-label">Product Name</label>
                                            <input type="text" required id="name" class="form-control" name="name">
                                        </div>
                                    </div>

                                    <div class="row">
                                        <div class="mb-3 col-md-6">
                                            <label for="price" class="form-label">Price</label>
                                            <input type="number" required id="price" class="form-control" name="price">
                                        </div>
                                        <div class="mb-3 col-md-6">
                                            <label for="stock" class="form-label">Stock</label>
                                            <input type="number" required id="stock" class="form-control" name="stock">
                                        </div>
                                    </div>

                                    <div class="row">
                                        <div class="mb-3 col-md-6">
                                            <input type="checkbox" class="form-check-input" id="is_active" name="is_active" checked>
                                            <label class="form-check-label" for="is_active">Is Active</label>
                                        </div>
                                    </div>

                                    <div class="mb-3 col-md-3">
                                        <button type="submit" class="btn btn-primary">Create</button>
                                    </div>
                                </form>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <!-- product list -->
    <div class="row">
        <div class="col-xl-12 col-12 mb-5">
            <!-- card -->
            <div class="card h-100 card-lg">
                <!-- card body -->
                <div class="card-body p-0">
                    <!-- table -->
                    <div class="table-responsive">
                        <table class="table table-hover" style="width:100%">
                            <thead class="bg-light">
                                <tr>
                                    <th>Name</th>
                                    <th>Price</th>
                                    <th>Stock</th>
                                    <th>Active</th>
                                    <th>Action</th>
                                </tr>
                            </thead>
                            <tbody>
                                {% for product in products %}
                                    <tr>
                                        <td>{{ product.name }}</td>
                                        <td>{{ product.price }}</td>
                                        <td>{{ product.stock }}</td>
                                        <td>
                                            {% if product.is_active %}
                                                <span class="badge bg-success">Yes</span>
                                            {% else %}
                                                <span class="badge bg-danger">No</span>
                                            {% endif %}
                                        </td>
                                        <td>
                                            <div class="dropdown">
                                                <a href="#" class="text-reset" data-bs-toggle="dropdown" aria-expanded="false">
                                                    <i class="feather-icon icon-more-vertical fs-5"></i>
                                                </a>
                                                <ul class="dropdown-menu">
                                                    <li>
                                                        <a class="dropdown-item" data-bs-toggle="modal" data-bs-target="#editProductModal{{ product.id }}">
                                                            <i class="bi bi-pencil-square me-3"></i>Edit
                                                        </a>
                                                    </li>
                                                    <li>
                                                        <a class="dropdown-item" data-bs-toggle="modal" data-bs-target="#deleteProductModal{{ product.id }}">
                                                            <i class="bi bi-trash me-3"></i>Delete
                                                        </a>
                                                    </li>
                                                </ul>
                                            </div>
                                        </td>
                                    </tr>

                                    <!-- Edit Product Modal -->
                                    <div class="modal fade" id="editProductModal{{ product.id }}" tabindex="-1" role="dialog" aria-labelledby="editProductModalLabel" aria-hidden="true">
                                        <div class="modal-dialog mt-6" role="document">
                                            <div class="modal-content">
                                                <div class="modal-header">
                                                    <h5 class="modal-title">Edit Product</h5>
                                                    <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
                                                </div>
                                                <div class="modal-body">
                                                    <form method="post" action="{% url 'product-list' %}'" enctype="multipart/form-data">
                                                        <input type="hidden" name="id" value="{{ product.id }}">
                                                        <input type="hidden" name="action" value="update">
                                                        <div class="row">
                                                            <div class="mb-3 col-md-12">
                                                                <label for="name" class="form-label">Product Name</label>
                                                                <input type="text" required id="name" class="form-control" name="name" value="{{ product.name }}">
                                                            </div>
                                                        </div>
                                                        <div class="row">
                                                            <div class="mb-3 col-md-6">
                                                                <label for="price" class="form-label">Price</label>
                                                                <input type="number" required id="price" class="form-control" name="price" value="{{ product.price }}">
                                                            </div>
                                                            <div class="mb-3 col-md-6">
                                                                <label for="stock" class="form-label">Stock</label>
                                                                <input type="number" required id="stock" class="form-control" name="stock" value="{{ product.stock }}">
                                                            </div>
                                                        </div>
                                                        <div class="mb-3 col-md-6">
                                                            <input type="checkbox" class="form-check-input" id="is_active" name="is_active" {% if product.is_active %}checked{% endif %}>
                                                            <label class="form-check-label" for="is_active">Is Active</label>
                                                        </div>
                                                        <div class="mb-3 col-md-3">
                                                            <button type="submit" class="btn btn-primary">Update</button>
                                                        </div>
                                                    </form>
                                                </div>
                                            </div>
                                        </div>
                                    </div>

                                    <!-- Delete Product Modal -->
                                    <div class="modal fade" id="deleteProductModal{{ product.id }}" tabindex="-1" aria-labelledby="deleteProductModalLabel" aria-hidden="true">
                                        <div class="modal-dialog">
                                            <div class="modal-content">
                                                <div class="modal-header">
                                                    <h5 class="modal-title">Product: {{ product.name }}</h5>
                                                    <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
                                                </div>
                                                <div class="modal-body">
                                                    <p>Are you sure you want to delete this product?</p>
                                                </div>
                                                <div class="modal-footer">
                                                    <form action="{% url 'product-list' %}" method="POST">
                                                        <input type="hidden" name="id" value="{{ product.id }}">
                                                        <input type="hidden" name="action" value="delete">
                                                        <button type="submit" class="btn btn-primary">Delete</button>
                                                    </form>
                                                    <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
                                                </div>
                                            </div>
                                        </div>
                                    </div>
                                {% endfor %}
                            </tbody>
                        </table>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

```


8. Testing and Running the Application

 

Run the server and visit /products/ to manage your products.

```

python manage.py runserver

```


Conclusion:

In this guide, we’ve shown how to build a professional Django CRUD application using Class-Based Views and a single URL to handle all actions. We integrated Bootstrap for styling and Django's messaging framework to provide user feedback. This method helps streamline the process, making it easier to maintain and extend the application in the future.

39

Applaudissez pour montrer votre soutien

Fotsing Tchoupe

Fotsing Tchoupe

4 Followers · Writer for Django

My objective is to apply my expertise in technology and problem-solving to create innovative solutions, develop optimized systems, and continuously … Read more