This past weekend, the RSS feed for Steve Smith’s great Ordered List blog decided to tell me a whole bunch of items were new, when they really weren’t. I’m not sure why that happened, but I’m glad it did. It resulted in my discovery of an entry he wrote back in November entitled Rails and MVC. Steve notes that several people toy with Rails a bit, but never get very far, and concludes that part of the reason for this is their lack of understanding of the Model-View-Controller programming design pattern.
Steve goes on to outline what MVC is and how it applies specifically to Ruby on Rails. It struck me that a similar piece for Django might be useful, especially since Django breaks slightly from the traditional definition of MVC. In Django, it’s MTV.
The best way to describe the MVC concept to the audience of this blog is with an analogy: MVC strives to rectify many of the same problems that the web standards movement tried to solve on the front end of things. Largely, MVC is about the separation of the different layers of a program. Just as the web standards movement was largely about breaking apart the content, presentation, and behavior layers of a web document, MVC is all about a clean break between the data, the logic that occurs around that data when a user interacts with an application, and the presentation of that data to the user. Just like web standards, right? Right.
Django is usually called an MVC framework, and justifiably so. It’s very heavily influenced by MVC and it’s even possible to argue that terminology is only place Django changes the pattern. In Django, the three core layers are the Model, the View, and the Template.
The model acts as a definition of some stored data. In a web application, this data is usually stored in a relational database, but it doesn’t have to be — it could be in an XML file, an LDAP schema, and so on. In Django, a model is a Python class that outlines the variables and methods for a particular type of data. As an example, let’s consider a blog entry (yes, it’s the example everyone does, but that’s because everyone knows what a blog entry is, so it’s easy to understand). A simple blog entry model in Django looks like this:
Our entry model has several variables (author, title, body, summary, etc.), and two methods (
get_absolute_url()). In the typical Django web application, variables are values stored in the database, and methods are Python functions that (very often, anyway) do something with that data. As as simple example, a model may have variables for
last_name, and a method called
full_name() that uses Python to concatenate the two together. In a typical blog application, we would have a handful of models — one that describes a blog, one that describes an entry, one that describes a tag, one that describes a user, and so forth. Each of these models can have any number of instances, or objects of that class (i.e. individual blogs, entries, tags, users, etc.).
In most typical Django applications, the purpose of the view is to determine what data is to be displayed, retrieve it from the database, and pass it off to the template. In actuality, a view has the potential to do a lot more — but I’m covering the typical case here. Views are Python functions. Typically, you will have one view for each “type” of page within your site. In our blog example, we could have several views: one for the entry page that displays each post, one for a monthly archive, one for a daily archive, one for a search page — and a homepage, of course.
In most Django views, the programmer takes advantage of Django’s built-in object-relational mapping API to retrieve some set of information from the database. The ORM allows one to write Python code instead of SQL for these functions (although you can still drop down a level and write SQL directly, if you prefer). Views may also perform other kinds of tasks besides database interaction — tasks like sending e-mail messages, authenticating against some external service, and validating form input are all common. Most of the time, view functions are short (often less than 15 lines of code), and perform simple, specific tasks. In plain English, here are a couple views:
- Get all of the blog posts created by the user “jcroft” with the tag “django” from the database, put them in a list (Python’s word for “array”) called “blog_entries”, and pass it through the template called “blog/tag.html”
- Take the input from the form a user just filled out, validate it according to a set of rules, save it to the database, fire off an e-mail to notify someone, and then return the template “form/done.html” to the user.
The most common end point for a view function is to hand off a context to a template for rendering. A context is simply the variables that are available to the template. So, on our blog entry page template, the context will be one specific blog post. One a monthly archive page, it will be a list of all posts in that month. On the homepage, you might have a much more varied context, including the last 10 posts, a list of all the tags, a list of all the years you’ve posted in, and the 10 latest comments.
It’s important to understand that the view has no bearing over how the data is presented — only which data is presented (this is where Django varies from some other MVC frameworks). How the data is presented is the job of…
entry, we might craft a template like this:
Of course, you’d do a fully-qualified HTML page with a
body, and so forth — but you get the idea. Django’s template language is designed to be accessible by designers who aren’t necessarily programmers. It offers several basic tags, as well as a large selection of built-in filters for modifying the output of variables and methods (for example, formatting a date string or lowercasing text that isn’t lowercase in the database). It contains basic programming constructs, such as
if statements and
for loops, which are often needed for presentation logic. But, unlike some other template languages, you can not arbitrarily put Python code into a template. The language is intentionally limited so as to encourage you to properly separate your presentation logic from your business logic. Seasoned programmers sometimes find this limiting. Having used the Django template language perhaps more extensively than anyone else anywhere, I can assure you: if you can’t do it with the Django template language, it’s probably because you shouldn’t be doing it with the Django template language. It’s got everything a designer needs for presentation — your business logic belongs in the view.
The URL Configuration
There is one final piece of the Django stack: the URL configuration (usually called a URLConf by Djangoers). This is simply a mapping of URLs to the views that should handle them. You’ll recall above that we create views for each type of page within our site — and each view is a Python function. The URLConf’s job is to read the URL the user has requested, find the appropriate view to handle it, and pass any variables along that the view will need to complete its job.
URLConfs are constructed with regular expressions, giving you absolute control over the URLs for each part of your site. This is a nice abstraction that many other frameworks don’t offer. It follows along with the Python philosophy that explicit is better than implicit, having you spell out exactly what you want your URLs to be, instead of implying them from your function names, directory structure, etc.
Beautiful URLs are cool, and Django’s URLConf setup lets you achieve them. Here’s an example URLConf:
As you can see, the first URL pattern contines a simple regular expression (
'^$'), which equates to the root level of the site — when found, it processes the
homepage function. The second line contains a much more complex regular expression, which evaluates urls in the format
/2007/jan/10/iphone-most-revolutionary-device/ and passes the various bits (year, month, date, slug) off to the
blog_entry view function.
Putting it all together
Having looked at each piece of the Django puzzle, let’s consider how they work together for a typical request. Consider the homepage of JeffCroft.com. When you visit that page, the basic steps that occur are:
- Django searches my URLConf for a URL that matches the one you’ve asked for (in this case, ”/”).
- The URLConf specifies that the appropriate view is
jcroft.homepages.views.homepage, so Django processes that view function.
- The view function for the homepage uses the Django database API to request several bits of data from the model layer. Among them: the latest blog posts, the latest flickr photos, the latest ma.gnolia links, the selections of music, books, and so forth from Enjoying, and so on.
- The model layer interacts with the database to find these requested items, and returns them to the view.
- The view passes these items as variables through the template, which is evaluated and results in an HTML page.
- This HTML page is passed on to the browser.
Wrapping it up
To be sure, this is a very basic overview, and my example of how a typical page request happens in Django is a simple one. Hopefully, though, it was able to give you a basic understanding of the duty of each layer in Django’s “MTV” stack.