Since Struts dominated the Java Web development landscape a decade ago, a competition began to replace it with something more productive. In addition to the Spring Framework and JavaServer Faces (JSF), an explosion of Java Web frameworks such as Wicket, Stripes, GWT, Play and Click has given Java developers a bewildering array of choices.
Outside of the Java world, the dynamic language ecosystem has produced its own Web frameworks such as Ruby on Rails and Django to name a couple. However, because of their “is not Java” or “does not run on the JVM” limitations, Java shops almost always ignore them.
Django, however, has such a specific feature set that is so symbiotic with the type of business applications many Java developers develop every day that it deserves special attention. Specifically, Django has a killer feature that makes it worthwhile for Java shops to leave the comforts of the Java language: its automatic admin interface.
What Is the Django Admin Interface?
Django is built around the idea of reusable modules (simply called “apps”) that can be assembled into a larger application. One of these apps is the Admin interface, basically an auto-generated UI for listing/searching/filtering database entities and creating the add/edit/delete screens for them.
Many frameworks claim to offer something along the same lines (e.g., Ruby on Rails), but none of them are truly production-ready out of the box. This is the big difference with Django Admin: you can deploy it as-is without any customizations and it would probably be more feature-rich, slick and polished than your hand-coded CRUD screens.
The productivity boost you get from this out-of-the-box usability is incredible. You stop thinking in terms of HTML forms or templates and start thinking instead at a much higher lever:
- What database entities do I want to show?
- What fields should be visible on the search screen?
- Which of them can be used as filters?
- What fields should be visible on the add/edit/delete screen?
As an example, when I initially started learning Django I developed a working CRUD portal for about 10 database entities in about 5 days — and that included brushing up on Python and doing a few Django tutorials. More importantly, I completed this project by writing a single line of HTML (no boring
<tr/> tags, etc.). I later attempted to do the same thing in the latest version of JSF 2, but it was like being forced to crawl after I had already learned to run. I promptly went back to Django.
In this article, I’ll show you the Django automatic admin interface in action. We will build a simple invoicing application with four entities: Customer, Product, Invoice and Invoice Line. Invoice consists of a master-header relationship between an Invoice Header and Invoice Line.
Installing Python and Django
On Ubuntu, it’s as simple as this:
sudo apt-get install python-setuptools sudo easy_install Django
When you have done all of that, just do the following from the app folder:
./manage.py syncdb ./manage.py runserver
The first command auto-creates the database tables in the local SQLite3 database. The second one runs the app on port 8000.
Code Speaks for Itself
Here is how the model definition for the invoicing application would look like (usually in a file called models.py):
from django.db import models class Product(models.Model): name = models.CharField("Name",max_length=30) price = models.DecimalField("Price", max_digits = 10, decimal_places = 2) def __unicode__(self): return "%s - $%s" % (self.name,self.price) class Customer(models.Model): first_name = models.CharField("First Name",max_length=50) last_name = models.CharField("Last Name",max_length=50) address = models.CharField("Address",max_length=50) city = models.CharField("City", max_length=50) state = models.CharField("State", max_length=2) postal_code = models.CharField("Postal Code", max_length=10) def __unicode__(self): return "%s %s" % (self.first_name,self.last_name) class Invoice(models.Model): invoice_number = models.CharField("Invoice Number", max_length=30) customer = models.ForeignKey(Customer) invoice_date = models.DateField("Date") def __unicode__(self): return self.invoice_number class InvoiceLine(models.Model): product = models.ForeignKey(Product) quantity = models.IntegerField("Quantity") invoice = models.ForeignKey(Invoice) def __unicode__(self): return ("%s x %s = $%s") % (self.product,self.quantity,(self.product.price * self.quantity))
A bit less verbose than JPA, I think we would all agree.
Now let’s hook up the entities to the admin interface. Customer, Product and Invoice will all get their own CRUD screens, while Invoice Line will be hooked up automatically to its invoice via a master-header relationship.
In a file usually called admin.py we enter:
from models import Customer, Invoice, InvoiceLine, Product from django.contrib import admin class InvoiceLineAdmin(admin.TabularInline): model = InvoiceLine extra = 1 class InvoiceAdmin(admin.ModelAdmin): fields = ['invoice_number','invoice_date','customer',] inlines = [InvoiceLineAdmin] admin.site.register(Customer) admin.site.register(Product) admin.site.register(Invoice,InvoiceAdmin)
That’s it! When this is up and running, the following screens are what we get:
Now think how much code and HTML you would have to create to provide the same functionality in any Java Web framework and ask yourself this simple question: isn’t Django worth my time?
And we haven’t touched on any of the advanced functionality available in the admin app: filtering, mass actions, in-line editing, customizing the edit/list screens, etc.
When Java developers hear Python, they probably think of old school Unix editors like vi or emacs. Don’t fear; there is a great Python plugin for Eclipse called PyDev. This plugin allows you to stay within the comforts of a modern IDE, providing new project wizards, code completion and even refactoring.
In short, it’s worth learning a Python to take advantage of Django. In our development team, we have settled on Java as our language of choice for all of our performance-intensive server applications and Python Django for all of our Web development.