article

Tuesday, June 21, 2022

Python Django Dependent Chained Dropdown List - Dynamic Dependent Select Box using jQuery Ajax

Python Django Dependent Chained Dropdown List - Dynamic Dependent Select Box using jQuery Ajax

Register App myapp
 
//devproject/settings.py
  
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'myapp', #add myapp
]
Creating View
myapp/views.py
 
//myapp/views.py
  
from django.shortcuts import render, redirect, get_object_or_404

from .forms import MemberCreationForm
from .models import Member, City

def create_view(request):
    form = MemberCreationForm()
    if request.method == 'POST':
        form = MemberCreationForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect('add')
    return render(request, 'home.html', {'form': form})

def update_view(request, pk):
    member = get_object_or_404(Member, pk=pk)
    form = MemberCreationForm(instance=member)
    if request.method == 'POST':
        form = MemberCreationForm(request.POST, instance=member)
        if form.is_valid():
            form.save()
            return redirect('change', pk=pk)
    return render(request, 'home.html', {'form': form})

# AJAX
def load_cities(request):
    country_id = request.GET.get('country_id')
    cities = City.objects.filter(country_id=country_id).all()
    return render(request, 'city_dropdown_list_options.html', {'cities': cities})
devproject/urls.py
 
//devproject/urls.py
  
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('myapp.urls'))
]
myapp/urls.py
 
//myapp/urls.py
  
from django.urls import path

from . import views

urlpatterns = [
    path('member/add/', views.create_view, name='add'),
    path('member/<int:pk>/', views.update_view, name='change'),

    path('member/ajax/load-cities/', views.load_cities, name='ajax_load_cities'), # AJAX
]
myapp/forms.py
 
//myapp/forms.py
  
from django import forms

from myapp.models import Member, City

class MemberCreationForm(forms.ModelForm):
    class Meta:
        model = Member
        fields = '__all__'
        widgets = { 'name': forms.TextInput(attrs={ 'class': 'form-control' }), 
            'email': forms.EmailInput(attrs={ 'class': 'form-control' }),
            'country': forms.Select(attrs={ 'class': 'form-select' }),
            'city': forms.Select(attrs={ 'class': 'form-select' }),
        }    

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['city'].queryset = City.objects.none()

        if 'country' in self.data:
            try:
                country_id = int(self.data.get('country'))
                self.fields['city'].queryset = City.objects.filter(country_id=country_id).order_by('name')
            except (ValueError, TypeError):
                pass  # invalid input from the client; ignore and fallback to empty City queryset
        elif self.instance.pk:
            self.fields['city'].queryset = self.instance.country.city_set.order_by('name')
Make Migrations
Run the commands below to make migrations:
python manage.py makemigrations
python manage.py migrate
C:\django\devproject>python manage.py makemigrations
C:\django\devproject>python manage.py migrate
myapp/models.py
 
//myapp/models.py
  
from django.db import models

class Country(models.Model):
    name = models.CharField(max_length=40)

    def __str__(self):
        return self.name

class City(models.Model):
    country = models.ForeignKey(Country, on_delete=models.CASCADE)
    name = models.CharField(max_length=40)

    def __str__(self):
        return self.name

class Member(models.Model):
    name = models.CharField(max_length=124)
    email = models.CharField(max_length=125)
    country = models.ForeignKey(Country, on_delete=models.SET_NULL, blank=True, null=True)
    city = models.ForeignKey(City, on_delete=models.SET_NULL, blank=True, null=True)

    def __str__(self):
        return self.name
myapp/admin.py
 
//myapp/admin.py
  
from django.contrib import admin

# Register your models here.
from myapp.models import City, Country, Member

admin.site.register(City)
admin.site.register(Country)
admin.site.register(Member)
Bootstrap 5
https://getbootstrap.com/docs/5.0/getting-started/introduction/
https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css

Jquery
https://jquery.com/download/
CDN : jsDelivr CDN
https://www.jsdelivr.com/package/npm/jquery
https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js

myapp/templates/home.html
//myapp/templates/home.html
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Dependent Dropdown in Django</title>
    <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css">
</head>
<body>
<div class="container"> <p><h1>Python Django Dependent Chained Dropdown List - Dynamic Dependent Select Box using jQuery Ajax</h1></p> 
    <div class="card">
        <div class="card-header">
            Member Form
        </div>
        <div class="card-body">
            <form method="post" id="MemberForm" data-cities-url="{% url 'ajax_load_cities' %}" class="form-horizontal" role="form">
                {% csrf_token %}
                {{ form.as_p }}
                <input type="submit" value="Submit" class="btn btn-info">
            </form>
        </div>
      </div>
</div>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script>
    $("#id_country").change(function () {
        const url = $("#MemberForm").attr("data-cities-url");  // get the url of the `load_cities` view
        const countryId = $(this).val();  // get the selected country ID from the HTML input

        $.ajax({                       // initialize an AJAX request
            url: url,                    // set the url of the request (= /members/ajax/load-cities/ )
            data: {
                'country_id': countryId       // GET parameters
            },
            success: function (data) {   
                $("#id_city").html(data); 
            }
        });

    });
</script>
</body>
</html>
myapp/templates/city_dropdown_list_options.html
//myapp/templates/city_dropdown_list_options.html
<option value="">---------</option>
{% for city in cities %}
<option value="{{ city.pk }}">{{ city.name }}</option>
{% endfor %}
Run : C:\django\devsite>python manage.py runserver

Related Post