How to do a multiple dependent dropdown Django form

Andre Perez
3 min readSep 9, 2021
Thumbnail Image
multiple dependent dropdown form fields
Our dropdown form

So you have a Django website and want multiple dropdown form fields? And you need them to be dependent on each other?

Well, this might be easier than you think.

The magic word here is AJAX, which stands for Asynchronous JavaScript and XML.

Using AJAX, you can easily query the Database with Django’s ORM (so no risk of SQL injection) and have a more responsive and dynamic website.

I assume you have a basic knowledge of JavaScript (Syntax and DOM), HTML, and Django (function-based views, a bit of Django’s template syntax, and ORM queries).

In case you have no idea what I just talked about or don’t feel ready to continue, I’ll put some links at the end of this article to help you out.

Let’s get started

First, let’s take a look at our form template:

{% extends ‘base.html’ %}{% load static %}{% block title %}New Order{% endblock %}{% block extra_head %}{{ form.media }}{% endblock %}{% block content %}<div>  <form action=”” id=”orderForm” method=”POST”>    {% csrf_token %}    {{ form.as_p }}    <button type=”submit” class=”btn btn-primary”>Create Order</button>  </form></div><script src=”{% static ‘js/orderDropdownSelection.js’ %}”></script>{% endblock %}

Just a simple Django HTML template, with a single JavaScript call at the end. We’ll get back to the JavaScript later. Now, let’s see how we are defiining our models, views and URLs.

models.py (There are two of them)

Institute and Discipline models
Order model

views.py

class CreateOrder(LoginRequiredMixin, CreateView):
model = QuestionOrder
template_name = ‘new_question_order.html’
form_class = QuestionOrderForm
def get_success_url(self):
return reverse(‘order-detail’, kwargs={‘pk’: self.object.pk})

urls.py

path(‘order/create/’, CreateOrder.as_view(), name=’create-order’)

As you can see, nothing special either. So now we can finally advance to the AJAX part.

Making requests via AJAX

Since this is a somewhat big piece of code, I’ll put some GitHub gists to make this article easier to read:

views.py

AJAX Django views

Dropdown HTMLs (there’s one for each view)

All dropdown HTML (there’s four of them)

urls.py

AJAX Django URL path

forms.py

Django forms

orderDropdownSelection.js

AJAX Dropdown Javascript

So let’s strip this code down:

The forms.py erases all dropdown information using Model.objects.none(), leaving data only for the Institute dropdown. The Institute ID could also be passed as an URL kwarg, to block users from creating orders for other institutes.

All the views follow the same pattern. First we get an object passed through request (“something_id”). This object is a ForeignKey for the model we’re targeting. Then we query the database to retrieve querysets that contain the information we want in our dropdown and load it in our Dropdown HTML.

The AJAX script then calls the views, sending them the user input from the previously filled dropdowns and filling the empty ones accordingly.

And that’s it. Not as simple as I made it look before, but still very logical and functional.
What do you think? Do you believe there is a better or easier way to do it?
Leave a comment if you can, or applause if I helped you. I believe there is always something we can learn from each other, so your feedback matters.
Till next time!

Some study sources:

--

--

Andre Perez

Web Developer - Python, JavaScript and learning WASM and Rust