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)
}
Related
I am trying to pass the following context from views.py to a Django Template:
views.py:
def home(request):
context = {
'dict_1': {'key_1': ['val_11', 'val_12'], 'key_2': ['val_21', 'val_22']}
}
return render(request, 'app/home.html', context)
home.html:
<script type="text/javascript">
var java_dict = {{ dict_1 }};
console.log(java_dict);
</script>
This throws an error: Uncaught SyntaxError: Unexpected token '&'
Upon investigating, I see that the dictionary in javascript is read as follows:
{'key_1': ['val_11', 'val_12'], 'key_2': ['val_21', 'val_22']}
which probably means that the quotes-character (') is read incorrectly. How do I fix this issue?
The context data that you pass into Django templates are escaped by default, for security purposes.
If you're sure that the data is safe, you can do this:
views.py
import json
def home(request):
# Use JSON dump so that it will be a data that can be loaded in javascript
context = {
'dict_1': json.dumps({
'key_1': ['val_11', 'val_12'], 'key_2': ['val_21', 'val_22']
})
}
return render(request, 'app/home.html', context)
home.html
<script type="text/javascript">
var java_dict = {{ dict_1| safe }}; // Actually solve your problem. Don't escape the data.
console.log(java_dict);
</script>
By default, all values in Django templates escape HTML characters for security purposes. If you want to use this dictionary in JavaScript you should use json_script filter. Please read the docs to understand what's going on.
A solution for your problem would be to:
Add the script tag containing your dict to the template
{{ dict_1 |json_script:"ID_OF_NEW_SCRIPT_TAG" }}
Load the dict value in your script tag (I'll use the name you had in your example)
var java_dict = JSON.parse(document.getElementById('ID_OF_NEW_SCRIPT_TAG').textContent);
console.log(java_dict);
Replace ID_OF_NEW_SCRIPT_TAG with whatever ID makes sense to you.
I'm new to working with django and I am trying to send information to my clientside javascript. I have a list of FooBarModels that I want to use with my clientside Javascript. Currently, I'm using the django template to generate an array of dictionaries that holds the information I'll use with the Javascript.
This feels like a hacky solution, is there a better way to achieve this?
models.py
class FooBarModel(models.Model):
bar = models.ForeignKey(Bar, on_delete=models.CASCADE)
#property
def desc(self):
# logic here
#property
def display_name(self):
# logic here
template.html
<script>
var $fb_list = [
{% for fb in foobar_list %}
{ "name": {{fb.display_name}}, "desc": {{fb.display_name}} },
{% endfor %}
]
// a bunch of code that uses the $fb_list
</script>
What's the best practice for handling this type of situation? Should I be sending a package of JSON to the clientside and parsing it?
This is called Serialization, Which means converting a django django.db.Model to JSON, the inverse of this is called Deserialization which means converting the JSON to a native object, this time -if it's a valid object-.
Django supports it natively, And DRF extends this support.
Here's an example with django itself.
from django.core import serializers
data = serializers.serialize("json", SomeModel.objects.all()) # xml is supported too
print(data) # prints model as JSON
or
JSONSerializer = serializers.get_serializer("json")
json_serializer = JSONSerializer()
json_serializer.serialize(queryset)
data = json_serializer.getvalue()
print(data)
It needs a queryset EVEN if you are serializing a single object.
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}}');
My model lop is contains a list of programs which I use for varying purposes. I want to use the name field as an argument for a javascript function.
I modified some of my lops so the modified versions have a "ver2" at the end of its name. What the Javascript function does is that it checks for the suffix "ver2" of the program. The javascript was originally found from here.
I read some similar questions and one of them said that I need to serialize the object
EDIT: Expanded view of views.py, Javascript console started working and now is included.
In my views.py (UPDATED)
from django.core import serializers
.
.
.
.
def loppage(request):
jsondata = serializers.serialize('json', lop.objects.all(),fields=('name'));
## get programs
data = []
types = Type.objects.all()
for type in types:
data.append([type.title, type.script_set.all()])
context = {'lop': Lop.objects.all(), 'cat': data, 'jsondata':jsondata}
## render list
return render(request, 'loppage.html', context)
In my templates file:
Javascript/HTML (loppage.html):
<script>
function endsWithsuffix(progname, suffix) {
return progname.indexOf(suffix, progname.length - suffix.length) !== -1;}
</script>
.
.
.
.
{% for lop in type %}
<p id="Options"><i>{{lop.options}}</i></p>
<p id="Id">{{lop.name}}</p>
<script type="text/javascript">
if (endsWithsuffix({{jsondata}}, 'ver2')) { //This I've tried with and without quotation marks, and with lop.name with and without quotation marks
document.getElementById('Options').style.visibility = 'visible';
document.getElementById('Id').style.visibility = 'visible';
}
else {
document.getElementById('Options').style.visibility = 'hidden';
document.getElementById('Id').style.visibility = 'hidden';
}
</script>
{% endfor %}
But for whatever reason, the script doesn't seem to load (it loads as if the script wasn't even though).
As wardk suggested, I have now included my Javascript console which can be seen here
SyntaxError: invalid property id loppage:56:28
It's a long repetition of this same error on the same line as shown below
Debugger console highlights
if (endsWithsuffix([{"pk": 2, "model": "programs.lop",
I've been working on this way longer than I should but I can't get anywhere with it. Help.
You're applying endsWithSuffix on a json representation of lop.objects.all(). Shouldn't you test endsWithSuffix for {{lop.name}} instead?
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.