2

I am trying to send a JSON object from a Django PostgreSQL database to a Django template. Here is my models.py

# models.py
from __future__ import unicode_literals

from django.contrib.postgres.fields import JSONField

from django.db import models

class Net(models.Model):
    net_name = models.CharField(max_length=200)

    def net_default():
        return {"net_name": "None", "graph_data": "None", "city_data": "None"}

    data = JSONField(default=net_default())

    def __unicode__(self):
        return self.net_name

Here is my views.py

# standard includes
from django.shortcuts import render

# my includes
from django.http import HttpResponse
from django.template import loader

# get nets
from .models import Net

def index(request):
    net_q_set = Net.objects.order_by('net_name')
    context = {
        'nets': net_q_set,
    }
    return render(request, 'viewer/index.html', context)

So I have a sidebar in which the user selects a network from the 'nets' JSON object. Then a javascript function which takes the selected network name should iterate through the JSON object to get the network's nodes and get each node's latitude and longitude. I am able to iterate through the names with the following code (this code works and produces what I want):

{% for name in nets %}
    <li><a href="javascript:plotMap('{{name}}');">{{name}}</a></li>
{% endfor %}

But I am having an issue establishing the JSON object in the javascript script. I have tried:

<script>
    var nets = JSON.parse({{ nets }})
    function plotMap(name){ ... };
</script>

But I get an error of 'unexpected token &' on the var nets line. I am guessing this is from parsing the JSON object. Is there a better way to do this? Or am I making an error I am blind to?

Edit -- 2 Using @Arpit's solution, I call

{% for name in nets %}
    <li><a href='javascript:plotMap({{name.data}});'>{{name}}</a></li>
{% endfor %}

Then in the plotMap(net_json) function I immediately call alert(net_json.city_data.Perth1.lat); from my understanding this should make an alert that displays "-31.93333", instead I get an error "Uncaught SyntaxError: Unexpected string". Clicking the debugger link on that shows me:

plotMap({u'city_data': {u'Alice,Springs': {u'lat': -23.7, u'long': 133.88333}, ...}, u'graph_data': {u'nodes': [u'Perth1', ...], u'links': [[u'Perth1', u'Adelaide1'], ...]'});

2 Answers 2

3

Your context is not a jsonfield attribute, Its a queryset. You are trying to give an object name in your javascript function rather than giving data attribute which is a jsonfield.

In your existing code if you reference the data attribute then it should work.

{% for name in nets %}
    <li><a href="javascript:plotMap('{{name.data|safe}}');">{{name}}</a></li>
{% endfor %}

If you just want jsonfield values then you can do

net_q_set = Net.objects.order_by('net_name').values('data')

EDIT: you can use a method to stringify the json so it would be much easier to use it.

class Net(models.Model):
    net_name = models.CharField(max_length=200)

    def net_default():
        return {"net_name": "None", "graph_data": "None", "city_data": "None"}

    data = JSONField(default=net_default())

    @property
    def get_json_data(self):
        return json.dumps(self.data)

    def __unicode__(self):
        return self.net_name

Then in template.

<li><a href="javascript:plotMap({{name.get_json_data}});">{{name}}</a></li>
Sign up to request clarification or add additional context in comments.

7 Comments

If I do '{{name.data}}' then can I dig down to the data I need in the javascript function? Or do I need to pass each as I need them? Example: `<li><a href="javascript:plotMap('{{name.data.graph_data}}', '{{name.data.city_data}}' );">{{name}}</a></li>
'{{name.data}}' will pass json to the function and then you can parse it and use it. If you don't want to loop through the entire data and pass every json object then you can use values method mentioned above or you can use a serializer directly
I am having trouble parsing. I call the javascript function passing "{{name.data}}" then I call var temp = JSON.parse(net_json); where net_json is the {{name.data}}. I get the error "Uncaught SyntaxError: Unexpected token u in JSON at position 1 at JSON.parse (<anonymous>) at plotMap ((index):349) at <anonymous>:1:1" upon further inspection I see that it is having problem with the JSON being: {u'city_data': {u'Alice,Springs': {u'lat': -23.7, u'long': 133.88333}, ... , u'graph_data': {u'nodes': [u'Perth1', ...], u'links': [[u'Perth1', u'Adelaide1'],..]}}
Don't use '{{name.data}}'. Use {{name.data}} and don't use json.parae in your script tag also
I will edit my post to show more of what's happening now. It seems like the JSON is only being parsed down one level or isn't even being parsed at all and is just undefined
|
1

This is not directly related to your question but you would probably like to replace

data = JSONField(default=net_default())

with

data = JSONField(default=net_default)

In the first case you invoke net_default function and set the return value as value of default argument. This will result in creating a mutable default that is shared between all instances of JSONField. In the other case you set callable as value of default argument and this will result in invoking the callable and setting its return value as a default for each new instance of the model.

Snippet from docs:

If you give the field a default, ensure it’s a callable such as dict (for an empty default) or a callable that returns a dict (such as a function). Incorrectly using default={} creates a mutable default that is shared between all instances of JSONField.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.