Of course I'd like to take that admin system as a basis and make it do what I want- without having to rewrite it
My latest idea of how to do this is to add dojo into django and then have dojo tart up the forms. There is already a django distribution that does dojo integration called dojoango. I wasn't keen on this as it makes me dependant on a third party source who are in turn dependant on django and dojo. So while dojo and django are stable enough to use, the extra risk of a intermediate package doesn't seem worth it for what I want to do. Anyway...
I've used ajax style javascript / dhtml / css manipulation before but not in dojo. I was keen on using dojo as it abstracts a lot of the problems of javascript such as browser imcompatiblity. This is probably true of most javascript libraries. I thought that the docs for dojo were reasonable too.
However, after a week of trying to learn dojo purely from online sources I found two problems. First, all the docs seemed to assume that you were already a top notch javascript developer and/or familiar with dojo. Secondly, I couldn't Cargo Cultishly copy example programs as the versions of the library functions seem to alter quite briskly. Examples for version 1.0.0 from a year or so ago don't work with the current at the time of writing 1.2.2. This was essentially a problem of not being able to understand enough of this comprehensive framework to get started. But fortunately I talked to the right person on the freenode irc channel #dojo and they recommended the book "Mastering Dojo: JavaScript and Ajax Tools for Great Web Experiences". After a weekend reading this I had some idea of how to do what I wanted
The forms I have to implement with django are quite extensive and in the default admin interface come out as one large page. But with dojo it is relatively easy to split the page up into "tabs"
The tricky bit is to add the javascript that makes dojo work to the right template files.
To find the template files I looked at the html source of the existing admin interface. Then I grepped for unusual strings in the django contrib/admin/templates/ directory. Once I had more or less the right files I copied them to my own private template directory ( configured in django settings.py )
First I added a bunch of stuff to the "base.html" file so that the dojo libraries and styles were loaded before I did anything else:
<!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" lang="{{ LANGUAGE_CODE }}" xml:lang="{{ LANGUAGE_CODE }}" {% if LANGUAGE_BIDI %}dir="rtl"{% endif %}>
<head>
<style type="text/css">
@import "http://localhost:8000/dijit/themes/nihilo/nihilo.css";
</style>
<script type="text/javascript" src="http://localhost:8000/dojo/dojo.js" djConfig="parseOnLoad:true, isDebug: true"></script>
<script type="text/javascript">
dojo.require("dojo.parser")
dojo.require("dijit.layout.TabContainer")
dojo.require("dijit.layout.ContentPane")
</script>
<style>
.formContainer{
width:800px;
height:700px;
}
label {
width:150px;
float:left;
}
</style>
<title>{% block title %}{% endblock %}</title>
<link rel="stylesheet" type="text/css" href="{% block stylesheet %}{% load adminmedia %}{% admin_media_prefix %}css/base.css{% endblock %}" />
{% if LANGUAGE_BIDI %}<link rel="stylesheet" type="text/css" href="{% block stylesheet_rtl %}{% admin_media_prefix %}css/rtl.css{% endblock %}" />{% endif %}
{% block extrastyle %}{% endblock %}
{% block extrahead %}{% endblock %}
{% block blockbots %}<meta name="robots" content="NONE,NOARCHIVE" />{% endblock %}
</head>
{% load i18n %}
<body class="nihilo">
<!-- Container -->
<div id="container">
The rest of the pre modified admin/templates/base.html file continues after the div id container tab
Next I altered the change_form.html container. Here is the fragment, starting from just before the repeated call to the fieldset template:
<div class="formContainer" dojoType="dijit.layout.TabContainer">
{% for fieldset in adminform %}
{% include "admin/includes/fieldset.html" %}
{% endfor %}
{% block after_field_sets %}{% endblock %}
{% for inline_admin_formset in inline_admin_formsets %}
{% include inline_admin_formset.opts.template %}
{% endfor %}
{% block after_related_objects %}{% endblock %}
</div> <!-- end of dijit tabcontainer -->
The above fragment sets up a context or container for enclosed dojo elements to be treated as tabs in a tabbed form.
Then I drilled into the admin/includes/fieldset.html and edit_inline/tabular.html templates and added the dojo magic to define the individual tabs. Basically for the fieldset.html I added this single line at the start of the file:
<div dojoType="dijit.layout.ContentPane" title="{{fieldset.name}}" >
and a closing div tag at the end of the file. I did a similar thing in the edit_inline/tabular.html file.
The only gotcha I found with trying to do this was the way that the dijit component did not like other elements as direct parents/children. If the container is immediately followed by a contentpane and then that contentpane is immediately followed by a another then there is no problem. If there are other bits and pieces in between then the container gets confused. Obviously when modifying a set of templates this can be an issue.
Next I had to alter the way that the admin form was declared to use fieldsets. This is covered in the django docs Each fieldset or inline group appears in its own tab.
Here's a screenshot of the changed form.
3 comments:
Very nice! Did you publish your code?
Thank you Eugene!
I'm not sure how I could publish the changes I made anywhere- except as I have in the article. Anyone wanting to do as I have should be able to follow it ...
This is awesome. But the dojo css screws my django design up. Also when only having one fieldset (or one tab), it displays it in a tab.
Post a Comment