Issue
I have adapted the following sample code https://tutorial101.blogspot.com/2021/01/python-flask-dynamic-loading-of.html in Flask to use the SQlite database. The objective of the app.py is to display the options for car brands, and then to display the available models by brand. The app.py uses two drop down boxes from which the user can make the selection. The original source code is written in Flask to access a MySQL database. I adapted the code for the app.py to use SQlite db.
The app.py is working perfectly. And I can visualize the two drop down boxes with the options. When I select a car brand, the app updates the second drop down box with the available models.
When the submit button is pressed I want to display the values of the two selections. Specifically which is the selected car make, and which is the selected model.
I have included an instruction in the code to display the value of the car brand, and also display the values that correspond to the car models. However, I cannot find a way to obtain the value of the selected car model.
How can I achieve this?
Thanks.
NB: The question text has been edited to be more specific. The essence of the question has not changed.
I attach the source code and the templates used.
app.py:
# flask sqlalchemy
from flask_sqlalchemy import SQLAlchemy
# app.py
from flask import Flask, render_template, request, jsonify
app = Flask(__name__)
app.config['SECRET_KEY'] = "caircocoders-ednalan"
# sqlite config
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///testingdb.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# Bind the instance to the 'app.py' Flask application
db = SQLAlchemy(app)
class Carbrands(db.Model):
__tablename__ = 'carbrands'
brand_id = db.Column(db.Integer, primary_key = True)
brand_name = db.Column(db.String(250))
def __repr__(self):
return '\n brand_id: {0} brand_name: {1}'.format(self.brand_id, self.brand_name)
def __str__(self):
return '\n brand_id: {0} brand_name: {1}'.format(self.brand_id, self.brand_name)
class Carmodels(db.Model):
__tablename__ = 'carmodels'
model_id = db.Column(db.Integer, primary_key = True)
brand_id = db.Column(db.Integer)
car_models = db.Column(db.String(250))
def __repr__(self):
return '\n model_id: {0} brand_id: {1} car_models: {2}'.format(self.model_id, self.brand_id, self.car_models)
def __str__(self):
return '\n model_id: {0} brand_id: {1} car_models: {2}'.format(self.model_id, self.brand_id, self.car_models)
# index.html
@app.route('/', methods=["POST","GET"])
def index():
q = Carbrands.query.all()
print(q)
carbrands = q
return render_template('index.html', carbrands=carbrands)
# response.html
@app.route("/get_child_categories", methods=["POST","GET"])
def get_child_categories():
if request.method == 'POST':
parent_id = request.form['parent_id']
car = Carbrands.query.filter_by(brand_id=parent_id).first()
print("Car brand '{0}' parent_id '{1}'".format(car.brand_name, parent_id))
carmodels = Carmodels.query.filter_by(brand_id=parent_id).all()
print(carmodels)
return jsonify({'htmlresponse': render_template('response.html', carmodels=carmodels)})
if __name__ == "__main__":
app.run(debug=True)
index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Python Flask Dynamic Loading of ComboBox using jQuery Ajax and SQlite</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" />
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.0/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
$('#search_category_id').change(function(){
$.post("/get_child_categories", {
parent_id: $('#search_category_id').val()
}, function(response){
$('#show_sub_categories').html(response);
$('#show_sub_categories').append(response.htmlresponse);
});
return false;
});
});
</script>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-lg-2"></div>
<div class="col-lg-8">
<h3 align="center">Python Flask Dynamic Loading of ComboBox using jQuery Ajax and SQlite</h3>
<form action="#" name="form" id="form" method="post">
<div class="form-group">
<label>Select Category</label>
<select name="search_category" id="search_category_id" class="form-control">
<option value="" selected="selected"></option>
{% for row in carbrands %}
<option value='{{row.brand_id}}'>{{row.brand_name}}</option>
{% endfor %}
</select>
</div>
<div id="show_sub_categories"></div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
<div class="col-lg-2"></div>
</div>
</div>
</body>
</html>
response.html:
<div class="form-group">
<label>Select Sub Category</label>
<select name="sub_category" id="sub_category_id" class="form-control">
<option value="" selected="selected"></option>
{% for row in carmodels %}
<option value="{{row.model_id}}">{{row.car_models}}</option>
{% endfor %}
</select>
</div>
Solution
I have found the solution. I attach the source code as a reference in case someone is interested in the solution. This question has meant research effort.
It can be seen in the screenshot that the option of selecting a car brand and the selection of the car model is displayed.
When selecting a car make, the second drop down box displays the list of models corresponding to the car make.
When the process selection button is pressed, the application displays the message indicating the car make and the car model that has been selected.
The solution was to implement a reading of the database tables that have the car brands and models. This information is converted into a python dictionary to feed the two drop down boxes. When selecting the car make, the application displays in the second drop down box the car models that correspond to the car make SEE: @app.route('/_update_dropdown')
The https://api.jquery.com/jquery.getjson/ documentation was crucial to the solution. In particular the implementation of $ .getJSON ('/ _ update_dropdown', ... and the implementation of $ .getJSON ('/ _ process_data', ... In many of the examples in Flask about the dynamic update of dropdown boxes it is demonstrated how the drop down boxes are implemented, however it is not mentioned how to obtain the selected data; that are important to continue the process. In this case, this solution includes all the details for the implementation of dynamic drop down boxes in Flask and the processing of the selected values.
After researching possible solutions, I found the link to a similar question. So, I studied the solution and adapted it to my needs. I acknowledge the author of the link: How to create chained selectfield in flask without refreshing the page? for your valuable contribution. Without that guidance it would not have been possible to be successful in solving this question.
app.py:
# SEE: https://stackoverflow.com/questions/25978879/how-to-create-chained-selectfield-in-flask-without-refreshing-the-page/49969686#49969686
# flask sqlalchemy
from flask_sqlalchemy import SQLAlchemy
import sqlalchemy
# app.py
from flask import Flask, render_template, request, jsonify
import json
# Initialize the Flask application
app = Flask(__name__)
app.config['SECRET_KEY'] = "caircocoders-ednalan"
# sqlite config
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///cars.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# Bind the instance to the 'app.py' Flask application
db = SQLAlchemy(app)
class Carbrands(db.Model):
__tablename__ = 'carbrands'
brand_id = db.Column(db.Integer, primary_key = True)
brand_name = db.Column(db.String(250))
def __repr__(self):
return '\n brand_id: {0} brand_name: {1}'.format(self.brand_id, self.brand_name)
def __str__(self):
return '\n brand_id: {0} brand_name: {1}'.format(self.brand_id, self.brand_name)
class Carmodels(db.Model):
__tablename__ = 'carmodels'
model_id = db.Column(db.Integer, primary_key = True)
brand_id = db.Column(db.Integer)
car_model = db.Column(db.String(250))
def __repr__(self):
return '\n model_id: {0} brand_id: {1} car_model: {2}'.format(self.model_id, self.brand_id, self.car_model)
def __str__(self):
return '\n model_id: {0} brand_id: {1} car_model: {2}'.format(self.model_id, self.brand_id, self.car_model)
def get_dropdown_values():
"""
dummy function, replace with e.g. database call. If data not change, this function is not needed but dictionary
could be defined globally
"""
# Create a dictionary (myDict) where the key is
# the name of the brand, and the list includes the names of the car models
#
# Read from the database the list of cars and the list of models.
# With this information, build a dictionary that includes the list of models by brand.
# This dictionary is used to feed the drop down boxes of car brands and car models that belong to a car brand.
#
# Example:
#
# {'Toyota': ['Tercel', 'Prius'],
# 'Honda': ['Accord', 'Brio']}
carbrands = Carbrands.query.all()
# Create an empty dictionary
myDict = {}
for p in carbrands:
key = p.brand_name
brand_id = p.brand_id
# Select all car models that belong to a car brand
q = Carmodels.query.filter_by(brand_id=brand_id).all()
# build the structure (lst_c) that includes the names of the car models that belong to the car brand
lst_c = []
for c in q:
lst_c.append( c.car_model )
myDict[key] = lst_c
class_entry_relations = myDict
return class_entry_relations
@app.route('/_update_dropdown')
def update_dropdown():
# the value of the first dropdown (selected by the user)
selected_class = request.args.get('selected_class', type=str)
# get values for the second dropdown
updated_values = get_dropdown_values()[selected_class]
# create the value sin the dropdown as a html string
html_string_selected = ''
for entry in updated_values:
html_string_selected += '<option value="{}">{}</option>'.format(entry, entry)
return jsonify(html_string_selected=html_string_selected)
@app.route('/_process_data')
def process_data():
selected_class = request.args.get('selected_class', type=str)
selected_entry = request.args.get('selected_entry', type=str)
# process the two selected values here and return the response; here we just create a dummy string
return jsonify(random_text="You selected the car brand: {} and the model: {}.".format(selected_class, selected_entry))
@app.route('/')
def index():
"""
initialize drop down menus
"""
class_entry_relations = get_dropdown_values()
default_classes = sorted(class_entry_relations.keys())
default_values = class_entry_relations[default_classes[0]]
return render_template('index.html',
all_classes=default_classes,
all_entries=default_values)
if __name__ == '__main__':
app.run(debug=True)
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container">
<div class="header">
<h1 class="text-center text-muted">Dynamic dropdowns</h1>
</div>
<br><br><br>
<div class="row">
<div class="form-group col-xs-6">
<label for="all_classes">Select a car</label>
<select class="form-control" style="color: white; background: #34568B;" id="all_classes">
{% for o in all_classes %}
<option value="{{ o }}">{{ o }}</option>
{% endfor %}
</select>
</div>
<div class="form-group col-xs-6">
<label for="all_entries">Select a model</label>
<select class="form-control" style="color:white; background:#009B77;" id="all_entries">
{% for o in all_entries %}
<option value="{{ o }}">{{ o }}</option>
{% endfor %}
</select>
</div>
</div>
<div>
<button type="button" style="color:white; background:#3498DB;" id="process_input">Process selection!</button>
</div><br><br>
<div id="processed_results">
Here we display some output based on the selection
</div>
</div>
<script src="https://code.jquery.com/jquery-1.12.4.js" type="text/javascript"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
$('#all_classes').change(function(){
$.getJSON('/_update_dropdown', {
selected_class: $('#all_classes').val()
}).done(function(data) {
$('#all_entries').html(data.html_string_selected);
})
});
$('#process_input').bind('click', function() {
$.getJSON('/_process_data', {
selected_class: $('#all_classes').val(),
selected_entry: $('#all_entries').val(),
}).success(function(data) {
$('#processed_results').text(data.random_text);
})
return false;
});
});
</script>
</body>
</html>
create_tables_and_data.sql:
--
-- Table structure for table `carbrands`
--
CREATE TABLE CARBRANDS (
BRAND_ID INT PRIMARY KEY NOT NULL,
BRAND_NAME CHAR(250)
);
--
-- Dumping data for table `carbrands`
--
INSERT INTO CARBRANDS (BRAND_ID, BRAND_NAME) VALUES (1, 'Toyota');
INSERT INTO CARBRANDS (BRAND_ID, BRAND_NAME) VALUES (2, 'Honda');
INSERT INTO CARBRANDS (BRAND_ID, BRAND_NAME) VALUES (3, 'Suzuki');
INSERT INTO CARBRANDS (BRAND_ID, BRAND_NAME) VALUES (4, 'Mitsubishi');
INSERT INTO CARBRANDS (BRAND_ID, BRAND_NAME) VALUES (5, 'Hyundai');
--
-- Table structure for table `carmodels`
--
CREATE TABLE CARMODELS (
MODEL_ID INT PRIMARY KEY NOT NULL,
BRAND_ID INT NOT NULL,
CAR_MODEL CHAR(250) NOT NULL
);
--
-- Dumping data for table `carmodels`
--
INSERT INTO CARMODELS (MODEL_ID, BRAND_ID, CAR_MODEL) VALUES (1, 1, 'Toyota Corolla');
INSERT INTO CARMODELS (MODEL_ID, BRAND_ID, CAR_MODEL) VALUES (2, 1, 'Toyota Camry');
INSERT INTO CARMODELS (MODEL_ID, BRAND_ID, CAR_MODEL) VALUES (3, 1, 'Toyota Yaris');
INSERT INTO CARMODELS (MODEL_ID, BRAND_ID, CAR_MODEL) VALUES (4, 1, 'Toyota Sienna');
INSERT INTO CARMODELS (MODEL_ID, BRAND_ID, CAR_MODEL) VALUES (5, 1, 'Toyota RAV4');
INSERT INTO CARMODELS (MODEL_ID, BRAND_ID, CAR_MODEL) VALUES (6, 1, 'Toyota Highlander');
INSERT INTO CARMODELS (MODEL_ID, BRAND_ID, CAR_MODEL) VALUES (7, 2, 'Honda HR-V');
INSERT INTO CARMODELS (MODEL_ID, BRAND_ID, CAR_MODEL) VALUES (8, 2, 'Honda Odyssey');
INSERT INTO CARMODELS (MODEL_ID, BRAND_ID, CAR_MODEL) VALUES (9, 3, 'Swift');
INSERT INTO CARMODELS (MODEL_ID, BRAND_ID, CAR_MODEL) VALUES (10, 3, 'Celerio');
INSERT INTO CARMODELS (MODEL_ID, BRAND_ID, CAR_MODEL) VALUES (11, 3, 'Ertiga');
INSERT INTO CARMODELS (MODEL_ID, BRAND_ID, CAR_MODEL) VALUES (12, 3, 'Vitara');
INSERT INTO CARMODELS (MODEL_ID, BRAND_ID, CAR_MODEL) VALUES (13, 4, 'Mirage');
INSERT INTO CARMODELS (MODEL_ID, BRAND_ID, CAR_MODEL) VALUES (14, 4, 'Mirage G4');
INSERT INTO CARMODELS (MODEL_ID, BRAND_ID, CAR_MODEL) VALUES (15, 4, 'Xpander Cross');
INSERT INTO CARMODELS (MODEL_ID, BRAND_ID, CAR_MODEL) VALUES (16, 4, 'Montero Sport');
INSERT INTO CARMODELS (MODEL_ID, BRAND_ID, CAR_MODEL) VALUES (17, 4, 'Strada Athlete');
INSERT INTO CARMODELS (MODEL_ID, BRAND_ID, CAR_MODEL) VALUES (18, 5, 'Reina ');
INSERT INTO CARMODELS (MODEL_ID, BRAND_ID, CAR_MODEL) VALUES (19, 5, 'Accent');
INSERT INTO CARMODELS (MODEL_ID, BRAND_ID, CAR_MODEL) VALUES (20, 5, 'Elantra');
INSERT INTO CARMODELS (MODEL_ID, BRAND_ID, CAR_MODEL) VALUES (21, 5, 'Tucson');
Answered By - Ramiro
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.