Using DHTMLXgrid in a Django application
12 December 2009
Comments
DHTML eXtensions (DHTMLX) is a set of JavaScript widgets/frontend UI elements such as trees, grids, comboboxes, windows etc. On the project web page you will find all components. DHTMLX offers GPL version, and paid commercial one with more features and with support. The components offer out of the box complete solutions - like dhtmlx grid can load partial data on requests from large datasets, edit data and so on.
dhtmlxGrid
dhtmlxGrid is a JavaScript frontend for displaying table like, spreadsheet like data. It can read data from formats like XML, JSON, CSV. For more details check the documentation and examples.

dhtmlxGrid quickstart
In this how-to I'll show you how to make a skeleton static HTML page with the initial grid code.
- When using dhtmlx components Firefox extension - Firebug comes really handy. You will be able to debug the app, and track it execution stages.
- Download the GPL version: dhtmlxGrid.zip
- Extract the archive to empty folder (I extracted everything to a subfolder dhtmlxGrid)
- To use dhtmlx grid (or other component) you have to create a initialization function that will put and configure the grid in a selected place on the page. A simple code that does the job would look like this:
In HEAD we add CSS and JS files for the grid, and then we define doInitGrid function, which will create the grid. In this function you can configure the grid as you like. This example doesn't has any rows in it yet.
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <title>xGrid</title> <!-- xGrid files --> <link rel="stylesheet" type="text/css" href="dhtmlxGrid/dhtmlxGrid/codebase/dhtmlxgrid.css" /> <link rel="stylesheet" type="text/css" href="dhtmlxGrid/dhtmlxGrid/codebase/skins/dhtmlxgrid_dhx_skyblue.css" /> <script src="dhtmlxGrid/dhtmlxGrid/codebase/dhtmlxcommon.js" type="text/javascript"></script> <script src="dhtmlxGrid/dhtmlxGrid/codebase/dhtmlxgrid.js" type="text/javascript"></script> <script src="dhtmlxGrid/dhtmlxGrid/codebase/dhtmlxgridcell.js" type="text/javascript"></script> <script type="text/javascript"> // init function function doInitGrid(){ mygrid = new dhtmlXGridObject('grid_container'); // DIV id in which the grid will show up mygrid.setImagePath("dhtmlxGrid/dhtmlxGrid/codebase/imgs/"); // path to images mygrid.setHeader("A,B,C"); // column labels mygrid.setSkin("dhx_skyblue"); // theme mygrid.init(); } </script> </head> <body onload="doInitGrid();"> <div id="my_grid"> <div id="grid_container" style="height:400px;"></div> </div> </body> </html>
- To load data from XML document we just have to add in doInitGrid function:
Where dane.xml is the file with data.
mygrid.loadXML('dane.xml');
- The XML document has this type of structure:
Every row has unique ID and a set of cells with values. You can run this example on a server (like localhost apache).
<?xml version="1.0" encoding="UTF-8"?> <rows> <row id="1"> <cell>Col A</cell> <cell>Col B</cell> <cell>Col C</cell> </row> <row id="2"> <cell>Col Aa</cell> <cell>Col Bb</cell> <cell>Col Cc</cell> </row> <row id="3"> <cell>some</cell> <cell>value</cell> <cell>123</cell> </row> </rows>
- The grid supports sorting, filtering, loading data from big datasets and more. But most of this requires some server-side code that will respond to grid requests. Using this skeleton code we can star making real apps that use grid to display data from database.
dhtmlxGrid and Django
There is no special problems or issues when using dhtmlx components with Django, GAE or other Python tools. One thing to remember that XML documents returned to the grid have to have correct MIME. If you use render_to_response, then just add:mimetype='text/xml'
So now we will make very basic Django application with dynamic loading of data and row editing.
- Create Django project and app:
django-admin.py startproject grid python manage.py startapp testgrid
- Edit database settings (I used SQLite), add "testgrid" to INSTALLED_APPS.
- Create app model:
This is basic 5-column row.
from django.db import models class Row(models.Model): cell1 = models.CharField(max_length=255, blank=True) cell2 = models.CharField(max_length=255, blank=True) cell3 = models.CharField(max_length=255, blank=True) cell4 = models.CharField(max_length=255, blank=True) cell5 = models.CharField(max_length=255, blank=True) def __unicode__(self): return self.cell1 class Meta: verbose_name = 'Row' verbose_name_plural = 'Rows'
- Copy all the static files - dhtmlxGrid folder to site_media folder
- Copy the HTML file with the skeleton code to templates folder (templates) as show_grid.html and the dane.xml as get_data.xml. We will use them in two views - one to show the grid, and second one to return the data for the grid.
- This is the initial view code:
The get_data.xml template we change to:
#!/usr/bin/python from django.shortcuts import render_to_response from django.conf import settings from django.template import RequestContext from django.http import HttpResponseRedirect,HttpResponse from testgrid.models import * def show_grid(request): """ Display the page with grid """ return render_to_response( 'show_grid.html', {}, context_instance=RequestContext(request)) def get_data(request): """ Return grid data in XML format """ data = Row.objects.all()[:20] return render_to_response( 'get_data.xml', {'data': data}, mimetype='text/xml', context_instance=RequestContext(request))
And in show_grid.html we change the static files path as well as the XML data file path:<?xml version="1.0" encoding="UTF-8"?> <rows> {% for i in data %} <row id="{{ i.id }}"> <cell>{{ i.cell1 }}</cell> <cell>{{ i.cell2 }}</cell> <cell>{{ i.cell3 }}</cell> <cell>{{ i.cell4 }}</cell> <cell>{{ i.cell5 }}</cell> </row> {% endfor %} </rows>
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <title>xGrid</title> <!-- pliki xGrida --> <link rel="stylesheet" type="text/css" href="/site_media/dhtmlxGrid/dhtmlxGrid/codebase/dhtmlxgrid.css" /> <link rel="stylesheet" type="text/css" href="/site_media/dhtmlxGrid/dhtmlxGrid/codebase/skins/dhtmlxgrid_dhx_skyblue.css" /> <script src="/site_media/dhtmlxGrid/dhtmlxGrid/codebase/dhtmlxcommon.js" type="text/javascript"></script> <script src="/site_media/dhtmlxGrid/dhtmlxGrid/codebase/dhtmlxgrid.js" type="text/javascript"></script> <script src="/site_media/dhtmlxGrid/dhtmlxGrid/codebase/dhtmlxgridcell.js" type="text/javascript"></script> <script type="text/javascript"> function doInitGrid(){ mygrid = new dhtmlXGridObject('grid_container'); mygrid.setImagePath("/site_media/dhtmlxGrid/dhtmlxGrid/codebase/imgs/"); mygrid.setHeader("A,B,C,D,E"); mygrid.setSkin("dhx_skyblue"); mygrid.loadXML('/get_data/'); mygrid.init(); } </script> </head> <body onload="doInitGrid();"> <div id="my_grid"> <div id="grid_container" style="height:400px;"></div> </div> </body> </html>
- So we have two working views. I've made also a script spawn.py for generating some rows:
When you spawn some rows and open the app in a browser you will see first 20 rows.
# -*- coding: utf-8 -*- import sys from os import environ environ['DJANGO_SETTINGS_MODULE'] = 'settings' from settings import * from testgrid.models import * for i in range(1,500): print i r = Row(cell1='abc', cell2='d', cell3=i, cell4='1234', cell5='this is Sparta!') r.save()
Dynamic row loading
Grid can load rows in parts on request. When you have thousands or millions of rows - this allows you to browse them without killing the servers. xgrid can load rows on requests requesting data URL - /get_data/ with two GET variables: posStart i count. First one is offset and second one is the quantity of rows grid needs.- To grid init function add:
mygrid.enableSmartRendering(true);
- Modify "rows" tag in template get_data.xml:
<rows total_count="{{ total }}" pos="{{ pos }}">
- Add to show_grid.html:
<script src="/site_media/dhtmlxGrid/dhtmlxGrid/codebase/ext/dhtmlxgrid_srnd.js"></script>
- Change view get_data into:
The grid will now load new rows on request when you will be scrolling it.
def get_data(request): """ Return grid data in XML format """ if 'posStart' in request.GET: offset = request.GET['posStart'] quantity = request.GET['count'] else: offset = 0 quantity = 20 data = Row.objects.all()[offset:offset+quantity] total = Row.objects.all().count() return render_to_response( 'get_data.xml', {'data': data, 'total': total, 'pos': offset}, mimetype='text/xml', context_instance=RequestContext(request))

dataprocessor for row editing
DHTMLX has also dataprocessor component which connects client-side actions like row edition with server-side actions. We can use it to save changes in edited row. Dataprocessor will send ajax request to given URL with data as GET variables, for example:?gr_id=6&c0=abc&c1=dsdsd&c2=6&c3=1234&c4=this%20is%20Sparta!
Where gr_idis the row ID and c0-c* are the cell values.
- Add to show_grid.html:
Add to doInitGrid:
<script src="/site_media/dhtmlxGrid/dhtmlxDataProcessor/codebase/dhtmlxdataprocessor.js"></script>
var dp = new dataProcessor('/update_data/'); dp.init(mygrid); dp.defineAction("error_of_datastore",handle_error_of_datastore);
- To the same template add JS function that will handle database errors:
function handle_error_of_datastore(obj) { alert('Data not saved!<br />' + obj.firstChild.data); return false; }
- The row update is handled by new view update_data:
def update_data(request): """ Update row """ try: rid = request.GET['gr_id'] r = Row.objects.get(id=rid) r.cell1 = request.GET['c0'] r.cell2 = request.GET['c1'] r.cell3 = request.GET['c2'] r.cell4 = request.GET['c3'] r.cell5 = request.GET['c4'] r.save() except: return render_to_response( 'update_data_error.xml', {}, mimetype='text/xml', context_instance=RequestContext(request)) else: return render_to_response( 'update_data.xml', {'id': rid}, mimetype='text/xml', context_instance=RequestContext(request))
- Template update_data.xml looks like:
<?xml version="1.0" encoding="UTF-8"?> <data> <action type="update" sid="{{ id }}" tid="{{ id }}" /> </data>
- update_data_error.xml looks like:
<?xml version="1.0" encoding="UTF-8"?> <data> <action type="error_of_datastore">Something went wrong</action> </data>
Source Code
RkBlog
Comment article