Passing objects from Django to Javascript DOM
I'm trying to pass a Query Set from Django to a template with javascript.
I've tried different approaches to solve this:
1. Normal Approach - Javascript gets all messed up with trying to parse the object because of the nomenclature [ > Object:ID <, > Object:ID <,... ]
Django View
django_list = list(Some_Object.objects.all())
Template HTML + JS
<script type="text/javascript" >
var js_list = {{django_list}};
</script>
2. JSON Approach - Django fails on converting the object list to a json string is not JSON serializable
Django View
django_list = list(Some_Object.objects.all())
json_list = simplejson.dumps(django_list)
Template HTML + JS
<script type="text/javascript" >
var js_list = {{json_list}};
</script>
So, I need some help here :)
Any one has any suggestion / solution?
Thanks!
Same Question, "Better"(more recent) answer: Django Queryset to dict for use in json
Answer by vashishtha-jogi:
A better approach is to use DjangoJSONEncoder. It has support for Decimal.
import json from django.core.serializers.json import DjangoJSONEncoder prices = Price.objects.filter(product=product).values_list('price','valid_from') prices_json = json.dumps(list(prices), cls=DjangoJSONEncoder)
Very easy to use. No jumping through hoops for converting individual fields to float.
Update : Changed the answer to use builtin json instead of simplejson.
This is answer came up so often in my google searches and has so many views, that it seems like a good idea to update it and save anyone else from digging through SO. Assumes Django 1.5
.
Ok, I found the solution!
Mostly it was because of not quoting the results. When Javascript was trying to parse the object this wasn't recognized as string.
So, first step is:
var js_list = {{django_list}};
changed to:
var js_list = "{{django_list}}";
After this I realized that Django was escaping characters so I had to replace them like this:
var myJSONList = (("{{json_list}}").replace(/&(l|g|quo)t;/g, function(a,b){
return {
l : '<',
g : '>',
quo : '"'
}[b];
}));
myData = JSON.parse( myJSONList );
Note: I tried to avoid escaping characters from Django using this:
var js_list = "{{json_list|safe}}";
But this doesn't work because it gets confused with the quotes.
Finally I found a way to avoid the logic on the backend of converting to JSON before sending it to Javascript:
var myDjangoList = (("{{django_list |safe}}").replace(/&(l|g|quo)t;/g, function(a,b){
return {
l : '<',
g : '>',
quo : '"'
}[b];
}));
myDjangoList = myDjangoList.replace(/u'/g, '\'')
myDjangoList = myDjangoList.replace(/'/g, '\"')
myData = JSON.parse( myDjangoList );
I'm sure this can be improved, I let this to you ;)
Thanks for your answers
Hope it helps to someone else!
Django querysets are serializable by JSON. Some field types (such as date, apparently), can't be serialized at is. A workaround for date objects is posted in another question on JSON and Python.
I would recommend creating dictionaries directly in the JavaScript itself. Given models like this:
class Article(models.Model):
title = models.CharField(max_length=100)
slug = models.SlugField()
content = models.TextField()
class Author(models.Model):
article = models.ForeignKey("Article", related_name="authors")
first_name=models.CharField(max_length=100)
last_name=models.CharField(max_length=100)
I'd do something like this in the template:
<script type="text/javascript">
var articles = [
{% for article in article_list %}
{% if not forloop.first %},{% endif %}
{
title: "{{ article.title }}",
slug: "{{ article.slug }}",
content: "{{ article.content }}",
authors: [
{% for author in article.authors.all %}
{% if not forloop.first %},{% endif %}
{
first_name: "{{ author.first_name }}",
last_name: "{{ author.last_name }}",
}
{% endfor %}
]
}
{% endfor %}
]
</script>
If you maybe worded the question a little poorly and aren't planning on inserting code in a <script>
tag and actually need JSON for some reason, I'd simply do a loop in the view and create a list of dict
s, which JSON has no problem serializing, and JavaScript no problem in understanding.