In this tutorial we are going to learn dynamic dependent select box using jquery, ajax Country and City.
This type of feature mostly use if you have use Country State City or you have working with Category
and you want to load Sub Category of particular category. models.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | #models.py from django.db import models class Country(models.Model): name = models.CharField(max_length = 30 ) def __str__( self ): return self .name class Meta: # managed = True db_table = 'myapp_country' class City(models.Model): country = models.ForeignKey(Country, on_delete = models.CASCADE) name = models.CharField(max_length = 30 ) def __str__( self ): return self .name class Meta: # managed = True db_table = 'myapp_city' class Person(models.Model): name = models.CharField(max_length = 100 ) birthdate = models.DateField(null = True , blank = True ) country = models.ForeignKey(Country, on_delete = models.SET_NULL, null = True ) city = models.ForeignKey(City, on_delete = models.SET_NULL, null = True ) def __str__( self ): return self .name class Meta: # managed = True db_table = 'myapp_person' |
Database Table
CREATE TABLE myapp_country (
id INTEGER NOT NULL
PRIMARY KEY AUTOINCREMENT,
name VARCHAR (30) NOT NULL
);
INSERT INTO myapp_country (id, name) VALUES (1, 'Philippines');
INSERT INTO myapp_country (id, name) VALUES (2, 'United States');
INSERT INTO myapp_country (id, name) VALUES (3, 'Russia');
INSERT INTO myapp_country (id, name) VALUES (4, 'Brazil');
INSERT INTO myapp_country (id, name) VALUES (5, 'United Kingdom');
CREATE TABLE myapp_city (
id INTEGER NOT NULL
PRIMARY KEY AUTOINCREMENT,
name VARCHAR (30) NOT NULL,
country_id INTEGER NOT NULL
REFERENCES myapp_country (id) DEFERRABLE INITIALLY DEFERRED
);
INSERT INTO myapp_city (id, name, country_id) VALUES (1, 'Olongapo City', 1);
INSERT INTO myapp_city (id, name, country_id) VALUES (2, 'Angeles City', 1);
INSERT INTO myapp_city (id, name, country_id) VALUES (3, 'Davao City', 1);
INSERT INTO myapp_city (id, name, country_id) VALUES (4, 'Pasay City', 1);
INSERT INTO myapp_city (id, name, country_id) VALUES (5, 'Manila City', 1);
INSERT INTO myapp_city (id, name, country_id) VALUES (6, 'New York', 2);
INSERT INTO myapp_city (id, name, country_id) VALUES (7, 'San Francisco', 2);
INSERT INTO myapp_city (id, name, country_id) VALUES (8, 'Los Angeles', 2);
INSERT INTO myapp_city (id, name, country_id) VALUES (9, 'Chicago', 2);
INSERT INTO myapp_city (id, name, country_id) VALUES (10, 'Seattle', 2);
INSERT INTO myapp_city (id, name, country_id) VALUES (11, 'Moscow', 3);
INSERT INTO myapp_city (id, name, country_id) VALUES (12, 'Saint Petersburg', 3);
INSERT INTO myapp_city (id, name, country_id) VALUES (13, 'Yekaterinburg', 3);
INSERT INTO myapp_city (id, name, country_id) VALUES (14, 'Kazan', 3);
INSERT INTO myapp_city (id, name, country_id) VALUES (15, 'Krasnodar', 3);
INSERT INTO myapp_city (id, name, country_id) VALUES (16, 'Sao Paulo', 4);
INSERT INTO myapp_city (id, name, country_id) VALUES (17, 'Rio de Janeiro', 4);
INSERT INTO myapp_city (id, name, country_id) VALUES (18, 'Belo Horizonte', 4);
INSERT INTO myapp_city (id, name, country_id) VALUES (19, 'Curitiba', 4);
INSERT INTO myapp_city (id, name, country_id) VALUES (20, 'Recife', 4);
INSERT INTO myapp_city (id, name, country_id) VALUES (21, 'London', 5);
INSERT INTO myapp_city (id, name, country_id) VALUES (22, 'Huddersfield', 5);
INSERT INTO myapp_city (id, name, country_id) VALUES (23, 'Glasgow', 5);
INSERT INTO myapp_city (id, name, country_id) VALUES (24, 'Edinburgh', 5);
INSERT INTO myapp_city (id, name, country_id) VALUES (25, 'Cambridge', 5);
CREATE TABLE myapp_person (
id INTEGER NOT NULL
PRIMARY KEY AUTOINCREMENT,
name VARCHAR (100) NOT NULL,
birthdate DATE,
city_id INTEGER REFERENCES myapp_city (id) DEFERRABLE INITIALLY DEFERRED,
country_id INTEGER REFERENCES myapp_country (id) DEFERRABLE INITIALLY DEFERRED
);
urls.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | #urls.py from django.contrib import admin from django.urls import path from myapp import views from django.conf.urls import url from django.urls import include, path urlpatterns = [ path( 'admin/' , admin.site.urls), path(' ', views.PersonListView.as_view(), name=' person_changelist'), path( 'add/' , views.PersonCreateView.as_view(), name = 'person_add' ), path( '<int:pk>/' , views.PersonUpdateView.as_view(), name = 'person_change' ), path( 'ajax/load-cities/' , views.load_cities, name = 'ajax_load_cities' ), ] < / int :pk> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | #views.py from django.shortcuts import render, redirect from django.views.generic import ListView, CreateView, UpdateView from django.urls import reverse_lazy from myapp.models import Person, City from myapp.forms import PersonForm class PersonListView(ListView): model = Person context_object_name = 'people' template_name = 'person_list.html' class PersonCreateView(CreateView): model = Person form_class = PersonForm template_name = 'person_form.html' success_url = reverse_lazy( 'person_changelist' ) class PersonUpdateView(UpdateView): model = Person form_class = PersonForm template_name = 'person_form.html' success_url = reverse_lazy( 'person_changelist' ) def load_cities(request): country_id = request.GET.get( 'country' ) cities = City.objects. filter (country_id = country_id).order_by( 'name' ) return render(request, 'city_dropdown_list_options.html' , { 'cities' : cities})<span style = "font-family: "times new roman";" ><span style = "white-space: normal;" ><b> < / b>< / span>< / span> |
forms.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | #forms.py from django import forms from myapp.models import Person, City class PersonForm(forms.ModelForm): class Meta: model = Person fields = ( 'name' , 'birthdate' , 'country' , 'city' ) 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' ) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | //templates/person_list.html {% extends 'base.html' %} {% block title %}Django Chained Dropdown List - Select Box using jQuery Ajax Country City{% endblock %} {% block content %} <table class = "table table-striped custab" > <thead> <a href= "{% url 'person_add' %}" class = "btn btn-primary btn-xs pull-right" ><b>+</b> Add new Person</a> <tr> <th>Name</th> <th>Birthdate</th> <th>Country</th> <th>City</th> <th class = "text-center" >Action</th> </tr> </thead> <tbody> {% for person in people %} <tr> <td><a href= "{% url 'person_change' person.pk %}" >{{ person.name }}</a></td> <td>{{ person.birthdate }}</td> <td>{{ person.country.name }}</td> <td>{{ person.city.name }}</td> <td class = "text-center" ><a class = 'btn btn-info btn-xs' href= "#" ><span class = "glyphicon glyphicon-edit" ></span> Edit</a> <a href= "#" class = "btn btn-danger btn-xs" ><span class = "glyphicon glyphicon-remove" ></span> Del</a></td> </tr> {% empty %} <tr> <td colspan= "4" >No person in the database. <a href= "{% url 'person_add' %}" >Add the first person</a>.</td> </tr> {% endfor %} </tbody> </table> {% endblock %} |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | //templates/person_form.html {% extends 'base.html' %} {% block content %} {% load widget_tweaks %} <h2>Person Form</h2> <form method= "post" id= "personForm" data-cities-url= "{% url 'ajax_load_cities' %}" novalidate> {% csrf_token %} <table> <!-- {{ form.as_table }} --> </table> {% for field in form.visible_fields %} <div class = "form-group" > <label for = "{{ field.id_for_label }}" >{{ field.label }}</label> {{ field|add_class: 'form-control' }} {% for error in field.errors %} <span class = "help-block" >{{ error }}</span> {% endfor %} </div> {% endfor %} <button type= "submit" class = "btn btn-success" >Save</button> <a href= "{% url 'person_changelist' %}" >Home</a> </form> <script> $( "#id_country" ).change( function () { var url = $( "#personForm" ).attr( "data-cities-url" ); var countryId = $(this).val(); $.ajax({ url: url, data: { 'country' : countryId }, success: function (data) { $( "#id_city" ).html(data); } }); }); </script> {% endblock %} |
1 2 3 4 5 | //templates/city_dropdown_list_options.html <option value= "" >---------</option> {% for city in cities %} <option value= "{{ city.pk }}" >{{ city.name }}</option> {% endfor %} |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | //templates/base.html <!DOCTYPE html> <html lang= "en" > <head> {% load static %} <link rel= "stylesheet" type= "text/css" href= "{% static 'css/bootstrap.css' %}" /> <meta charset= "UTF-8" name= "viewport" content= "width=device-width, initial-scale=1" /> <title>{% block title %}Django Chained Dropdown List - Select Box using jQuery Ajax Country City{% endblock %}</title> </head> <body> <nav class = "navbar navbar-default" > <div class = "container-fluid" > <a class = "navbar-brand" >Cairocoders</a> </div> </nav> <div class = "container" > <div class = "col-md-12 well" > <h3 class = "text-primary" >Django Chained Dropdown List - Select Box using jQuery Ajax Country City</h3> <hr style= "border-top:1px dotted #ccc;" /> {% block content %} {% endblock %} </div> </div> <style> .custab{ border: 1px solid #ccc; padding: 5px; margin: 5% 0; box-shadow: 3px 3px 2px #ccc; transition: 0.5s; } .custab:hover{ box-shadow: 3px 3px 0px transparent; transition: 0.5s; } </style> </body> </html> |
INSTALLED_APPS = [
'myapp',
'widget_tweaks', #pip install django-widget-tweaks https://pypi.org/project/django-widget-tweaks/
]