Django template data update using ajax - django

I am trying to update my data periodically (10 seconds) on a Django template using ajax scripts. I am relatively new in front-end development.
Using other articles, I am able to do so. But everytime page refreshes, multiple threads for page refreshing are created and update requests are doubled every 10 secods.
Following is my django template snippet:
<body id="page-top">
<div class="table-responsive">
<table class="table table-striped">
<thead>
<tr class="table-info">
<th style="text-align:center">Parameter</th>
<th style="text-align:center">A</th>
<th style="text-align:center">B</th>
</tr>
</thead>
<tbody>
{% for para, details in manualData.items %}
<tr>
<th style="text-align:center" scope="row">{{ details.1.name }}</th>
{% for key, entity in details.items %}
<td style="text-align:center">
<font color="white" size="4px">{{ entity.value }}</font>
</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
</div>
</body>
I am using ajax script as follows:
<script type="text/javascript">
function refresh() {
var_ref = $.ajax({
success: function (data) {
$('#page-top').html(data);
}
});
}
$(function () {
setInterval('refresh()', 10000);
});
</script>
Conclusively, all I need is:
once the refreshing process is called, new process should not be
created, or else past process to be aborted if new process is to be
defined.
Kindly help me to attain the same.
Thanks in advance
Nakul

You need your ajax call to be synchronomous instead of async, this way you will block the thread until you get the data you require
Can be done by adding the corresponding attribute on the ajax call
When within the industry you would normally use the template system to load something like react, angular or vue which constantly update the DOM without having to make endless polling

Thanks to the answer at post: Refresh page periodically using jquery, ajax and django.
Also, Thank you #Mr-Programs for your suggestion regarding async attribute.
I have got a suitable answer for my query and updated the javascript as follows.
<script>
function worker(){
var url = 'yoururl';
$.ajax({
type:'get',
url: url,
async: false,
success: function(data) {
var dtr = $('.page-top',data);
# not necessarily body div, can use any section required to be updated
$('.page-top').html(dtr);
complete: function() {
setTimeout(worker, 10000);
}
});
}
$(document).ready(function(){
setTimeout(worker, 10000);
});
};
</script>

Related

Django: how to refresh html content on new database entry

I am developing a MQTT Dashboard app with django. I have a mqtt thread running in background, periodically polling for data from remote device and saving it as a database (MariaDB) row. I also have a view that displays this row in simple table. Now, what I want to do is to refresh this view (without page reload) when new data appears and my question is how to do that. I thought of two different approaches:
Use JS's setInterval triggering ajax call to periodically refresh content. Problem here is that I'm not really proficient with JavaScript nor jQuery so I would love to get simple example how to do that
Somehow refresh data from within on_message function which is called when mqtt gets new data. Problem here is that I have no clue if it is even possible
I would appreciate any explanation of above or even more some description of different, more proper way to do that. Here is my code:
part of template with content i want to refresh:
<div class="row mb-4 justify-content-center text-center">
<h1 class="text-uppercase text-white font-weight-bold">{% translate "Parameters" %}</h1>
<table id="device-parameters-table">
<thead>
<tr>
<th scope="col">{% translate "Parameter" %}</th>
<th scope="col">{% translate "Value" %}</th>
<th scope="col">{% translate "Unit" %}</th>
</tr>
</thead>
<tbody>
{% for key, value in latest_read_data.items %}
<tr>
<td>{{key}}</td>
<td>{{value.value}}</td>
<td>{{value.unit}}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
device view:
def device(request):
clicked = request.GET.get('device_id')
dev = Device.objects.get(id=clicked)
latest_read_data = ReadData.objects.filter(device=dev).order_by('timestamp')
if latest_read_data:
read_data = latest_read_data.values()
read_data = read_data[len(read_data)-1]
read_data.pop('id')
read_data.pop('device_id')
read_data.pop('timestamp')
parameters_get_units(read_data)
context = {'latest_read_data': read_data, 'device': dev}
return render(request, 'dashboard/device.html', context=context)
else:
return HttpResponseRedirect('/dashboard')

How to get table row values in a javascript function from a dynamically created table using for loop in django?

So basically, I am passing a context from views to my template.
In my template I am using 'for loop' to view the context in a tabular form and also attaching a button for every table row.
When that button is clicked, I want to call a javascript function(that has ajax call).
I need to get values of row elements for that particular row to use in my function.
My view function:
def asset_delivery(request):
deliverylist = Delivery.objects.filter(status='Added to Delivery List')
context = {'deliverylist': deliverylist}
return render(request, 'gecia_ass_del.html', context)
So far I tried passing those values as parameters in the following way.
My html template table:
<table class="table">
<thead style="background-color:DodgerBlue;color:White;">
<tr>
<th scope="col">Barcode</th>
<th scope="col">Owner</th>
<th scope="col">Mobile</th>
<th scope="col">Address</th>
<th scope="col">Asset Type</th>
<th scope="col">Approve Asset Request</th>
</tr>
</thead>
<tbody>
{% for i in deliverylist %}
<tr>
<td id="barcode">{{i.barcode}}</td>
<td id="owner">{{i.owner}}</td>
<td id="mobile">{{i.mobile}}</td>
<td id="address">{{i.address}}</td>
<td id="atype">{{i.atype}}</td>
<td><button id="approvebutton" onclick="approve({{i.barcode}},{{i.owner}},{{i.mobile}},{{i.address}},{{i.atype}})" style="background-color:#288233; color:white;" class="btn btn-indigo btn-sm m-0">Approve Request</button></td>
</tr>
{% endfor %}
</tbody>
</table>
The table is displayed perfectly but the button or the onclick or the function call does not seem to work.
My javascript function:
<script>
function approve(barcode2, owner2, mobile2, address2, atype2){
console.log('entered approved');
var today = new Date().getFullYear()+'-'+("0"+(new Date().getMonth()+1)).slice(-2)+'-'+("0"+new Date().getDate()).slice(-2);
$.ajax({
type:'POST',
url: 'deliveryupdate/'+barcode+'/',
dataType: 'json',
data:{
barcode: barcode2,
owner: owner2,
mobile: mobile2,
address: address2,
atype: atype2,
status:'Authority Approved',
statusdate: today,
csrfmiddlewaretoken:$('input[name=csrfmiddlewaretoken]').val()
},
beforeSend: function() {
console.log('before send');
},
success: function(){
console.log("success log");
swal("Success!","Asset request has been approved","success");
},
error: function(){
console.log("error");
}
});
}
</script>
I checked the browser logs and it looks like the function is not getting executed, meaning the problem lies with the function call or the button. Please help.
The code is working on my end. I have reduced the function to:
function approve(){console.log('entered approved');}
without any parameters and 'entered approved' is logged to the console. Check if you are setting the correct parameters and if the console throws an error. Simplify your function and add the parameters one by one in order to troubleshoot this.

Issues with csfr token and ajax call

I tried to implement a button on a Website, which upon pressing it automatically runs a python function on the server and copies some value into the clipboard of the user. The clipboard copying runs fine, but I can not run the python function.
Whenever I try to I get an error 403 and I think it is due to an issue with the csfr token. Can anyone help me to solve this issue?
Here is my HTML
{% if categories %}
<div class="card shadow mb-4">
<div class="card-body card-interface">
<table id="predictionTable" class="table table-bordered">
<thead>
<tr>
<th>Vorhersage</th>
<th>Wahrscheinlichkeit</th>
<th>Kopieren</th>
</tr>
</thead>
<tbody>
{% for category in categories %}
<tr>
<td>{{ category.0}}</td>
<td>{{ category.1}}%</td>
<td><img src="{% static "documents/img/copy.png" %}" class="interface-copy" value="{{ category.0 }}" input_text = "{{ input_text }}" style="cursor: pointer"></td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<div id="django-data" data-CSRF="{{csrf_token}}"></div>
And here the .js that is run
$(".interface-copy").on('click', function(e) {
var csrftoken = $("django-data").data().CSRF;
console.log(csrftoken);
console.log("test")
var $temp = $("<input>");
$("body").append($temp);
$temp.val($(this).attr('value')).select();
document.execCommand("copy");
$temp.remove();
console.log("test")
$.ajax({
url: "/ajax/postSingleSourceEntry/",
type : 'POST',
beforeSend: function(request){
request.setRequestHeader("X-CSRFToken", csrftoken);
},
data: {
csfrmiddlewaretoken: csrftoken
},
dataType: "json",
success: function (data){
console.log("call created")
},
error : function(response){
console.log(response)
}
})
});
Change:
<div id="django-data" data-CSRF="{{csrf_token}}"></div>
To:
<div id="django-data" data-csrf="{{csrf_token}}"></div>
And:
var csrftoken = $("django-data").data().CSRF;
To:
var csrftoken = $("#django-data").data().csrf; // Note the # before django-data and csrf in small letter.
You might want to read: How to get the data-id attribute?
You can add #csrf_exempt decorator for that ajax function

executing python script in django with arguments from the frontend

I want to manipulate the values associated with the entries of an external mongodb database using a django webapp.
I've created the app and I'm currently displaying all the entries and their associated value in a simple table.
My idea is simply to create a button, that calls a python script with an argument (the id of that entry) and then changes it from false to true. The problem is, this seems like rocket-science, I've been at this for days now and I just can't get it to work as I have little to no proficiency when it comes to Ajax or Jquery, and all relevant examples I can find don't simply seem to pertain very well to my situation despite how basic it would appear, nor fit with Django 2.0+.
I'm using Django 2.1.5
def change_value(idnumber):
db_value = get_db_status_value(idnumber)
if db_value is True:
change_db_entry_status(idnumber, False)
else:
change_db_entry_status(idnumber, True)
my_template.html
<table>
<thead>
<tr>
<th> Status </th>
<th> Button </th>
</tr>
</thead>
<tbody>
{ % for entry in entry_data % }
<tr>
<td> {{ entry.status }} </td>
<td> <button type="button">{{ entry.idnumber }}</button> </td>
</tr>
</tbody>
{% endfor %}
</table>
I simply can't figure out how I can get the change_value function in there that I can create a button for and include an argument ( entry.idnumber ). This seems incredibly difficult, which from what I understand is a design principle, but it seems a shame if I can't even accomplish something as basic as above.
I was hoping someone could explain how I'm actually supposed to go about this? So far, it seems I require AJAX or Jquery (unfortunately, I barely know the basics of this, and what usually trips me up is that the urls.py which exist in both project and application level seems to work a little different in django 2.0+ compared to older versions)
This isn't actually difficult. It's just that you're missing an understanding of the relationship between the client and the backend code.
Once the template is rendered, the user sees it as HTML in their browser. That's it as far as the backend (ie Django) is concerned. The only way to run any further code on the server is to send another request. A request involves the browser contacting the server, which requires a URL and a view in Django.
Now, one way to send that request is via Ajax, but for your purposes that isn't necessary; since you're just learning, it's easier if you make it a simple form. So, your template might look something like this:
{% for entry in entry_data % }
<tr>
<td> {{ entry.status }} </td>
<td><form action="{% url 'change_value' idnumber=entry.idnumber %}" method="POST"> {% csrf_token %} <button type="submit">{{ entry.idnumber }}</button> </form></td>
</tr>
{% endfor %}
</tbody>
Notice how every iteration of the for loop has a separate form, which posts to a specific URL including the ID number.
Next you need a URL:
path('change_value/<int:idnumber>/', views.change_value, name='change_value'),
and update your function to actually be a view, which needs to accept a request and return a response:
def change_value(request, idnumber):
if request.method != "POST":
return HttpResponseNotAllowed()
db_value = get_db_status_value(idnumber)
if db_value:
change_db_entry_status(idnumber, False)
else:
change_db_entry_status(idnumber, True)
return redirect('/')
You always need to redirect after a POST, but you could redirect back to the same URL that rendered my_template in the first place. (Also note I've put in a test to make sure the user is actually sending a POST; you don't want Google to crawl this URL and flip your values for you.)
And that's it, now you have a button that should toggle your value.
The answer from #Daniel is enough for you. But if you want to use ajax so that the page does not have to refresh to change the vaue, you may do something like:
In your template make changes as:
<table>
<thead>
<tr>
<th> Status </th>
<th> Button </th>
</tr>
</thead>
<tbody>
{ % for entry in entry_data % }
<tr>
<td id="status"> {{ entry.status }} </td>
<td> <button type="button" onclick="change_status(this)" id="{{ entry.idnumber }}">{{ entry.idnumber }}</button> </td>
</tr>
</tbody>
{% endfor %}
and a script as:
<script>
function change_status($this){
var request_data = $this.id;
console.log("data: " + request_data);
$.post({
url: "url that leads to your view",
data : { request_data: request_data},
success : function(json) {
document.getElementById('status').innerHTML = "" //insert the data returned from the function
}
})}
</script>

handling ajax and jquery in django template

I am trying to load page in two parts.
second part is only render when user click on 'show more details'
<script>
$(document).ready(function(){
$('#toggle_details').click(function(e){
e.preventDefault();
if ($(this).hasClass('up')){
$(this).removeClass('up').addClass('down');
$('#toggle_text').html('Show More Details');
}
else {
$(this).removeClass('down').addClass('up');
$.ajax({
url: 'some_url_returning_json',
data: $(this).serialize(),
processData: false,
dataType: "json",
success: function(data) {
$( '.name' ).html(data.name);
$( '.lname' ).html(data.lname);
alert(data.name);
}
})
$('#toggle_text').html('Hide Details');
}
$('#details').slideToggle("slow");
return false;
});
$('#details').hide();
});
</script>
and my html is :
<div class="ad-grp-tbl creative-tbl custom-tbl">
<table width="100%">
<tr>
<th>Status:</th>
<td id='status'>{{ status }}</td>
</tr>
</table>
<table width="100%" id="details">
<tr>
<th>Name:</th>
<td id="name" >{{data.name}}</td>
</tr>
<tr>
<th>Last Name:</th>
<td id ="lname">{{ data.lname}}</td>
</tr>
</table>
<table>
<tr>
<th class="tog">
<span id="toggle_text" style="color:blue;font-weight:bold">Show More Details</span>
<span class="down" id="toggle_details"></span>
</th>
<td></td>
</tr>
</table>
</div>
So Basically I am not able to load the json return value in the template.
hw can i fix it. or my approach for solving the problem is wrong.
Thanks.
I show you an example:
def post_ajax(request):
TOTLE = 5
OFFSET = int(request.GET.get('offset', 0))
END = OFFSET + TOTLE
if OFFSET + 1 >= Post.objects.count():
LOADED = "已经全部加载完毕"
return HttpResponse(LOADED)
posts = Post.objects.filter(pub_time__lte=timezone.now())[OFFSET:END]
json_list = []
for post in posts:
t = get_template('blog/ajax_post.html')
html = t.render(Context({'post': post}))
# print(html)
json_list.append({
'html': html,
})
data = json.dumps(json_list)
return HttpResponse(data, content_type="application/json")
Is this you need?
Ajax + JQuery will get response and should put data appropriately in the page. Template of original page doesn't have much role to play.
However, you have to implement separate url+view+template that will handle the ajax request. You can use existing view but need to handle for ajax request (i.e. just to send part of html, likely using another template).
The template for ajax response should send only the relevant part of html and not the entire html page.
In the HTML you have ids set but you are using the class selector.
It should be:
$( '#name' ).html(data.name);
$( '#lname' ).html(data.lname);
instead of:
$( '.name' ).html(data.name);
$( '.lname' ).html(data.lname);
. is the class selector and # is the id selector.
You can try using Firebug or Chrome Dev Tools to see that the above returns the items.