FOR loop over a Django model in a JS script - javascript

I just started a web app using Django and HTML/Javascript templates.
My Django spot app contains a Spot model that is sent to a HTML template - to be used with the Google Map Api. I've encountered a problem when looping over the variable spots containing Spot.objects.all().
It seems the problem comes from the way I send the data to the HMTL file.
----------------------------------------- Spot Django-app : models.py --------------------------------------------
class Spot(models.Model):
idn = models.IntegerField(unique = True)
name = models.CharField(max_length = 200)
longitude = models.FloatField()
latitude = models.FloatField()
------------------------------------------------- HTML / JS -----------------------------------------------
<script type="text/javascript">
var IDs = []
var names = []
var lat = []
var lng = []
{ % for spot in spots % }
IDS.push( {{spot.idn}} );
names.push( {{spot.name}} );
lat.push( {{spot.latitude}} );
lng.push( {{spot.longitude}} );
{ % endfor % }
Then, the lists do not contain any data that can be used afterwards. Worse, the HTML file does not work if the names.push( {{spot.name}} ) is un-commented.
----------------------------------------- Spot Django-app : views.py --------------------------------------------
from spots.models import Spot
def index(request):
return render(request, 'index.html', {'spots':Spot.objects.all()})
Thanks to the other stackoverflow questions (listed below), I also tried to serialize the Spot.objects.all() either with django.core.serializers.serialize("json", Spot.objects.all() ) or by creating my own serializer (thanks to Django_REST). The problem remains the same. So is the problem in the way I parse my data with JS?
I've look the following link :
Returning JSON array from a Django view to a template
django for loop in a .html template page (newbie)
Django FOR LOOP in JavaScript
with no success. So if the answer is included or related to these topics, would you mind explaining me something I've been working around for days ...
EDIT:
The problem was plural:
Serializing the data (or not ; I did not for now but everyone who answered agreed to say that it's better to)
Adding the quotes from {{ spot.name }} to '{{ spot.name }}', only to non Integer/Float models (i.e. only the models.CharFields fields)
Google Maps Api may return errors for some (longitude, latitude) tuples even if they are well-defined

Django will not recognize those template tags because you have spaces between the brace and the percent. So, there is no looping being done at all. You need to write them in the correct format:
{% for spot in spots %}
...
{% endfor %}
Once you do that, you'll start getting all sorts of JS syntax errors because you have not wrapped any of your data in quotes. But, as the comments say, doing this as JSON would be much better.

Even that I think that serializing your data into Json is much better idea. Your javascript code does not work because e.g. {{ spot.name }} will render raw string so for javascript to understand it you need to put it in quotes (and of course semicolon after each line).
names.push('{{spot.name}}');

Related

How to import data from django.models, to use in javascript?

I am trying to import a python dictionary from moodels and manipulate/print it's properties in Javascript. However nothing seems to print out and I don't receive any error warnings.
Views.py
from chesssite.models import Chess_board
import json
def chess(request):
board = Chess_board()
data = json.dumps(board.rep)
return render(request, 'home.html', {'board': data})
Here board.rep is a python dictionary {"0a":0, "0b":0, "0c":"K0"} - basically a chess board
home.html
<html>
<body>
{% block content %}
<script>
for (x in {{board}}) {
document.write(x)
}
</script>
{% endblock %}
</body>
</html>
I also would very much appreciate some debugging tips!
Thanks in advance, Alex
Django defaults to escaping things as HTML, and that will make " into #quot;. Try changing {{board}} into {{board|safe}} to prevent the html escaping. Alternatively, in the view you can wrap the string in mark_safe() which is in django.utils.safestring to indicate that the string shouldn't be escaped.
To transfer data between django and javascript, dump data in django view and load in a javascript variable. Try to avoid django interpolation with javascript language constructs. It is unsafe, error prone, and can cause complexities.
in view
data = json.dumps(board.rep)
in template
const data = JSON.parse('{{ data|safe }}')
// use normal javascript here. 'data' is a javascript array
for (let x of data) {
document.write(x)
}

set twig variable from json array

As twig renders prior to any javascript, I'm running into what feels like a minor problem.
I need to set a variable in twig that I receive from JSON array, but I'm running into some problems, and I feel like this should be simple.
The data is fed to twig through symfony through a json array, and renders different messages depending on one element in the array; this part works without trouble.
I am able to print the output to the twig file; that works fine. The problem is that I'm having a hard time setting this to a twig variable so that I can use it in a few places.
This works fine:
$('.id').html(items[0].id);
and prints out to the twig here correctly:
<div class="id"></div>
I tried to do do something like this:
{% set requestid = '<div class="id"></div>' %}
{{ requestid }}
But as expected this simply rendered the HTML without the value.
I've been attempting to do something like this:
In the twig I have this:
{% set requestid = "request_holder" %}
{{ requestid }}
And in the jquery I have something like this:
var reqid = items[0].id;
reqid.replace("request_holder",reqid);
I also attempted something like this
var request_id = items[0].id;
window.location = request_id.replace("request_holder",request_id)
I feel like I'm missing a small piece.
**Edit for clarity **
The JSON array is being parsed by jquery.
I have the value of items[0].id
Additional edit here - to make it clear that I was confused: cleaning up a little so as not to send future readers down the wrong path
I believe[d] that the variable needs to be assigned in the javascript because the twig, which is php, is generated prior to the javascript.
I have been attempting to generate the twig in the javascript to no avail.
Here's what I have been attempting:
var requestitem = items[0].id;
$('.id').html("{% set requestId = " + requestitem + " %} <br/> {{ requestId }}");
This defines requestId as a string and is only returning + requestitem + onto the page.
When I attempt this (without the quotations)
var requestitem = items[0].id;
$('.id').html("{% set requestId = requestitem %} <br/> {{ requestId }}");
The twig does not recognize requestitem at all
I have attempted quoting out the twig brackets (e.g. "{" + "%" etc) but this of course only prints them onto the page and does not interpret them.
Twig processes on the server side. It takes variables and renders them as HTML and text. What gets displayed in the browser is just HTML / text / and Javascript. So your set requestid = "request_holder" and {{ requestid}} are just turned to text before they get to the browser.
After that, you have HTML and text on the front end which Javascript can interact with. If you need this id to change on the front end, it needs to be done in Javascript.
What are you using the id to do?
Thanks to the hint from ASOlivieri, I was able to realize what I was doing wrong. I'm putting this here in case anyone comes across this. I was simply looking for a way to create a variable and make it reusable (I didn't go into details as that seemed extraneous).
The data was only available in the JSON array, so any attempt to write it to a twig file would fail, quite simply because it had already been converted to HTML, so I was forced to find another solution,
I was able to keep the variable in a javascript as I had it before
var request_item = items[0].id;
As my original goal was to get the value to update the application through php, I simply needed to use this variable in an AJAX call, and pass it through the path I had wanted to use in twig. Here's a brief summary:
$('#mark-received').click(function()
{
var requestURL = "{{ path('my_path') }}";
jQuery.ajax({
url: requestURL,
type: 'GET',
data: {'id' : request_item},
success: function success(data, text, xhr){
$('#mark-received').addClass('hidden');
$('#received-canceled').removeClass('hidden');
$('header > .alerts').append( $('<div>Success Message</div>').addClass('alert alert-success'));
},
error: function error( xhr, status, err){
$('header > .alerts').append( $('<div>There is a problem. <div class="close">x</div></div>', err).addClass('alert alert-danger'));
}
})
});

How to pass data from python to javascript in web2py

I see some relevant posts to my query.
Tornado is used in the below link
How to pass variable from python to javascript
I know that it can be done using json but I am not clear how to implement it.
In the web2py default controller I am returning a dictionary which contains the latitudes and longitudes.
def index():
lat_long_list=[]
info1 = {'lat':'1.0032','long':'2.00003','name':'Akash'}
info2 = {'lat':'1.2312','long':'-1.0034','name':'Kalyan'}
lat_long_list.append(info1)
lat_long_list.append(info2)
return dict(lat_long_list=lat_long_list)
In java script I want to iterate through the list of dictionaries and mark the points on the google maps.
I cannot say
<script>
{{ for lat_long_rec in lat_long_list :}}
var name = {{=lat_long_rec['name']}}
{{ pass }}
</script>
This fails. An alternative to handle this is to write the list into an xml and from javascript read the file but I dont want to achieve it this way as writing to file is non performant. Let me know how best this can achieved.
Convert the Python list to JSON and pass that to the view to insert in the Javascript code:
from gluon.serializers import json
return dict(lat_long_list=json(lat_long_list))
In the view:
<script>
...
var latLongList = {{=XML(lat_long_list)}}
...
</script>

Passing Google App Engine datastore models to javascript code

I know that the Jinja2 library allows me to pass datastore models from my python code to html and access this data from inside the html code as shown in this example . However Jinja2 isn't compatible with javascript and I want to access the data inside my Javascript code . What is the simplest templating library which allows to iterate over my datastore entities in Javascript ? I've heard about things like Mustache and Jquery , I think they look a bit too complicated. Is there anything simpler?
You should create a python controller which serves JSON formatted data, which any Javascript library (especially jQuery) can consume from. Then, setup the Jinja2 template to contain some Javascript which calls, loads and displays said data.
One more approach to consider: If the Python object is not dynamic, you may want to use json.dumps() to store it as a TextProperty, and simply JSON.parse(unescape(model_text)) on the JS side. Reduces the overhead, and memory hit which can be important when trying to stay within an F1 limit. For example, I run an instance that very easily runs inside an F1. There is one large dictionary object that we deliver. Were this object to exist as a Python dictionary inside the instance we would kill the instance due to the soft memory limit. Using the TextProperty approach we can pass this large dict to the client without any issues. (Note: we did have to momentarily boost our instance up to an F4 when initially creating this object -- something incredibly easy inside the Admin web page.) With more dynamic objects, answers above apply.
Jinja2 and Javascript play fine together. You need to arrange to have template expansion emit your Python data structures into a JS-friendly form.
https://sites.google.com/a/khanacademy.org/forge/technical/autoescape-in-jinja2-templates covers it fairly well. (Note the use of the escapejs filter.)
It works. I had to serialize(convert) my datastore entities to json format, which Javascript understands well. I created a function which converts every instance of my datastore into a dictionnary then encapsulates all these instances into a list which is then converted to Json using json.dumps. When I pass this result to the Java script , I can then easily access my values as seen below.
import json
import webapp2
from google.appengine.ext import db
import jinja2
JINJA_ENVIRONMENT = jinja2.Environment(
loader=jinja2.FileSystemLoader(os.path.dirname(__file__)),
extensions=['jinja2.ext.autoescape'],
autoescape=True)
# serialize datastore model to JSON format
def serialize(model):
allInstances = model.all() # fetching every instance of model
itemsList = [] #initial empty list
for p in allInstances:
d = db.to_dict(p)
itemsList.append(d)
return json.dumps(itemsList)
class myModel(db.Model):
v = db.FloatProperty()
c = db.FloatProperty()
tdate = db.DateTimeProperty(auto_now_add=True)
class MainPage(webapp2.RequestHandler):
def get(self):
myModel(v=4.5, c=3.0).put()
#creating template variables
template_values = {
'json_data': serialize(myModel)
}
template = JINJA_ENVIRONMENT.get_template('index.html')
self.response.write(template.render(template_values))
Inside my 'index.html' file, I have:
{% autoescape true %}
<!DOCTYPE html>
<html>
<head>
<title> webpage </title>
<script type="text/javascript">
// I retrieve my data here
var results = "{{ json_data }}";
for(var i = 0; i < db_results.length; i++) {
document.write("myModel instance:" + i + results[i] + "<br>");
}
</script>
</head>
<body>
</body>
</html>
{% endautoescape %}
It has nothing to do with compatibility. Jinja is server side templating. You can use javascript for client side coding.
Using Jinja you can create HTML, which can be accessed by javascript like normal HTML.
To send datastore entities to your client you can use Jinja to pass a Python list or use a json webservice.

List.pop() in Django Template without for loop

I have a list of id all_entries_user. They basically serve as a part of url for rest service that I have developed using TastyPie. Inside my Django template i want to use them by iterating all_entries_user
function ajaxCall(){
$.getJSON("http://localhost:8000/api/Location/" + {{ all_entries_user.pop }} + "/?format=json",
function(json) {
convert(json,"googleMapUser");
}
);
}
Using this I am getting values from Service and this happens in a continous interval .
interval = startInterval(ajaxCall, 3000);
The value of url must change for each call and it must be taken from list
all_entries_user
gives me the same id every time.
I tried to pop values but each time gives me same value
I havent found an efficient way to iterate through this.
Suggestions and Help Please
Why don't you use the for construct?
{% for user in all_entries_user %}
Do your thing with {{ user }}
{% endfor %}
It's very confusing when you mix two languages. What's happening is your javascript is getting "Built" once when the template is rendered so you only have one URL regardless of how many times javascript hits that method. You can verify this by using view source and checking out what your javascript looks like to the client.
If you want the client to call a different URL each time, you will have to send all the IDs down to the client first. One way to do this is by using json serializer or just a simple home grown javascript array builder.
Something like this might work:
<script>
var allEntries = [{% for entry in all_entries_user %}{{ entry.id }},{% endfor %}];
for (entryId in allEntries) {
doSomethingWith(entryId);
}
</script>
This isn't the best way to populate an array of javascript from django, but it works in a hurry.

Categories