How to Make Dynamic Dropdown List with Ajax in Python Django?

In Django projects, we may have data like categories and subcategories. We can present this data in forms with drop-down lists in the user interface. In this post, I will explain how to dynamically get subcategories from server with ajax request without refreshing the page, depending on the selected category.

There is a database structure with a parent category named subject where we will keep the software languages, and a database structure with subcategories named topic to hold the contents of the languages ​​related to this category.


As you can see in our HTML template below, while rendering the page, we render it with our subjects data. We will update our Topic drop-down list with the ajax request according to the subject selected from the drop-down list.

{% csrf_token %}
<div class="col-md-6">
  <div class="form-group">
    <label for="inputStatus">Subject</label>
    <select id="question-subject" class="form-control-sm custom-select">
      <option selected disabled>Choose a subject</option>
      {% for subject in subjects%}
      <option value="{{subject.id}}">{{subject.title}}</option>
      {% endfor %}
    </select>
  </div>
</div>
<div class="col-md-6">
  <div class="form-group">
    <label for="inputStatus">Topic</label>
    <select id="question-topic" class="form-control-sm custom-select" name="topic">
      <option selected disabled>Choose a topic</option>
    </select>
  </div>
</div>

To make an Ajax request, we first need to include the jquery library to our page.

We define id = "question-subject" to our subject dropdown list. We select this list with the jquery selector and detect a change in this list with the change event. We assign the ID of the selected subject to a variable. Then, we make an ajax request to the address named get_topics_ajax and renew our topic list with the data returned from the request.

{% block javascript %}
<script src="https://code.jquery.com/jquery-3.5.1.js" integrity="sha256-QWo7LDvxbWT2tbbQ97B53yJnYU3WhH/C8ycbRAkjPDc=" crossorigin="anonymous"></script>
<script>
    $("#question-subject").change(function () {
        const subjectId = $(this).val();  // get the selected subject ID from the HTML dropdown list 
        $.ajax({                       // initialize an AJAX request
            type: "POST",
            url: '{% url "get_topics_ajax" %}',
            data: {
                'subject_id': subjectId,       // add the country id to the POST parameters
                'csrfmiddlewaretoken':$('input[name=csrfmiddlewaretoken]').val(),
            },
            success: function (data) {   // `data` is from `get_topics_ajax` view function
                let html_data = '<option value="">---------</option>';
                data.forEach(function (data) {
                    html_data += `<option value="${data.id}">${data.title}</option>`
                });
                $("#question-topic").html(html_data); // replace the contents of the topic input with the data that came from the server
            }
        });
    });
</script>
{% endblock javascript %}

We define the url where the ajax request will be made in urls.py in the backend.

 path('get-topics-ajax/', get_topics_ajax, name="get_topics_ajax"),

We define our function that will work according to the url request in view.py as follows.

According to the subject_id, we get the topics related to it from the database. We send topics as json data to frontend. If there is a problem, we send an error message to frontend.

from quiz.models import Question, Topic, Subject
from django.http import JsonResponse,

def get_topics_ajax(request):
    if request.method == "POST":
        subject_id = request.POST['subject_id']
        try:
            subject = Subject.objects.filter(id = subject_id).first()
            topics = Topic.objects.filter(subject = subject)
        except Exception:
            data['error_message'] = 'error'
            return JsonResponse(data)
        return JsonResponse(list(topics.values('id', 'title')), safe = False) 

Good luck.