Passing objects from Django to Javascript DOM

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 dicts, which JSON has no problem serializing, and JavaScript no problem in understanding.


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!


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.


EDIT: please don't use this method, see @agconti's answer.

Use the escapejs filter: https://docs.djangoproject.com/en/1.4/ref/templates/builtins/#escapejs

Example of dumping a list:

var foo = [{% for x in y %}'{{ x|escapejs }}',{% endfor %}]