Open In App

How to make an API-based carousel using Django?

Last Updated : 25 Jan, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

In web development, carousels are widely used to showcase a dynamic set of images or content interactively. They prove popular for displaying products, portfolios, or any content that benefits from an engaging visual presentation. This tutorial will guide you through the process of creating an API-based carousel using Django—a robust web framework for Python—and Bootstrap, a front-end framework known for crafting responsive and visually appealing web pages.

What is a Carousel?

A carousel, also referred to as an image slider or image carousel, is a web component that enables the sequential display of multiple images or content items. Users can manually navigate through these items or opt for automatic cycling. Navigation controls such as arrows or dots are typically provided for users to move through the items.

API-based carousel using Django

Below is the step-by-step implementation of an API-based carousel using Django In Python.

To install Django follow these steps.

Starting the Project Folder

To start the project, and app use this command

django-admin startproject carousel
cd carousel
python manage.py startapp carousel_project

Now add this app to the ‘settings.py’

INSTALLED_APPS = [
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
    "carousel",
]

File Structure

file-manage-2

Setting Necessary Files

models.py: Below, code creates a Django model, `CarouselItem`, representing carousel items with title, image URL, and description fields. The `__str__` method defines the string representation as the item’s title.

Python3




from django.db import models
 
class CarouselItem(models.Model):
    id = models.AutoField(primary_key=True)
    title = models.CharField(max_length=255)
    image_url = models.URLField()
    description = models.TextField()
 
    def __str__(self):
        return self.title


serializers.py : Below, code creates a Django REST Framework serializer, `CarouselItemSerializer`, for the `CarouselItem` model with specified fields, enabling easy conversion between JSON and model instances for API interactions.

Python3




from rest_framework import serializers
from .models import CarouselItem
 
class CarouselItemSerializer(serializers.ModelSerializer):
    class Meta:
        model = CarouselItem
        fields = ['id','title', 'image_url', 'description']


views.py : Below, code defines Django views for rendering HTML templates and two Django REST Framework API views (`CarouselItemList` and `CarouselItemDetail`). The views handle list and creation operations as well as retrieve, update, and delete operations for the `CarouselItem` model. The corresponding HTML templates are for carousel display, form submission, and item list/update.

Python3




from rest_framework import status
from rest_framework.response import Response
from rest_framework import generics
from django.shortcuts import render
from .models import CarouselItem
from .serializers import CarouselItemSerializer
 
def carousel_view(request):
    return render(request, 'carousel/index.html')
 
def carousel_Form_view(request):
    return render(request, 'carousel/form.html')
 
def carousel_update_delete(request):
    return render(request, 'carousel/list.html')
 
def carousel_update(request, pk):
    return render(request, 'carousel/update.html')
 
class CarouselItemList(generics.ListCreateAPIView):
    queryset = CarouselItem.objects.all()
    serializer_class = CarouselItemSerializer
    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)
        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
 
class CarouselItemDetail(generics.RetrieveUpdateDestroyAPIView):
    queryset = CarouselItem.objects.all()
    serializer_class = CarouselItemSerializer
    lookup_field = 'pk'  # Use 'id' as the lookup field


carousel/urls.py :Below, code sets up Django URL patterns linking specific URLs to corresponding views for a carousel application. It includes paths for index, form, list, update, and API endpoints for item retrieval and details.

Python3




from django.urls import path
from . import views
 
urlpatterns = [
    path('index/', views.carousel_view, name='index'),
    path('', views.carousel_Form_view, name='form'),
    path('list/', views.carousel_update_delete, name='list'),
    path('update/<int:pk>/', views.carousel_update, name='update'), 
    path('api/', views.CarouselItemList.as_view(), name='carousel-item-list'),
    path('api/<int:pk>/', views.CarouselItemDetail.as_view(), name='carousel-item-detail'),
]


carousel_project/urls.py : The code configures Django URL patterns, linking ‘admin/’ to the admin interface and including URLs from the ‘carousel.urls’ module at the root level (”).

Python3




from django.contrib import admin
from django.urls import path, include
 
urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('carousel.urls')),
 
]


Creating GUI ( templates/carousel)

form.html : Below, HTML code is a Bootstrap-styled form for creating a new carousel item. It uses JavaScript for client-side validation and includes a `postData` function to send a POST request to the API endpoint (‘http://127.0.0.1:8000/api/’) with entered data. The CSRF token is included for security, and there’s a ‘See Carousel’ button to reload the page after form submission.

HTML




<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Create Carousel Item</title>
 
  <!-- Bootstrap CSS -->
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
</head>
<body>
 
  <div class="container mt-5">
    <h2>Create Carousel Item</h2>
 
    <form id="carouselForm">
      <div class="form-group">
        <label for="title">Title:</label>
        <input type="text" class="form-control" id="title" name="title" required>
        <div class="invalid-feedback">Title is required.</div>
      </div>
 
      <div class="form-group">
        <label for="image_url">Image URL:</label>
        <input type="text" class="form-control" id="image_url" name="image_url" required>
        <div class="invalid-feedback">Image URL is required.</div>
      </div>
 
      <div class="form-group">
        <label for="description">Description:</label>
        <textarea class="form-control" id="description" name="description" required></textarea>
        <div class="invalid-feedback">Description is required.</div>
      </div>
 
      <button type="button" class="btn btn-primary" onclick="postData()">Submit</button>
      <a href="{% url 'index' %}" type="button" class="btn btn-success" onclick="postData()">See Carousel</a>
    </form>
  </div>
  <!-- Bootstrap JS and dependencies -->
  <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
  <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
 
  <script>
    function postData() {
        // Validate the form
        if (validateForm()) {
            let title = document.getElementById('title').value;
            let image_url = document.getElementById('image_url').value;
            let description = document.getElementById('description').value;
 
            const data = {
                title: title,
                image_url: image_url,
                description: description
            };
 
            fetch('http://127.0.0.1:8000/api/', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'X-CSRFToken': getCookie('csrftoken') // Ensure to include CSRF token
                },
                body: JSON.stringify(data)
            })
                .then(response => response.json())
                .then(result => {
                    console.log('Success:', result);
                })
                .catch(error => {
                    console.error('Error:', error);
                    // Handle errors as needed
                });
        }
        location.reload();
 
        // Return false to prevent the form from being submitted
        return false;
    }
 
    function validateForm() {
        const title = document.getElementById('title').value;
        const image_url = document.getElementById('image_url').value;
        const description = document.getElementById('description').value;
 
        const invalidFeedbacks = document.querySelectorAll('.invalid-feedback');
        invalidFeedbacks.forEach(element => {
            element.style.display = 'none';
        });
 
        let isValid = true;
 
        if (!title.trim()) {
            document.getElementById('title').nextElementSibling.style.display = 'block';
            isValid = false;
        }
 
        if (!image_url.trim()) {
            document.getElementById('image_url').nextElementSibling.style.display = 'block';
            isValid = false;
        }
 
        if (!description.trim()) {
            document.getElementById('description').nextElementSibling.style.display = 'block';
            isValid = false;
        }
 
        return isValid;
    }
 
    // Function to get CSRF token from cookies
    function getCookie(name) {
        var cookieValue = null;
        if (document.cookie && document.cookie !== '') {
            var cookies = document.cookie.split(';');
            for (var i = 0; i < cookies.length; i++) {
                var cookie = cookies[i].trim();
                if (cookie.substring(0, name.length + 1) === (name + '=')) {
                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                    break;
                }
            }
        }
        return cookieValue;
    }
</script>
</body>
</html>


index.html : Below HTML template utilizes Bootstrap to create a visually appealing image carousel. It includes JavaScript to fetch data from an API (‘http://127.0.0.1:8000/api/’) and dynamically updates the carousel with the retrieved items. The template also features buttons for adding images and updating/deleting slides, with links to specific URLs. Custom styles are applied to the carousel, images, and buttons for a polished appearance.

HTML




<!-- templates/index.html -->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.0.0/dist/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous" />
    <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/popper.js@1.12.9/dist/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.0.0/dist/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
    <script>
      // Assume this script is in a separate JavaScript file linked to your HTML
      document.addEventListener('DOMContentLoaded', function () {
        // Fetch data from the API
        fetch('http://127.0.0.1:8000/api/')
          .then((response) => response.json())
          .then((data) => {
            // Select the carousel container element
            const carouselContainer = document.querySelector('.carousel-inner')
       
            // Iterate over the fetched data and update the carousel
            data.forEach((item) => {
              console.log(item)
              let code = ` <div class="carousel-item">
                <img id="imgSlide" class="d-block w-100" src="${item.image_url}" alt="${item.title}" />
                <div class="carousel-caption d-none d-md-block">
                  <h5>${item.title}</h5>
                  <p>${item.description}</p>
                </div>
              </div>`
              carouselContainer.innerHTML += code;
            })
          })
          .catch((error) => console.error('Error fetching data:', error))
      })
    </script>
 
    <title>carousel</title>
    <style>
       /* Custom Carousel Styles */
  #carouselExampleIndicators {
    margin-top: 20px;
  }
 
  #imgSlide {
    border-radius: 8px;
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
    height: 400px; /* Set a fixed height for the images */
    object-fit: cover; /* Adjust the object-fit property as needed */
  }
 
  .carousel-caption {
    background-color: rgba(0, 0, 0, 0.5);
    border-radius: 5px;
    padding: 10px;
  }
 
  .carousel-caption h5,
  .carousel-caption p {
    color: #fff;
    margin: 0;
  }
 
  /* Centered Heading */
  #devnamdev {
    margin-top: 30px;
  }
 
  /* Buttons Styling */
  .btn-info,
  .btn-success {
    margin-top: 15px;
  }
      /* Custom Carousel Styles */
      #carouselExampleIndicators {
        margin-top: 20px;
      }
     
      #imgSlide {
        border-radius: 8px;
        box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
      }
     
      .carousel-caption {
        background-color: rgba(0, 0, 0, 0.5);
        border-radius: 5px;
        padding: 10px;
      }
     
      .carousel-caption h5,
      .carousel-caption p {
        color: #fff;
        margin: 0;
      }
     
      /* Centered Heading */
      #devnamdev {
        margin-top: 30px;
      }
     
      /* Buttons Styling */
      .btn-info,
      .btn-success {
        margin-top: 15px;
      }
    </style>
     
  </head>
  <body>
    <h1 id="devnamdev" style="text-align: center; color: green; font-family: 'Times New Roman', Times, serif;">GeeksforGeeks</h1>
    <h2 id="devnamdev" style="text-align: center;">carousel</h2>
    <div class="container">
      <div id="carouselExampleIndicators" class="carousel slide" data-ride="carousel">
        <div class="carousel-inner">
          <div class="carousel-item active">
            <img id="imgSlide" class="d-block w-100" src="https://source.unsplash.com/1080x460/?flower" alt="Flower" />
            <div class="carousel-caption d-none d-md-block">
              <h5>Flower</h5>
            </div>
          </div>
        </div>
        <a class="carousel-control-prev" href="#carouselExampleIndicators" role="button" data-slide="prev">
          <span class="carousel-control-prev-icon" aria-hidden="true"></span>
          <span class="sr-only">Previous</span>
        </a>
        <a class="carousel-control-next" href="#carouselExampleIndicators" role="button" data-slide="next">
          <span class="carousel-control-next-icon" aria-hidden="true"></span>
          <span class="sr-only">Next</span>
        </a>
      </div>
    </div>
    <div class="mt-3 container">
      <a href="{% url 'form' %}" class="btn btn-info">Add Image</a>
      <a href="/list" class="btn btn-success">Update/Delete Slide</a>
    </div>
  </body>
</html>


list.html : Below, HTML template displays a table of carousel items with titles. It fetches data from the ‘/api’ endpoint using JavaScript and dynamically populates the table. Each row includes buttons for updating and deleting the respective item. The ‘Back’ button links to the ‘index’ URL. The JavaScript functions handle item deletion and navigation to the update form.

HTML




<!-- carousel/templates/carousel/index.html -->
 
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Carousel Items</title>
</head>
<body>
    <div class="container mt-5">
        <h2>Carousel Items</h2>
        <table class="table mt-3" id="carouselTable">
            <thead>
                <tr>
                    <th>Title</th>
                    <!-- Add other fields as needed -->
                    <th>Actions</th>
                </tr>
            </thead>
            <tbody id="carouselBody">
                <!-- Data will be dynamically inserted here -->
            </tbody>
        </table>
        <hr>
        <a href="{% url 'index' %}" type="button" class="btn btn-warning" >Back</a>
    </div>
     
 
   
 
    <script>
        // Fetch and display data on page load
        document.addEventListener('DOMContentLoaded', function () {
            fetchData();
        });
 
        // Function to fetch and display data
        function fetchData() {
            fetch('/api')
                .then(response => response.json())
                .then(data => {
                    const tableBody = document.getElementById('carouselBody');
                    tableBody.innerHTML = '';
 
                    data.forEach(item => {
                        const row = document.createElement('tr');
                        row.innerHTML = `
                            <td>${item.title}</td>
                            <td>
                                <button class="btn btn-primary btn-sm" onclick="updateItem(${item.id})">Update</button>
                                <button class="btn btn-danger btn-sm" onclick="deleteItem(${item.id})">Delete</button>
                            </td>
                        `;
                        tableBody.appendChild(row);
                    });
                })
                .catch(error => console.error('Error fetching data:', error));
        }
 
        // Function to delete an item
        function deleteItem(itemId) {
            if (confirm("Are you sure you want to delete this item?")) {
                fetch(`/api/${itemId}/`, {
                    method: 'DELETE',
                    headers: {
                        'Content-Type': 'application/json',
                        'X-CSRFToken': '{{ csrf_token }}',
                    },
                })
                .then(response => {
                    if (response.ok) {
                        fetchData();  // Refresh the data after deletion
                    } else {
                        alert("Failed to delete item.");
                    }
                })
                .catch(error => console.error('Error deleting item:', error));
            }
        }
 
        // Function to navigate to the update form
        function updateItem(itemId) {
            window.location.href = `/update/${itemId}/`;
        }
    </script>
 
</body>
</html>


update.html : Below, HTML template serves as an update form for a carousel item. It uses Bootstrap for styling and JavaScript to fetch the item data from the API, pre-fill the form fields, and handle form submission with a PUT request to update the item. Upon successful update, it displays an alert and redirects to the ‘list’ page.

HTML




<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Update Carousel Item</title>
  </head>
  <body>
    <div class="container mt-5">
      <h2>Update Carousel Item</h2>
      <form id="updateForm">
        <div class="form-group">
          <label for="title">Title</label>
          <input type="text" class="form-control" id="title" name="title" required />
          <label for="link">URL</label>
          <input type="text" class="form-control" id="image_url" name="image_url" required />
          <label for="description">Description</label>
          <input type="text" class="form-control" id="description" name="description" required />
        </div>
        <!-- Add other form fields as needed -->
 
        <button type="submit" class="btn btn-primary">Update</button>
      </form>
    </div>
 
    <script>
      document.addEventListener('DOMContentLoaded', function () {
        // Fetch item data and fill the form fields
        const url = window.location.pathname.split('/')
        let itemId = url[2]
        fetch(`/api/${itemId}/`)
          .then((response) => response.json())
          .then((data) => {
            document.getElementById('title').value = data.title
            document.getElementById('image_url').value = data.image_url
            document.getElementById('description').value = data.description
            // Set values for other form fields as needed
          })
          .catch((error) => console.error('Error fetching item data:', error))
       
        // Submit form with API call
        document.getElementById('updateForm').addEventListener('submit', function (event) {
          event.preventDefault()
       
          // Get form data
          const formData = new FormData(this)
       
          // Make API call to update item
          fetch(`/api/${itemId}/`, {
            method: 'PUT',
            headers: {
              'X-CSRFToken': '{{ csrf_token }}'
            },
            body: formData
          })
            .then((response) => response.json())
            .then((data) => {
              alert('Item updated successfully!')
              window.location.href = '/list'
            })
            .catch((error) => console.error('Error updating item:', error))
        })
      })
    </script>
  </body>
</html>


admin.py : In admin we register the model.

Python3




from django.contrib import admin
from .models import CarouselItem
 
class CarouselItemAdmin(admin.ModelAdmin):
    list_display = ('id','title', 'image_url', 'description')
    search_fields = ('title', 'description')
 
admin.site.register(CarouselItem, CarouselItemAdmin)


Deployement of the Project

Run these commands to apply the migrations:

python3 manage.py makemigrations
python3 manage.py migrate

Run the server with the help of following command:

python3 manage.py runserver

Output

second

Video Demonstration



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads