API-based carousel using Django
Below is the step-by-step implementation of an API-based carousel using Django In Python.
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
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;" >w3wiki</ 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 > < link rel = "stylesheet" href = "https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" > </ 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 > < link rel = "stylesheet" href = "https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" /> </ 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
Video Demonstration
How to make an API-based carousel using Django?
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.