How to display mySQL data from server side to HTML from AJAX - python

I can't find many tutorials on this, mostly could find ones for PHP. I am trying to create a search bar with an autocomplete feature using python Flask, mySQL, and Ajax. I got things working up to capturing the keystroke and selecting from the database. After that, I can't get any of this to display on the client side.
I've tried using a partial page but none of this will display.
server.py file
#app.route("/search", methods=['POST'])
def search():
output = ''
mysql = connectToMySQL("countries_db")
data_received = json.loads(request.data)
data = data_received['query']
var_data = '%' + data + '%'
mysqlQuery = "SELECT name FROM countries WHERE countries.name LIKE '%s' LIMIT 10;" %var_data
result = mysql.query_db(mysqlQuery)
output += '<ul class="list-unstyled">'
if len(result) > 0:
for country in result:
output += '<li>' + country["name"] + '</li>'
else:
output += '<li>Country Not Found</li>'
output += '</ul>'
return render_template("index.html", result=result)
index.html
<li class="search">
<div class="auto">
<img src="{{ url_for('static', filename='search.png') }}">
<input class="search-bar" type="text" id="country" name="country" aria-label="Search through site content"
placeholder="Search for a Country">
<div class="countryList">
{% for country in result %}
<p>{{country.name}}</p>
{% endfor %}
</div>
</div>
</li>
# Ajax
<script type="text/javascript">
$(document).ready(function () {
$('#country').keyup(function () {
var query = $(this).val();
if (query != '') {
$.ajax({
url: "/search",
method: "POST",
data: JSON.stringify({
query: query,
}),
dataType: "JSON",
contentType: 'application/json;charset=UTF-8',
success: function (data) {
data = data.data
$('#countryList').fadeIn();
$('#countryList').html(data)
},
dataType: 'text'
})
}
})
})

ids are refferred using # and class names are referred using . in Jquery. Replace the # before country-list with '.'

Related

How to load content into div element with flask

I'd like to fill / update a div area in index.html with the result from the python function, but I don't know how to do this. I know there are several other questions with a similar topic but I couldn't succeed with them because they were too specific. I'm pulling my hair out over this.
Would be someone so nice and guide me?
This is a function in main.py:
#app.route('/')
def index():
return render_template('index.html')
#app.route('/stat/')
def stat():
a = 2
b = 10
return(str(a) + ' is not ' + str(b))
this is the index.html:
<body>
<form action="/stat/">
<button type="submit" id="btn1" class="btn btn-primary btn-sm">check stat</button>
</form>
<div id="stat_content"></div>
</body>
As #S3DEV points out, you will need to pass the string to the template via an additional argument. For example, we might do something like this:
#app.route('/stat/', methods=['GET', 'POST']) # EDIT
def stat():
a = 2
b = 10
text = f"{a} is not equal to {b}"
return render_template("index.html", text=text)
In the code above, we set text to be the string to be passed to the template. In the template, we will be able to access this string variable as text.
Now when index.html is rendered, it will be looking for the text variable that is passed in from the Flask application. This is taken care of by Jinja 2, which is the rendering engine used by Flask.
<div id="stat_content">
{% if text %}
<h2>No text to show</h2>
{% else %}
<h2>{{ text }}</h2>
{% endif %}
</div>
Using Jinja 2 syntax with curly braces, we first check if the text variable exists or not; if it does not exist, we render the message, "No text to show." This will happen when we first route into "/", or the default home route of the Flask app.
Once the user fills out the form, however, they will be redirected to "/stat/", at which point we will now have generated text and passed it back to index.html via the render_template("index.html", text=text) function call. Then, when Jinja 2 renders index.html, it will see that text was passed over from the Flask app and display that message, namely that 2 is not equal to 10.
You want this initiated from the button right? Here's how to achieve that with ajax...
<body>
<form action="/stat/">
<button type="submit" onclick="GetData();" id="btn1" class="btn btn-primary btn-sm">check stat</button>
</form>
<div id="stat_content"></div>
</body>
<script type="text/javascript">
function GetData() {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == XMLHttpRequest.DONE) { // XMLHttpRequest.DONE == 4
if (xmlhttp.status == 200) {
document.getElementById("stat_content").innerHTML = xmlhttp.responseText;
}
else if (xmlhttp.status == 400) {
alert('There was an error 400');
}
else {
alert('something else other than 200 was returned');
}
}
};
xmlhttp.open("GET", "/stat/", true);
xmlhttp.send();
}
</script>
to update the content of that div, i think (based on your logic) you need to perform an ajax call to your stat function with the two parameters a and b submitted via POST request:
<form class="form-stat needs-validation" novalidate role="form">
<div class="form-group">
<input type="text" class="form-control" name="a" value="">
<div class="invalid-feedback"></div>
</div>
<div class="form-group">
<input type="text" class="form-control" name="b" value="">
<div class="invalid-feedback"></div>
</div>
<button type="submit" id="btn1" class="btn btn-primary btn-sm">check stat</button>
</form>
<div id="stat_content">Output: ?</div>
put the javascript code below after jquery call
<script>
$(document).ready(function() {
"use strict";
$('.form-stat').submit(function(e) {
e.preventDefault();
$.ajax({
url: "{{ url_for('stat') }}",
type: 'POST',
cache: false,
dataType: 'json',
data: $('.form-stat').serialize(),
success: function(data) {
// console.log(data);
$('.form-stat input[name=a]').val(''); // reset field
$('.form-stat input[name=b]').val(''); // reset field
$('#stat_content').html(data); // update div with the returned vlue
}
});
});
});
</script>
and you have to make little change to your stat function so you can submit dynamically the two parameters via POST like so :
from flask import Flask, request, make_response
import json
#app.route('/stat', methods=['POST'])
def stat():
if request.method == 'POST':
a = request.form['a']
b = request.form['b']
# check if inputs are valid to work with ..
res = str(a) + ' is not ' + str(b) if a != b else str(a) + ' and ' + str(b) + ' are equal.'
resp = make_response(json.dumps(res))
resp.status_code = 200
return resp

How can I CSS-style different returns from the same Python function?

I have a Python function which returns different messages in different scenarios. I want to style different messages differently, but I don't know how to do it.
This is my function:
def checkans(request, spanish_id):
random_spanish_question = get_object_or_404(Spanish, pk=spanish_id)
query = request.GET.get('ans')
coreng = random_spanish_question.english_set.get()
if query == str(coreng):
message = {
'message' : "Correct!"
}
return JsonResponse(message)
else:
message = {
'message' : "Incorrect. The correct answer is " + str(coreng)
}
return JsonResponse(message)
This is the HTML page:
<div class="flexcontainer" style="justify-content: center;">
<div class="sectiontitle">Quiz time
</div>
<div class="question_card">
<div class="question_word">{{ random_spanish_question }}</div>
<div id="msg"></div>
<form action="/checkans/{{random_spanish_question.id}}/" method="get">{% csrf_token %}
<label for="ans">Answer:</label>
<input type="text" name="ans"autofocus autocomplete="off" id="ansfield"/>
<input type="submit" value="Submit"/ id="submitbtn">
</form>
<input type="submit" value="Skip"/>
<button onclick="location.reload();">Next</button>
</div>
</div>
And this is the JS and AJAX code:
$('form').on('submit', function(e){
e.preventDefault();
var form = $(this);
var url = form.attr('action');
$.ajax({
type: 'GET',
url: url,
data: form.serialize(),
success: function(data){
$("#msg").html(data.message);
}
});
disable();
})
function disable(e){
$('#submitbtn').prop('disabled', true);
$('#ansfield').prop('disabled', true)
}
For example, I want to make the "Correct!" message green, while if it returns "Incorrect...", I want it to be red, and underline the answer, "str(coreng)". Please tell me how I can do it. Thanks in advance!
def checkans(request, spanish_id):
random_spanish_question = get_object_or_404(Spanish, pk=spanish_id)
query = request.GET.get('ans')
coreng = random_spanish_question.english_set.get()
if query == str(coreng):
message = {
'message' : "<span class=\"result-correct\">Correct!</span>"
}
return JsonResponse(message)
else:
message = { =
'message' : "<span class=\"result-incorrect\">Incorrect. The correct answer is " + str(coreng)</span>
}
return JsonResponse(message)
where those classes are defined in css:
.result-correct{
color:#00aa00; // or any shade of green you like
}
.result-incorrect{
color:#aa0000; // or any shade of red you like
}

change datalist input when another changes

I have two datalist input like this.
<input list="Province" name="Province" id="1">
<datalist id="Province">
{% for item in province_list %}
<option >{{item.Name}}</option>
{% endfor %}
</datalist>
<input list="City" name="City" id="2">
<datalist id="City">
{% for item in city_list %}
<option >{{item.Name}}</option>
{% endfor %}
</datalist>
i want when user select Province, i show list of that province city in input2.
I use JavaScript as below:
$("input[name=Province]").on('input', function () {
province = $(this).val();
dataList.empty();
$.ajax({
url: "/get_cars_"+province,
dataType: 'json',
success: function (data) {
console.log(data);
for (var i = 0, len = data.length; i < len; i++) {
$("input[name=City]").append("<option value='" +
data[i].city + "'></option>");
}
},
error: function (req, status, err) {
console.log('something went wrong', status, err);
}
});
});
In server side handle "/get_cities_\w+" request.
Remove second "for" statement in html code:
<datalist id="City">
</datalist>
Server side code in Django:
def getTheVendorProducts(request):
if request.is_ajax():
try:
uriQueri = request.build_absolute_uri()
province = uriQueri.split('_')[]
province = urllib.parse.unquote(province.split('?')[0])
vendorProduct= getTheCitiesOfprovince(province)
return HttpResponse(convertListToJson(vendorProduct), 'application/json')
except Exception as e:
logging.error(e)
return failedHttpResponse()
You need to define your own "getTheCitiesOfprovince" and "convertListToJson" functions. Visit here For more information about this type questions.

Django - Ajax POST error 403 (Forbidden) and 500 (Internal Server Error)

I'm using Ajax to post data. It threw the error 403 (Forbidden), then I added #csrf_exempt to my view. Afterwards, error 500 (Internal Server Error) occurred.
I've tried different like following the docuement to add extra code and imported it to the template. I'm struggling to fix these two problem. One's gone then the other occurs.
Also the view works fine using action attribute rather than Ajax. So I don't it's the problem of the view I reckon.
detail.html:
<script>
$(document).ready(function () {
$("#add").click(function (event) {
event.preventDefault();
$.ajax({
url: '{% url "cart:add_to_cart" %}',
type: "POST",
dataType: 'json',
success: function (response_data) {
alert('second alert');
$("#cartButton").text("Cart" + "(" + response_data.quantity + ")");
},
});
});
});
</script>
<form method="post">
{% csrf_token %}
<select name="quantity">
<option>1</option>
<option>2</option>
<option>3</option>
</select>
<input name="bookID" value=" {{ book.id }} " hidden>
<button id="add" type="submit"> Add to Cart</button>
</form>
Once I added #csrf_exempt, error 500 came out.
cart/views.py:
#csrf_exempt
def add_books(request):
print('submitted')
c = Cart.objects.get(user=request.user)
if request.method == 'POST':
q = request.POST.get('quantity', )
book_id = request.POST.get('bookID', )
the_id = int(book_id)
the_quantity = int(q)
b = Book.objects.get(id=the_id)
c = Cart.objects.get(user=request.user)
title = b.title
book = BooksInCart.objects.filter(cart=c).filter(book__title=title)
if book:
book_in_cart = book.get(book__title=title)
book_in_cart.quantity += the_quantity
book_in_cart.save()
else:
book_in_cart = BooksInCart.objects.create(cart=c, book=b, quantity=the_quantity)
book_in_cart.save()
response_data = {
'quantity': BooksInCart.objects.filter(cart=c).aggregate(item_quantity=Sum('quantity'))['item_quantity']
}
return JsonResponse(response_data)
part of the error info:
"ValueError at /cart/add_books/↵invalid literal for int() with base 10: ''↵↵Request Method: POST↵Request URL: http://127.0.0.1:8000/cart/add_books/↵Django Version: 2.1
q = request.POST.get('quantity', ) # <--- this or
book_id = request.POST.get('bookID', ) # <---- this is coming back as an empty string
# The below code is causing an error because the above code isn't finding anything
# And it is returning to you an empty string, which it cannot convert to an int()
the_id = int(book_id)
the_quantity = int(q)
You need to make sure that there is a value coming back in your POST request otherwise, you'll continue to have the problem of the empty string. If you are requiring that value, you could require that value before the user can POST the form or you could throw an error in the validation on the server.

Star Rating Bootstrap Data Input to Flask

After much help and many attempts at getting this functional I have now done so. The code below should be sufficient should anyone else also want to do the same.
Jinja2 Template
<div class="panel-footer">
<label for="input-2" class="control-label">My Rating:</label>
<input id="stars_{{result.id}}" name="input-2" class="rating rating-loading" data-min="0" data-max="10" data-step="0.1" data-stars="10" data-size="xs"onchange="updateStars('{{result.id}}')" >
</div>
<form action="{{url_for('delete_f', id=result.id)}}" method="post">
<input type="hidden" name="_method" value="DELETE">
<input type="submit" value="Delete" class="btn btn-danger">
</form>
</div>
JavaScript
{% for result in results %}
<script type="text/javascript">
function updateStars(id) {
var rating = document.getElementById("stars_" + id).value;
$.ajax({
url : '/rate_movie',
headers: {"Content-Type": "application/json"},
type : 'POST',
dataType: 'json',
data : JSON.stringify{'id': 'id', 'rating': rating}
});
};
</script>
{% endfor %}
Flask Backend
#app.route('/rate_movie',methods=['GET','POST'])
def rate_movie():
# Create cursor
if request.method == 'POST':
data = request.get_json(force=True)
rating = data['rating']
id = data['id']
cursor = cnx.cursor()
# Execute
#cursor.execute("UPDATE favourites SET rating=5 WHERE id =49") ## Works
cursor.execute("UPDATE favourites SET rating=%s WHERE id =%s",(rating,id))
#("INSERT INTO favourites(rating)VALUES(%s) WHERE id =%s" ,(rating,id))
# Commit to DB
cnx.commit()
#Close connection
cursor.close()
flash('Movie Rated', 'success')
return redirect(url_for('my_f'))
There are a number of problems here, but your first big issue is that you're using non-unique ids. Make your Ids unique and you can properly reference the value of your hidden input, fix your jQuery listener to look like $('#actually_uniqe_id').on('change', function (){...} instead of the mess it is currently, you can get your value correctly with var rating = document.getElementById("#actually_unique_id").value; and modify your posted data to convey both the id and rating like data: {'id': {{result.id}}, 'rating': rating}.
Never use non-unique IDs. Because of confusion surrounding this point, your current jQuery event listener is meaningless, and your rate_id variable is undefined because document.getElementById("{{result.id}}") fetches the first reference of that id, which is a div that has no attribute 'value'.
Edit: Also, since you have a loop generating potentially lots of rating inputs, drop the event listener for something like:
<input id="value_{{result.id}}" type="hidden" onchange="updateStars('{{result.id}}')" />
and
<script type="text/javascript">
function updateStars(id) {
var rating = document.getElementById("value_" + id).value;
$.ajax({
url : '/dashboard',
type : 'POST',
data : {'id': '{{result.id}}', 'rating': rating}
});
</script>

Categories