How do I create a dependent dropdown form in Django

  django, django-forms, dropdown, python

I’ve searched far and wide for an answer to this question with no success. I would like to create a simple dependent dropdown form in Django. The first field is to be a ‘workout’ that is to be selected and the second field should be of models.PositiveIntergerField() with some validators in it coming from the django.core.validators module. I would like this integer to be dependent on the amount of ‘exercises’ within the chosen ‘workout’ (exercise has a foreign key to workout). Once a user selects a workout, the amount of exercises is dependent on how many exercises are actually under that workout. So far, I have been able to get the first field but not the integer field. Below are the forms.py, views.py, model.py, and routine.html of my application.

forms.py – have it set to where a user can only see the workouts & exercises they have created

from django import forms
from .models import Workout, Exercise, Routine
class RoutineForm(forms.ModelForm):
    """creates a form for a routine"""

    def __init__(self, *args, user=None, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['workout'].queryset = Workout.objects.filter(owner=user)

    class Meta:
        model = Routine
        fields = ['workout']
        labels = {'workout': '',}

views.py

from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required
from .models import Workout, Exercise
from .forms import RoutineForm

@login_required
def routine(request):
    """display a dropdown of all workouts for a user"""
    if request.method != 'POST':
        form = RoutineForm(user=request.user) #creating a form here with user id in mind
        #the request has a user attribute because we know who is requesting this information
    else:
        form = RoutineForm(data=request.POST, user=request.user) #loading data from form with user id in mind
        if form.is_valid():
            form.instance.owner = request.user
            new_routine = form.save()
            return redirect('index')
    context = {'form':form}
    return render(request, 'routine_workouts_app/routine.html', context)

models.py

from django.db import models
from django.contrib.auth.models import User
from django.core.validators import MaxValueValidator, MinValueValidator

class Routine(models.Model):
    """Shows a routine"""
    workout = models.ForeignKey(Workout, on_delete=models.CASCADE) #does not have and id attribute bc it is a key not an object
    owner = models.ForeignKey(User, on_delete=models.CASCADE)
    #num_of_exercises = models.PositiveIntegerField(default=0, validators=[MaxValueValidator(#integer I need based off of workout), MinValueValidator(0)])

    def __str__(self):
        return 'this is a routine'

routine.html

{% extends 'routine_workouts_app/base.html' %}

{% block content %}
    <p>this is the home page for creating routines</p>
    <form action="{% url 'routine_workouts_app:routine' %}" method="POST">
        {% csrf_token %}
        {{ form.as_p }}
        <button name='submit'>create routine</button>
    </form>
{% endblock content %}

This code is functioning but not to the extent I want it to. I have read on multiple sites about jQuery, Ajax, django-2select, and other things but I have had trouble implementing them and get stuck somewhere along the line. Any suggestions on how to implement a dependent dropdown form? Are there any textbooks that go over this topic? Websites with an in-depth explanation? I am attaching a photo of what my application looks like with the code provided.

photo of working single dropdown

Source: Python Questions

LEAVE A COMMENT