Having Django iterate through JSON possible?

1,836 views
Skip to first unread message

robo

unread,
Sep 14, 2007, 1:35:05 PM9/14/07
to Django users
Hi,

I am able to send JSON data from Django to my javascript function, but
I would like to iterate JSON by using the Django template language. Is
this possible at all?

For example, my view passing JSON back:
def ajax_form_test(request):
data = serializers.serialize("json", Order.objects.all())
if request.method == 'POST':
return HttpResponse(data, mimetype="application/json")

And my Javascript function that receives JSON:

function hello() {
var form_data = {
url: "/ajax_form_test/",
handleAs: "json",
load: function(data){
dojo.byId("myDiv1").innerHTML = data;
},
error: function(data){
alert("Holy Bomb Box, Batman! An error occurred: " +
data);
},
timeout: 5000,
form: "myForm"
};
dojo.xhrPost(form_data);
}

Right now the way my template displays JSON is by using innerHTML as
above. But I would like to convert the data somehow so that Django can
iterate in the {{...}} syntax.

Thanks,

robo

olivier

unread,
Sep 14, 2007, 2:24:15 PM9/14/07
to Django users
Hi,


> I am able to send JSON data from Django to my javascript function, but
> I would like to iterate JSON by using the Django template language. Is
> this possible at all?

No, it's not. Javascript works on the client side and doesn't know
anything about the way the server did generate the response.

But nothing prevents you to iterate your data with regular javascript,
ie. stuff like :
for (i = 0; i < data.length; i++) {
// do something.
}

In this case, you may want to build your json object by hand with
simplejson.dumps() instead of using serializers.serialize(), it will
give you more flexibility.

Regards,

olivier

r_f_d

unread,
Sep 14, 2007, 3:05:31 PM9/14/07
to Django users
The big issue here would be why to do that. If you are doing this
synchronously, why put the data into a json object. Just pass a
dictionary and do what yo will. If you are doing this ansynchronously
(ala AJAX) then the page will not reload and the template will already
be compiled and unable to incorporate any new information passed
asynchronously. One thing that you can do is to pass a
render_to_response call a template and the python dictionary you want
modified and let django work its majic on it before returning the
'._container' to the page via json. You will still have to use some
javascript to display the new information. I use this mechanism
extensively in an app I am currently writing, but am partial to the
YUI rather than dojo.
-richard

robo

unread,
Sep 14, 2007, 3:31:12 PM9/14/07
to Django users
Hi Richard,

Can you give an example of what you are suggesting?

> One thing that you can do is to pass a
> render_to_response call a template and the python dictionary you want
> modified and let django work its majic on it before returning the
> '._container' to the page via json.

Thanks.

To Olivier: Iterating through javascript like that is possible, but it
poses a disadvantage in that I cannot access the data's related object
(e.g. ForeignKey relationships).
For example I can do data[0].fields.user and I'd get "3" as a
response, but I cannot do data[0].fields.user.username, where user is
a foreignkey. Whereas in Django I can do something like this:
manager.user.username and I'd get the user name.

Thanks for the responses, all.

olivier

unread,
Sep 14, 2007, 4:07:15 PM9/14/07
to Django users
> To Olivier: Iterating through javascript like that is possible, but it
> poses a disadvantage in that I cannot access the data's related object
> (e.g. ForeignKey relationships).
> For example I can do data[0].fields.user and I'd get "3" as a
> response, but I cannot do data[0].fields.user.username, where user is
> a foreignkey. Whereas in Django I can do something like this:
> manager.user.username and I'd get the user name.


That's the reason you may want to build a custom JSON dict and use
simplejson.dumps().
Something like:

orders_qs = Order.objects.all()
orders = []
for order in order_qs:
# stuff all the fields and foreign key fields you want to use
here.
item = [order.foo, order.spam, order.user.username]
orders.append(item)

output = {"orders" : orders}
return HTTPResponse(simplejson.dumps(output), mimetype = "application/
javascript")


and in javascript

var form_data = {
url: "/ajax_form_test/",
handleAs: "json",
load: function(data){

for (i = 0, i < data.orders.length, i ++) {
// Do something
}
},

Richard Dahl

unread,
Sep 14, 2007, 4:48:18 PM9/14/07
to django...@googlegroups.com
sure,
I am using the YUI tree to display a tree of assets and thier associated children, i.e. the 'Devices' node of the tree has 'www.acme.com' and ' db1.acme.com' underneath it.  Clicking on the tree parent utilizes the builtin YUI function to expand the tree which sends an async (Xml HTTP Request aka AJAX) request to a view which returns the nodes and is populated.  However, when the user clicks on a childless node such as ' www.acme.com'  an XHR request is sent to a view which, after verifying some security parameters, creates a newform of the device, gets associated history records, assessment records, and messages for the device and then uses a number of render_to_response calls ala:

form = render_to_response('device_form_template.html', {'form': f})

The view then creates tables for the related records (history, assessments, messages) ala:

a = obj.assessments.all()
assessment_table = render_to_response('assessment_table.html': {'assessment': a})

This template formats the assessment, history, and message information into 3 raw html tables

the view then takes all of these components (the tables and the form) and bundles it into a response dictionary

response_dict.update{'form': form._container, 'assessment_table': assessment_table, messages, history... )

and returned: via
HttpResponse(simplejson.dumps(response_dict), mimetype = 'application/javascript')

My javascript callback function then unpacks the json object and puts the forms and the three tables into one of four tabs on a tab panel on the right 2/3rd of the screen.  As I said I am using the YUI so I can easily transform the three tables into Yahoo User Interface Datatables which allow sorting and scrolling and all that stuff really easily.

I hope this explanation has been clear enough, but I can post a sample if you would like, let me know which piece is most puzzling (view, template, javascript)

-richard

robo

unread,
Sep 18, 2007, 11:08:41 AM9/18/07
to Django users
Hi Richard,

I think I got the idea of your view. What I'd like to see is an
example of your template and javascript to see how you are accessing
the json data.

Thanks a lot,

robo

Richard Dahl

unread,
Sep 18, 2007, 11:53:20 AM9/18/07
to django...@googlegroups.com
Robo,
The particular view I was describing returns a jsonified  dictionary that (if all goes well) contains a form, a history table, and a messages table.  If things do not go well, it will return either a jsonified dictionary containing either an error or a login_error depending on what went wrong.

The template for the individual forms is pretty basic as are the templates for the history and messages tables:
form template:
{% if form %}
    <form id='deviceForm' name='Device' method="POST' action='javascript:submitForm("deviceForm", {{ id }},  "Device")'>
    {{ form.as_p }}
    {% if editable %}
        <button>Save</button>
    {% endif %}
{% endif %}

the history table template:

<div id='logTableDiv'>
    <table id='logTable'>
        <thead><tr><th>User</th><th>Action</th><th>Date</th></tr></thead>
        <tbody>
            {$ for l in logs %}
                <tr><td>{{ l.user }}</td><td>{{ l.action }}</td><td>{{ l.datefield }}</td></tr>
            {% endfor %}
       </tbody>
    </table>
</div>

the messages table template looks exactly like the history template with just different headers and contents

Here is the function that initiates the ajax call and evaluates the ajax response, but remember this is YUI specific, this will not work using mochikit, prototype, or any other javascript library:

function loadDetailData(node){
var sUrl = ("get_asset_detail/" + node.nodeId + "/" + node.nodeType + "/" + Math.ceil(Math.random() * 500000) + "/");

//the math.random call is needed as the current version of the YIU treeview widget uses a default mode to cache all expand calls.  I want users to be able to see all nodes that may have been added by others during a user session without doing a page refresh.  the view called by get_asset_detail ignores the random number.

var callback = {
success: function(oResponse) {
    var response_obj = eval('(' + oResponse.responseText + ')');
   if (response_obj.Login_Error){
        alert('Your session has expired, please login again.');
        var authWindow = window.open("", "loginWindow");
        authWindow.document.write(response_obj.Login_error);
    }
    else{
        var detailTabl = new YAHOO.widget.TabView('tab-div');
        var myobj = response_obj.form; // Get the form html from the json dictionary
        var tab = detailTab.getTab(0);    // Get the form tab
        tab.set("content", myobj, true);  //Put the form on the tabview widget
        var myobj = response_obj.log; //get the history table html from the json dictionary
        var tab = detailTab.getTab(1);    //Get the history tab
        tab.set("content", myobj, true);  //Put the history table on the tabview widget
        buildLogTable();  //call the function that turns the raw html table into a YUI datatable
        }
    }
    failure: function(oResponse) {
        alert("Failed to process XHR transaction.",
    },
    argument: {
        "node": node, // This is the treeview node that is passed into the function to initiate the async request
    },
    timeout: 7000
};

YAHOO.util.Connect.asyncRequest('GET', sUrl, callback):
}     


Let me know if you need any clarification on any point.
-richard

robo

unread,
Sep 19, 2007, 1:51:44 PM9/19/07
to Django users
Richard, it still doesn't seem like Django can iterate through json.
All we can do is stuff data into div tags. In the "{% if form %}"
statement of yours, is "form" the object that you got from "var myobj
= response_obj.form;" ? If it is, then you might have something
special going on there that I can learn from.

But meanwhile, I've tried to switch from serializers to simplejson,
and it's giving me a "Error: bad http response code:500" everytime,
whereas serializers give me the same error only 50% of the time (and
this too is BAD!).

When I'm using serializers, the only difference between getting an
error not depends on which objects I'm getting. For example, I get an
error when I use this code:


def ajax_form_test(request):
data = serializers.serialize("json", Order.objects.all())

return HttpResponse(data, mimetype="application/javascript")

but no errors when I use this code:
def ajax_form_test(request):
data = serializers.serialize("json", Manager.objects.all())
return HttpResponse(data, mimetype="application/javascript")

And when I use simplejson, I ALWAYS get errors no matter what. The
code is as simple as this:
def ajax_form_test(request):
data = Manager.objects.all()
return HttpResponse(simplejson.dumps(data), mimetype="application/
javascript")

Help me solve this bizzare mystery!

Thanks,

robo

Richard Dahl

unread,
Sep 19, 2007, 2:33:06 PM9/19/07
to django...@googlegroups.com
robo,
I think you may be looking at this the wrong way.  The way I am using JSON is to pass server generated data from django to my javascript callback on the client. That is it.  when I make a request from the client to the server I do things exactly like I would do a "Web 1.0" application.  When you go to the index page of my app a YUI treeview is created on the left side of the screen with various component names in the tree.  Clicking on any of the component names will cause an async request to be made (AJAX) to django at a url defined within urls.py just as a synchronous request, i.e. '/add_tree_node/device'.  The difference is that the view that responds to this url returns an HttpResponse that contains a JSON object instead of html.  The javascript function processes the JSON object and changes the DOM to add whatever markup is provided, alert the user, etc...  There is no time where django needs to iterate through JSON directly.  The template for the 'index' page where this is happening has already been parsed by django and that action is done. 

The 'form' object that is returned is a standard django.newforms.Form subclass (or a form_for_model or form_for_instance) and that template is used only to essentially create an html snippet that can be displayed via the javascript callback.  This process happens natively within django with no JSON at all.  I am using a regular call to a model, i.e. d = Device.objects.get(pk=1) to get the device object and f = forms.form_for_instance(d) to get the form.  The render_to_response works the same way, putting together html just like django always does.  The JSONification happens with the simplesjson.dumps(response_dict)  and it is pure javascript on the client callback to munge the returned data.

As far as why you are having problems with serializers I do not know, I have only used simplejson.dumps .  I believe it is failing with your code because it expects a  python dictionary, not a django queryset.
Try something like

data = Manager.objects.all()
managers = []
for d in data:
    managers.append ({'data_attr1': d.attr1, 'data_attr2': d.attr2, etc.....})
response_dict = {'Managers':  data}
return HttpResponse(simplejson.dumps(response_dict), mimetype="application/
javascript")

When you evaluate the JSON object with your javascript, the ouptut should look like {Manageers:[{'data_attr1': d.attr1, 'data_attr2': d.attr2},{'data_attr1': d.attr1, 'data_attr2': d.attr2}]}
so using the YUI you would eval the response.ResponseText and end up with a response_obj.Managers object that would contain the list of dictionaries.

Does this make sense?

-richard

robo

unread,
Sep 19, 2007, 2:36:15 PM9/19/07
to Django users
Hmm ... I tested these in non-Django templates and Django itself gave
me no errors. But now that I've tested it on a Django template, it's
giving me "Decimal("0.00") is not JSON serializable" errors.

Richard Dahl

unread,
Sep 19, 2007, 3:00:21 PM9/19/07
to django...@googlegroups.com
I believe that that is a known bug, thought I do not know details and have not had any problems myself, as I have never tried to serialize a decimal.
-richard


On 9/19/07, robo <LongD...@gmail.com> wrote:

Russell Keith-Magee

unread,
Sep 19, 2007, 7:46:03 PM9/19/07
to django...@googlegroups.com
On 9/20/07, Richard Dahl <ric...@dahl.us> wrote:
> I believe that that is a known bug, thought I do not know details and have
> not had any problems myself, as I have never tried to serialize a decimal.

Known to who? I'm not aware of any current Decimal serialization
issues, and a quick search of the ticket database didn't reveal
anything, either.

There were some decimal serialzation issues when 0.96 was released,
but they were fixed long ago, and the test suite includes Decimal (and
Float) serialization..

Can you either:
- provide an example that demonstrates your problem
- point at the Django ticket for the serialization issue you describe.

Yours,
Russ Magee %-)

Richard Dahl

unread,
Sep 20, 2007, 9:51:51 AM9/20/07
to django...@googlegroups.com
My bad it is not a bug in Django, I was it was on this list a while ago, a quick search provided this:

" here's no bug here.

Firstly, it's a "problem" with simplejson, not with Django. It would be
bad policy for us to make any changes to simplejson. We just include a
copy of the upstream simplejson source.

It's not even really a problem with simplejson, since Bob Ippolito has
designed it very well to make it easy to extend as you might wish.
That's exactly how we handle the problem in Django and how you should
handle it if you are using simplejson directly for your own purposes.

Regards,
Malcolm "

Which is where my confusion came from.   Another post to the list suggested casting the decimal field as a float prior to using simplejson.dump.

-richard

robo

unread,
Sep 20, 2007, 12:09:36 PM9/20/07
to Django users
I've found this piece of code from Wolfram Kriesing: http://dpaste.com/hold/4601/

He hacked it so that any decimal field is returned as a string. All
you have to do to use this is paste the code into a file, such as
json.py, and import the json_encode function from that file where you
want to use it:

from dev_gfs.shop.json import json_encode
def hello():
return HttpResponse(json_encode(OrderDetail.objects.all()),
mimetype="application/javascript")

To Russel: you said that this decimal serialization issue was fixed a
long time ago. How so?

Thanks,

robo

Russell Keith-Magee

unread,
Sep 20, 2007, 9:23:43 PM9/20/07
to django...@googlegroups.com
On 9/21/07, robo <LongD...@gmail.com> wrote:
>
> To Russel: you said that this decimal serialization issue was fixed a
> long time ago. How so?

s/Russel/Russell/ :-)

I'm not entirely sure what 'this decimal serialization issue' actually
is - this thread hasn't produced a clear test case that demonstrates
that there is a problem in Django's JSON serializer.

However, in 0.96, we didn't make the clear distinction between
Decimals and Floats that exists in SVN trunk. This caused all sorts of
problems for serialization.

SVN trunk now makes the distinction between the two types, and the
test suite contains explicit serialization tests for Floats and
Decimals of various levels of precision. If there is a test case we're
missing, feel free to open a ticket.

Yours,
Russ Magee %-)

Reply all
Reply to author
Forward
0 new messages