Building a Dynamic Filtering System with Django and AJAX

Getting Started with Django

To create a list page that allows filtering and pagination, several components need to work together seamlessly. Fortunately, Django’s object-relational mapper (ORM) and built-in pagination class make it easy for developers to become productive without needing to know the intricacies of databases and SQL.

The Dataset: Top 50 Songs on Spotify by Country

For this example, we’ll be using a dataset of the top 50 songs on Spotify by country. You can download the dataset from this link. The code used in this guide is available on GitHub, with a link provided at the end of this article.

Setting Up the Project

To begin, start a new Django project and create a sample app. Update the settings.py file to include the necessary configurations. The directory structure for this guide is as follows:

project/
    project/
        __init__.py
        asgi.py
        settings.py
        urls.py
        wsgi.py
    app/
        __init__.py
        admin.py
        apps.py
        migrations/
            __init__.py
        models.py
        tests.py
        urls.py
        views.py
    manage.py

Preparing the Data

Before diving into the code, we need to push the dataset to the database. Create a basic model named TopSongPopularity to store the necessary information from the dataset.

from django.db import models

class TopSongPopularity(models.Model):
    country = models.CharField(max_length=50)
    song_name = models.CharField(max_length=100)
    artist = models.CharField(max_length=50)
    #... other fields...

Then, migrate the model to the database using the following command:

python manage.py migrate

Next, use the shell to execute a script that pushes the CSV data to the database.

Creating Views

Now, let’s write the views. ListTopSongs is a class-based view that inherits the View class. In the get() method, it takes up the query parameters and filters the QuerySet accordingly. After filtering, it calls getpaginatedcontext() to get the paginated data in serialized format.

from django.shortcuts import render
from django.core.paginator import Paginator
from.models import TopSongPopularity
from.serializers import TopSongPopularitySerializer

class ListTopSongs(View):
    def get(self, request):
        query_params = request.GET.get('country')
        queryset = TopSongPopularity.objects.all()
        if query_params:
            queryset = queryset.filter(country=query_params)
        paginator = Paginator(queryset, 10)
        page_number = request.GET.get('page')
        page_obj = paginator.get_page(page_number)
        serializer = TopSongPopularitySerializer(page_obj, many=True)
        return JsonResponse(serializer.data, safe=False)

getCountries() is a function-based view that returns the JSON output for all the unique countries in the database.

from django.http import JsonResponse
from.models import TopSongPopularity

def getCountries(request):
    countries = TopSongPopularity.objects.values_list('country', flat=True).distinct()
    return JsonResponse(list(countries), safe=False)

Now, let’s route the views using Django’s URL dispatcher.

from django.urls import path
from.views import ListTopSongs, getCountries

urlpatterns = [
    path('top-songs/', ListTopSongs.as_view()),
    path('countries/', getCountries),
]

Creating Templates

With the backend code complete, let’s move on to the frontend. We’ll use a base template (base.html) that includes Bootstrap and jQuery libraries. Then, create an index.html file that displays the table with filters. This template file inherits the base.html and creates the table with a header and empty body.

<!-- base.html -->
<html>
    <head>
        <title>Dynamic Filtering System</title>
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
    </head>
    <body>
        {% block content %}{% endblock %}
        <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"></script>
        <script src="undefined.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script>
    </body>
</html>

<!-- index.html -->
<{% extends 'base.html' %}>
<{% block content %}>
    <div class="container">
        <h1>Top Songs by Country</h1>
        <form>
            <label>Filter by Country:</label>
            <select id="country">
                <option value="">Select a country</option>
                {% for country in countries %}
                    <option value="{{ country }}">{{ country }}</option>
                {% endfor %}
            </select>
            <button type="submit">Filter</button>
        </form>
        <table id="song-table">
            <thead>
                <tr>
                    <th>Country</th>
                    <th>Song Name</th>
                    <th>Artist</th>
                </tr>
            </thead>
            <tbody id="song-table-body"></tbody>
        </table>
        <ul id="pagination"></ul>
    </div>
<{% endblock %}>

Client-Side Scripting with AJAX

The final step is to connect the frontend with the backend using AJAX.

$(document).ready(function() {
    $('#country').change(function() {
        var country = $(this).val();
        $.ajax({
            type: 'GET',
            url: '/top-songs/',
            data: {'country': country},
            success: function(data) {
                $('#song-table-body').empty();
                $.each(data, function(index, song) {
                    $('#song-table-body').append('<tr><td>' + song.country + '</td><td>' + song.song_name + '</td><td>' + song.artist + '</td></tr>');
                });
            }
        });
    });

    $.ajax({
        type: 'GET',
        url: '/countries/',
        success: function(data) {
            $.each(data, function(index, country) {
                $('#country').append('<option value="' + country + '">' + country + '</option>');
            });
        }
    });
});

Mastering Dynamic Filtering and Pagination

By following this guide, you’ve learned how to use AJAX to communicate with the backend asynchronously. You’ve also gained a better understanding of how to handle filtering tabular data. If you prefer, you can use REST frameworks like Django REST framework to simplify the process.

Troubleshooting and Next Steps

If you encounter any issues during the guide, you can always check the GitHub repository to view the whole project.

  • Make sure to update your settings.py file correctly.
  • Check your database connections and migrations.
  • Verify your template files and static assets.

Don’t forget to set up error tracking to monitor your application’s performance.

Leave a Reply