Update Value dynamically using repeated Ajax calls from DJango template - python

I wanted to show my sound sensor readings from a django site (original code as posted in the link). Now as per the situation 2 of the accepted answer, I wanted to make a Javascript function which repeatedly calls the ajax_data function from views template.
But it seems that no repeated calls are being made. And no update in reading reflects either.
My django template till now:
<!doctype html>
<html>
<head>
<title>Noise measurement site</title>
<script src="http://code.jquery.com/jquery-3.0.0.js"
integrity="sha256-jrPLZ+8vDxt2FnE1zvZXCkCcebI/C8Dt5xyaQBjxQIo="
crossorigin="anonymous"></script>
<script language="javascript" type="text/javascript">
function updateValue() {
$.ajax({
url:"D:/Python programs/django_projects/Noise_Measurement/noise_m/views.py/ajax_data/",
//success: updateValue(), for experimenting with a recursive call...
});
}
$(document).ready(function(){
var v = setInterval(updateValue,2000);
});
</script>
</head>
<body>
<p>Hello there</p>
<p>Present noise level : {{noise_level}} dB</p>
</body>
</html>
(I have mentioned rest of the code in my previously asked question. I have read some of the answers on the platform but I'm not getting much results.)
Update
Sorry I made a mistake. I made slight changes in the code and posted output without that only. Now I have made the exact changes as in the previous part. But output is not sorted out yet. (Thanks to comment by CumminUp07)

** Own answer on own question **
Oh sorry, actually it was a misunderstanding of the syntax from my side.
I was first supposed to create method in views.py, which will send the reading from the module taking it. Then for that method, I had to assign an url using path(), in a fashion like:
path('read', views.data_update1, name='readings'),
Then the ajax request was supposed to be made to read link:
$.ajax({
url: "read",
dataType: "json",
contentType: "application/json",
success: function(r) { ... }
});
Then this method is conveniently called using setInterval method.
But finally at the line, the {{ }} didn't help, so the div where the value was to be displayed was assigned an id, whose value was updated on each call of the method.

Related

Only upload file names and metadata

Is it possible to have a upload box on a site where a user can drag in a folder of files but instead of the entire folder being uploaded you can just grab the file names and metadata?
Not complete, but probably a good start...
This would be possible with dropzone.js, by setting the autoProcessQueue option to false. Then you can drop files/folders via the GUI, without them actually uploading, but still access the file object in javascript to get the metadata.
See this answer for more information on how to add a manual button to eventually start processing this queue if you wish. Regardless of whether you process that queue or not, you can use the addedfile event to manually inspect the file objects.
A really basic example, with the scripts loaded from a CDN, would look like:
<html>
<head>
<title> Dropzone</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.5.0/dropzone.css" integrity="sha256-0Z6mOrdLEtgqvj7tidYQnCYWG3G2GAIpatAWKhDx+VM=" crossorigin="anonymous" />
</head>
<body>
<div>
<form method='POST'
enctype="multipart/form-data"
class="dropzone"
id="my-awesome-dropzone"></form>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.5.0/dropzone.js" integrity="sha256-NLit4Z57jz8npRHkopjfr68hSZY1x/ruN0T8kf68xq4=" crossorigin="anonymous"></script>
<script type='text/javascript'>
Dropzone.autoDiscover = false;
var myDropzone = new Dropzone("form#my-awesome-dropzone",
{ url: "/upload",
autoProcessQueue: false,
});
myDropzone.on("addedfile", function(file) {
// runs for every file dropped
console.log(file.name, file.fullPath, file.lastModified, file.size);
});
</script>
</body>
</html>
Dropping a single file with the above code outputs something like:
views.py undefined 1567770276854 1604
You can drop an entire folder, and every file recursively will appear, including file.fullPath for each:
models.py stack/models.py 1566159281216 1974
serializers.py stack/serializers.py 1565978398499 309
...
You could instead console.log(file) to inspect that object further (in your browser's dev tools console) to see the other available metadata.
To get this data to the backend you could use the fetch API or a similar AJAX post function. You may wish to add all the info to an array, then post this to the backend at once using another event handler tied to an "Upload metadata!" button.

KO: Error when parsing JSON

Created a JSBin that demostrated the problem: http://jsbin.com/kukehoj/1/edit?html,js,console,output
I'm creating my first REST-powered website. The backend is in Python (Django REST Framework), and seems to be working fine. I'm trying to make the front-end get the comments for the posts, but its not working.
HTML Imports
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.1/knockout-min.js"></script>
scripts.js
function Comment(data) {
this.body = ko.observable(data.responseText)
}
function Post(data) {
this.title = ko.observable(data.title)
this.body = ko.observable(data.body)
var self = this;
self.comments = ko.observableArray([])
self.comments(($.map(data.comments, function(link) { // Map the data from
return $.getJSON(link, function(data) { return new Comment(data)}) //These requests
})))
}
function PostViewModel() {
// Data
var self = this;
self.posts = ko.observableArray([])
// Get the posts and map them to a mappedData array.
$.getJSON("/router/post/?format=json", function(allData) {
var mappedData = $.map(allData, function(data) { return new Post(data)})
self.posts(mappedData)
})
}
ko.applyBindings(new PostViewModel());
Server data:
[{ "title":"-->Title here<--",
"body":"-->Body here<--",
"comments":[
"http://127.0.0.1:8000/router/comment/6/?format=json",
"http://127.0.0.1:8000/router/comment/7/?format=json",
"http://127.0.0.1:8000/router/comment/8/?format=json",
"http://127.0.0.1:8000/router/comment/9/?format=json"]
}]
where each of the links leeds to:
{"body":"-->Body here<--"}
index.html
<div class="col-lg-7" data-bind="foreach: { data: posts, as: 'posts' }">
<h3 data-bind="text: title"></h3>
<p data-bind="text: body"> </p>
<span data-bind="foreach: { data: comments(), as: 'comments' }">
<p data-bind="text: comments.body"></p>
</span>
</div>
(There is a lot more HTML, but i removed the irrelevant parts)
Everything is working fine, except from that the comments seem to be in the wrong format.
The chrome console shows JSON "responseText" bound to each of the comment object values.
Wrong format
I'm sorry if this is a stupid question, but I have tried everything - but it doesn't work. (I'm a noob)
There is nothing wrong with your sample code you provided except the part you have this.body = ko.observable(data.responseText) while your data does not contain a responseText in your sample commentData object . if you replace commentData object with var commentData = {"responseText":"-->Body here<--"} it works.
Note: this part
<span data-bind="foreach: { data: comments(), as: 'comments' }">
<p data-bind="text: comments.body"></p> // comments.body => body
</span>
on your question is wrong but you have it correct on your sample code .It should be
<span data-bind="foreach: { data: comments(), as: 'comments' }">
<p data-bind="text: body"></p>
</span>
Here is a working version of your sample :https://jsfiddle.net/rnhkv840/26/
I assume you are using Django Rest Framework, so the JSON structure you get for your posts is done automatically by your serializer based on your model fields.
Back to the frontend, I have not used knockout js before, but what you require is to load the comments using another controller. Either you do it one by one using the links provided by your main resource (this can result in lots of queries sometimes), or you create a filter on your comments endpoint which will allow you to retrieve comments for a specific post.
Ever considered using the django REST framework? It can help you serialize all you models with a simple viewset. Check out the docs.
So found the actual problem. The way the JavaScript read the data from the server, ment that since there was only one value for the comments, the data property of a comment was the variable storing the body of the comment. Not the data.body.

Embedding Python Game Into HTML Using Skulpt

I have written a game in Python using the PyGame library that I am trying to embed into an HTML page to allow me to play in a web browser.
I am attempting to do this using the JavaScript library Skulpt. I have attached a test script below that successfully outputs the print statement below.
skulpt.html
<html>
<head>
<script src="assets/skulpt/skulpt.js" type="text/javascript"></script>
</head>
<body>
<textarea id="pythonCode">
print "I am python."
</textarea><br />
<pre id="output"></pre>
<script type="text/javascript">
function outf(text) {
var mypre = document.getElementById("output");
mypre.innerHTML = mypre.innerHTML + text;
}
var code = document.getElementById("pythonCode").value;
Sk.configure({output:outf});
eval(Sk.importMainWithBody("<stdin>",false,code));
</script>
</body>
</html>
Output of skulpt.html:
The issue that I am having is that when I use my game code instead of the simple print statement shown above it produces the error seen below;
I have included all relevant images to my web servers' directory at the correct path. I am unsure of why this error is being produced. Any help would be much appreciated, thanks!
Also, here is the attached Python game code (and a live demo of the error):
http://nicolasward.com/portfolio/skulpt.html
You have a lot of indentation on line 1 -> remember, in python, indentation always matters. Take away all those spaces/tabs on the first line and it should run.

Dynamically update image using Python Flask AJAX

I have 1 very simple web application I am building right now but am very new to flask and jinja (and web development as a whole actually).
I have a watch folder, which will be getting an image sent to it via ftp on a pulse for ever. This wtch folder will only ever have one image in. Every 1 minute, the old image is replaced by a new image, with a new timestamp.
I would like to dynamically update the page, (and displayed timestamp) on a pulse as well, without having to reload any banners or static images that I will add later. I only want to update the following two lines out of the "Channels.Jinja" sample to follow.
<br>{{screenshot_datetime}}<br/>
<img src={{screenshot_location}} width="100%"/>
Channels.Jinja
<!DOCTYPE HTML>
<html>
<head>
<title>Training</title>
</head>
<body bgcolor=white>
<div id=main>
<br>Date and Time of Screenshot <br/>
<br>{{screenshot_datetime}}<br/>
<img src={{screenshot_location}} width="100%"/>
</div>
<div id='test'>
<p>
<script>
var myVar=setInterval(function(){get_image()},1000);
function get_image() {
$.ajax({
type: 'GET',
cache: false,
url: 'get_data',
success: function({{data}}) {
$('img').attr('src', data);
}
});
}
</script>
</p>
</div>
</body>
</html>
Channels.py
def render_channel_route(cr):
static_folder = os.path.join('static',cr)
file_list = os.listdir(static_folder)
channel_files = [f for f in file_list if f.startswith(cr)]
if not channel_files :
logger.error('Could not find image file for Channel. File should start with {0}'.format(cr))
abort(404)
img = os.path.join(static_folder,file_list[0])
ts = get_time_from_filename(file_list[0],cr)
return render_template('Channels.jinja',screenshot_datetime=time.strftime('%c',ts),screenshot_location=img)
#app.route('/channel01-10')
def first_tab():
return render_channel_route('channel01-10')
#app.route('/get_data', methods=['GET'])
def get_data():
return render_template('Channels.jinja',
screenshot_datetime=time.strftime('%c',ts),screenshot_location=img)
Im at a loss, Ive been bumbling around for a while now. Any and all advice is welcome! I am seeing a 304 response upon refresh, but not even the timer i am trying to put on it is working. Pardon sloppy code, highly volatile code is getting changed often -_-
I don't know it there is a "special" way to deal with Ajax using some Flask extension, but in the "normal" Ajax flow first you need to use url_for to put the correct url in your Ajax call and return the data formatted in some way (in my example in JSON) and not to render the template again:
$.ajax({
type: 'GET',
cache: false,
url: "{{ url_for('get_data') }}",
success: function(resp){
$('img').attr('src', resp.url);
$('#sst').html(resp.time);
}
});
So, in your get_data function in your controller you have to get the time and the path again for your image an then return some like this (to fit in my example before):
from flask import json
#app.route('/get_data', methods=['GET'])
def get_data():
#get time and path
time=...
path=...
return json.dumps({time:time,url:path}), 200, {'Content-Type':'application/json'}
Look that I use $('#sst') so you have to put in your HTML:
<br><span id='sst'>{{screenshot_datetime}}</span><br/>

Display multiple mpld3 exports on a single HTML page

I've found the mpld3 package to be brilliant for exporting a matplolib plot to HTML and displaying this via a flask app.
Each export comes with a lot of JS which seems unnecessary duplication if you want to display multiple plots within a single page. However I'm not well enough versed in JS to extract the relevant components and then loop through them. The .fig_to_dict method gives the necessary JSON to display each chart but then I'm left wondering what JS/ template work is needed to display each chart in turn.
I considered just stacking each plot into a single big figure but I'd like to layout the charts in separate DIVs and so this isn't the right solution.
I think I can see what the JS is doing to display them but I don't have enough knowledge to modify the functions to suit the purpose.
I haven't included code as I'm expecting this only to be relevant to someone with mpld3 experience but can supply some sample code if needed.
Sample HTML output for mpld3.fig_to_html(fig, template_type="simple"):
<script type="text/javascript" src="http://d3js.org/d3.v3.min.js"></script>
<script type="text/javascript" src="http://mpld3.github.io/js/mpld3.v0.1.js"></script>
<style>
</style>
<div id="fig136845463888164451663379"></div>
<script type="text/javascript">
var spec136845463888164451663379 = { <snip JSON code> };
var fig136845463888164451663379 = mpld3.draw_figure("fig136845463888164451663379", spec136845463888164451663379);
</script>
I'd thought it would be as simple as linking the two core scripts from the template header and then creating a new script for each JSON export. But that hasn't worked for me.
You're half-way there with your answer. I think what you want to do is something like this, which will embed three figures on the page:
<script type="text/javascript" src="http://d3js.org/d3.v3.min.js"></script>
<script type="text/javascript" src="http://mpld3.github.io/js/mpld3.v0.1.js"></script>
<style>
</style>
<div id="fig01"></div>
<div id="fig02"></div>
<div id="fig03"></div>
<script type="text/javascript">
var json01 = { <snip JSON code> };
var json02 = { <snip JSON code> };
var json03 = { <snip JSON code> };
mpld3.draw_figure("fig01", json01);
mpld3.draw_figure("fig02", json02);
mpld3.draw_figure("fig03", json03);
</script>
The json code for each figure can be created in Python by running
import json
# ... create matplotlib figure
json01 = json.dumps(mpld3.fig_to_dict(fig))
Embed this string at the appropriate place in the HTML document you're creating, and you should be good to go. I hope that helps!
Note that since jakevdp's answer was posted mpld3 has had a new release. As of today (September 2014) the mpld3 include has to be:
<script type="text/javascript" src="http://mpld3.github.io/js/mpld3.v0.2.js"></script>

Categories