I am trying to pass a variable onto a javascript in flask.
But I get the following error: TypeError: Object of type MyClass is not JSON serializable
Code:
routes.py:
#app.route('/')
#app.route('/index')
def index():
data = {
"foo": myObj
}
return render_template('index.html', data=data)
To note that myObj is a custom class object of type MyClass.
index.html:
<script src="{{ url_for('static', filename='my_script.js', type="module") }}" crossorigin="anonymous"
defer>
</script>
<script>
let data = {{ data|tojson }};
</script>
my_script.js:
console.log(data);
I tried to simply write {{ data }} instead of {{ data|tojson }} but I get the errors:
Uncaught SyntaxError: Unexpected token '&' and my_script.js?type=module:1 Uncaught ReferenceError: data is not defined at my_script.js?type=module:1
I know that there are a lot of question, but I do not find one that addresses this issue.
The problem here is that you're trying to pass a Python object to Javascript. It's not going to work. The best thing to do is convert it to JSON, which is compatible between Python and Javascript.
Using the json module you can serialise your dictionary. However, the Python object of MyClass is not JSON serialisable. You should be able to serialise the __data__ attribute instead, which is a dictionary of attributes in the object.
Change your Python like this:
import json
#app.route('/')
#app.route('/index')
def index():
data = {
"foo": myObj.__dict__
}
return render_template('index.html', data=json.dumps(data))
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 am rendering the json response data through apiview in django restframework, to html template list.html where i want to retrieve this data in a javascript code.
However everytime it gives "missing ) after argument list error" even though they are not actually present in the data received (as seen in inspect tools of chrome)
Getting the error on
var list =JSON.parse("{{data|safe}}")
The code apiview from views.py which is rendering the data is :
#api_view(['GET','POST'])
def memeList(request):
if request.method=='GET':
meme = Meme.objects.all().order_by('-meme_id')[:100]
serializer = MemeSerializer(meme, many=True)
elif request.method=='POST':
serializer=MemeSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
serJS = JsonResponse(serializer.data,safe=False)
return render(request,'list.html',{'data':serJS.content})
Any solution for this as i have tried all available solutions on the internet still the problem isn't resolved.
The problem lies in the last line in the snippet from your views.py file:
return render(request, 'list.html', {'data': serJS.content})
Here, serJS.content returns a bytestring representing the content. To parse it as JSON, you need to convert it to string, render in the html body and then it will be parsed as JSON correctly. Use this instead:
return render(request, 'list.html', {'data': serJS.content.decode()})
You cannot do this:
var list = JSON.parse("{{data|safe}}")
{{ data|safe }} will render Python objects that cannot be (reliably) parsed as JSON.
What you likely want is to use the json_script template filter. Follow the steps in the docs to get your data as JSON in JavaScript.
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 want to export a JSON string in python into a JS variable.
<script type="text/javascript">
var data = JSON.parse('{{ dataJSON }}');
console.log(data)
</script>
If I print the content of dataJSON I get: [{"offset":0,"total":1,"units":[{"village_id":37,"village_name":"Glim
But in the JS I get this: JSON.parse('[{"offset":0,"total":1,"units":[{"village_id":37
I use jinja2 template engine: http://jinja.pocoo.org/docs/dev/templates/#if
How can I fix that?
You need to mark the data as safe:
var data = {{ dataJSON|safe }};
This prevents it from being HTML-escaped. There is no need to use JSON.parse() this way; JSON is a valid JavaScript subset (at least insofar that the Python json module produces a valid subset).
Take into account that this doesn't make it JavaScript safe. You may want to adjust your JSON serialisation. If you are using Flask, a tojson filter is provided that ensures you get JavaScript-safe valid JSON:
var data = {{ data|tojson|safe }};
If you are not using Flask, post-process the JSON:
dataJSON = (json.dumps(data)
.replace(u'<', u'\\u003c')
.replace(u'>', u'\\u003e')
.replace(u'&', u'\\u0026')
.replace(u"'", u'\\u0027'))
This is Python code to produce a dataJSON value that can be safely used in HTML (including attribute values) and in JavaScript. Credit here goes to the Flask json.htmlsafe_dumps() function.
I want to export a JSON string in python into a JS variable.
<script type="text/javascript">
var data = JSON.parse('{{ dataJSON }}');
console.log(data)
</script>
If I print the content of dataJSON I get: [{"offset":0,"total":1,"units":[{"village_id":37,"village_name":"Glim
But in the JS I get this: JSON.parse('[{"offset":0,"total":1,"units":[{"village_id":37
I use jinja2 template engine: http://jinja.pocoo.org/docs/dev/templates/#if
How can I fix that?
You need to mark the data as safe:
var data = {{ dataJSON|safe }};
This prevents it from being HTML-escaped. There is no need to use JSON.parse() this way; JSON is a valid JavaScript subset (at least insofar that the Python json module produces a valid subset).
Take into account that this doesn't make it JavaScript safe. You may want to adjust your JSON serialisation. If you are using Flask, a tojson filter is provided that ensures you get JavaScript-safe valid JSON:
var data = {{ data|tojson|safe }};
If you are not using Flask, post-process the JSON:
dataJSON = (json.dumps(data)
.replace(u'<', u'\\u003c')
.replace(u'>', u'\\u003e')
.replace(u'&', u'\\u0026')
.replace(u"'", u'\\u0027'))
This is Python code to produce a dataJSON value that can be safely used in HTML (including attribute values) and in JavaScript. Credit here goes to the Flask json.htmlsafe_dumps() function.