Recent posts

  • Relative readability Why go so big on type? There’s a short answer and a long answer.
  • Excuses, excuses Some people might suggest it’s not worth redesigning a site I only post to twice a year. They’re missing the point.
  • The Optimizer Every designer is wired differently. Some people are idea people, some people are artists. I’m an optimizer.
  • Indistinguishable from magic I love video games. I’m terrible at most of them. But I’m a sucker for a game with a good story.
  • Airport express Recently I learned two things about interaction design and user experience from waiting in lines at the airport.
  • Shouts and echoes There have been some situations lately that have got me thinking a lot about the Internet as a megaphone for personal communication.


10 May 2006

Are you generic?

Even more Django for non-programmers. How I built a portfolio app in 30 minutes with Django's generic views.

I remember when people were just getting excited about Rails. It was all about the demo. Build a blog (or whatever) in 30 minutes. It was so elegant that even designers were getting into it. I tried, but I hit a wall. I’m not a programmer, I probably never will be, and Rails is for programmers. Even the templates use Ruby. That’s great for some, but it’s not for me.

As a designer for World Online, I’ve been involved with the development of Django since before it was Django. I may have been the first person other than Adrian and Simon to use the template language in production. I told Simon halfway through that first project that I’d never used a template language that made so much sense to me. From the beginning, I’ve always held out hope that I would be able to take advantage of that on my personal projects, without bugging the programmers to write code for me.

I’ve finally been able to realize that dream (sniff), thanks to a little feature in Django called generic views. Jeff showed the world what a non-programmer can do with Django’s generic views (and a lot of pictures of drunk girls). So what’s so special about something so… generic?

The missing link

There are really three basic steps you need to build a basic web app in Django. You need to define models (what your data is), views (how requests for your data are returned) and templates (how your data is displayed). I know how to write templates (and any web designer who’s ever customized a Movable Type template or hacked up some PHP includes does too).

And I can get my head around a model. It’s just a definition of objects and their attributes. Conceptually, it’s a lot like writing CSS rules or Javascript objects. You’re just declaring properties, there’s no advanced logic required.

Views are another story. In a framework like Django, views are where what programmers like to call “business logic” happens, with functions and routines and queries and optimization and all that scary stuff. In a word (or two): actual programming.

But most of the time I don’t need anything that complicated. Most of the time—probably 80% of the time—I need the same simple views: a list view, a detail view and maybe some date-based archives.

That’s where generic views come in. They’re a set of simple, commonly-used views that are built in to Django for reuse in your apps. They’re designed as a utility for programmers to save time creating the same routine code so they can get on to more important things, but they’re pretty handy on their own too.

In fact, it’s possible to build an entire app or site using entirely generic views, without writing a single line of actual view code. I did it this weekend. Want to see? OK, let’s go.

How I built a portfolio app in 30 minutes with Django

I haven’t updated my portfolio in three years. To give you an idea of how long that is in Internet years, it was one of the first sites I coded entirely by hand, and one of my first all-CSS layouts. I’ve reluctantly added a few pieces here and there over the years, but I cringed every time I went back to that code. I considered recreating it with a hacked-up Movable Type blog, but that ship has sailed.

Now that I’ve got my site on Django, I figured I’d be able to put something together that would be simple enough that I couldn’t put it off any longer, and flexible enough that I might actually want to keep it updated.

Note: I’m just going to document the steps I took to put together a really simple portfolio app. I’m not writing it as a tutorial, so I’m not going to cover a lot of background or fill in the blanks step by step. If you do want to follow along with your own code, I’d suggest you check out Jeff’s intro to Django for non-programmers and run through the Django tutorials first. If you want more information at any point about how something works, you can find it in the official Django documentation.

Step 1. Write the model (10 minutes)

I already have a project for the apps I use on my site, so I started by creating a new application within my project. startapp portfolio

I decided I needed three models to put it together: Project, Client (so I could group projects with the same client) and Medium (web, print, etc.—also for grouping projects). Since I wanted to keep it simple, I could have just used text fields for client and medium, but since those make sense as relationships and it’s easy enough to define them separately up front, I did.

Here’s what my models look like
(I’m linking these out to text files so my post formatting doesn’t crap on the Python indenting.)

Even if you don’t know Python, I bet you can figure out most of what’s going on just by reading the code. I’m defining the three objects and their fields, along with some extra information in the Meta and Admin sections, and some simple functions to tell Django how to refer to the objects by name (using Python’s “repr” object) and URL within the site.

Client has two fields (name and URL). Pretty simple. Medium just has one field (name), but I had to include some extra information so Django knows what the plural of medium. The db_table property gets used to name the database table, and verbose_name_plural is used when referring to groups of objects in the admin interface.

Project has a few more fields, but they’re all pretty simple. Django has a lot of different types of fields for different types of data.

  • Name is a simple character field which will appear as an input in the admin interface.
  • Slug is a special type of field that can only contain lowercase letters and dashes. It’s used in URLs.
  • Project URL is a URL field. Django will check that the URL is valid before saving.
  • Description is a text field, which will appear as a textarea in the admin interface.
  • Client is a foreign key relationship to the Client object we defined earlier. It will appear as a select menu in the admin interface, with a list of all the clients in the system.
  • Media is a “many to many” relationship to the Medium objects, which means we can select more than one medium for each project. (There are many projects related to many media, hence “many to many”.)
  • Disciplines is a simple character field. It could just as well be a many to many relationship to a “discipline” object, but I felt like that was overkill for this project.
  • Completion date is a date field. It will appear as an input in the admin interface, with a calendar widget for choosing a date.
  • In development and Is public are boolean fields (yes or no). They’ll appear as checkboxes in the admin interface.
  • Overview image and Detail image are URLs where I will paste links to the project images. These could easily use Django’s ImageField field type, which would provide a widget for uploading images directly through the admin interface, but since I’m not hosting my media on the same server as my Django setup, so I’ll just use URLs instead.

The get_absolute_url function tells Django how to find each project by its URL on the site. I’ll define the URLs later, but I know now how I want them to work. In this case I want my portfolio URLS to start with /work/ and just stick the slug field for each project on the end as a unique identifier. So an example URL would look like: /work/project-slug/.

I’ve also added an extra field to the Meta section, which tells Django how I want to sort projects when it retrieves them from the database. In this case, I want to keep them ordered reverse chronologically by date published, with the most recent projects first.

That’s all I need, there’s models are done. I’ll even give you time to look up the field types in the docs.

All I have to do now is tell Django to activate the models and reload my web server and log in to the admin interface and voila!

Screenshot of the Django admin interface showing links to add new Projects, Clients or Media.

I’ve got a web interface for adding and editing the objects I just defined. It’s not magic and, just like any language, Django’s model syntax takes some learning and getting used to. It’s not English, but it’s not SQL either.

2. Map the URLs (5 minutes)

So now Django knows what all our objects are. Now it needs to know where to display them when they’re requested on the site. When a user requests the URL for a project on our site, we want them to get the right project or list of projects.

Every Django project has a set of rules that map URL patterns (defined using regular expressions) to views that retrieve objects from the database and display them to the browser through templates. Since we’re using Django’s built-in generic views, all we need to do is tell Django which generic view to use for each URL pattern.

Here’s what the URL patterns look like for the portfolio

Skip the first few lines for now and let’s look at urlpatterns part, specifically the first one.

The first part (before the first comma) is the regular expression to match the requested URL against. In this case the expression is easy, since all I want to match is /work/. I don’t want to match anything but /work/ though, so I do need some regex magic to start the match when it finds “work” and terminate the match after it hits the slash. That way I don’t match /work/stuff/ or /posts/work/ and serve up the wrong view in the wrong place.

The second part specifies the view I want to invoke with the URL I just matched. In this case, I’m using Django’s generic view for object lists. I found out how to specify this view from the generic views docs but it’s in part four of the tutorial as well.

The third part specifies what object I want to display and what template I want to use to display it. These extra arguments are contained in what’s called a dictionary, which in Python is basically just a list of variables and their definitions. In this case I’m referencing an external dictionary, info_dict, which I’ve defined earlier in the file, just above the urlpatterns.

All this dictionary does is get a list of all the projects in the database and assign it to a variable queryset. The object_list generic view looks for that queryset variable to find the objects to display. (The reason I’m defining this in a separate dictionary is because I’ll use the same info again for the next view.)

I’m also adding another variable just for this view, template_name, which specifies which template in our template directory to use to render this view.

The second URL pattern follows the same form. Regular expression to match the URL (/work/ followed by the project slug), the view I want to use (in this case the generic object detail view), and the info dict to pass to the view, with an extra argument telling the detail view which field to use for the slug in the URL.

That’s a lot of explanation for a few lines of code, but you don’t actually need to know any of it. If you’re good at copying and pasting, you can do it this part in three minutes instead of five.

Now, if I reload my web server and bring up one of the URLs I just defined, Django gives me an error page saying template does not exist.

Screenshot of a Django error page saying the template portfolio/project_list does not exist.


Step 3. Make the templates (10 minutes)

Now I’m in the home stretch. This is familiar territory. I can start with a blank file, add my markup and some simple template logic and I’m good to go. If you haven’t already, spend some time with the Django template documentation for HTML authors to get the idea.

I start by creating a template called projects_list.html in a folder called portfolio in my templates directory.

Here’s what my template looks like for the project list

That’s it. This template extends another template called base_work (see the docs for a primer on template inheritance and extension) which includes all my surrounding page markup, so all I need to define here is the content specific to this page.

The object list generic view provides a list of the objects I passed to it (in this case projects) in a variable called object_list. I’m looping through each object in the list, checking if it’s marked as public and displaying the info for each one (but you knew that).

As an added bonus, I can use Django’s template filters to run my content through different transformations. In this case I’m loading a template tag library included with Django called markup ({% load markup %}) and using the filters it provides, in this case Textile.

Step 4. Add style (5 minutes)

OK, I cheated here. I already had most of the style done, so this didn’t take long. But at this point, we’re not even using Django anymore, so you’re kind of on your own. Mileage may vary.

Step 5. Gloat

Check out my new portfolio.

You cheated again! That’s not an app, that’s just one page!

OK, so I kept it really simple. So simple that I’m not even using the detail views I created (yet). By the time I got this far I just couldn’t think of what else I would put on a detail page for each project, and I’m really fond of other people’s portfolios that are all on one page. How very Real™ of me.

But someday I probably will want detail views, and all I’ll have to do is add a template. Archives by date? Three lines of code and three templates. Archives by medium? One line, one template.

What else can you possibly do with generic views?

How about a blog? This entire site is powered by generic views (with some exceptions, including search and the home page, neither of which are too complicated on their own.)

But I can’t make money from a blog!

OK, how about ecommerce? I built this catalog site for a friend of mine with nothing but generic views and a PayPal account. No programmers in sight. Go ahead, buy something. I dare you.

On both of these projects, I spent more time designing and tweaking style and markup than I did writing application code. I’d be ashamed to call it programming.

Sure, it’s not revolutionary functionality, but it’s not something I could have done on my own a year ago with PHP or a hacked-up blog CMS. And the great thing is, I can hand off a project like this to a client (as I did with the jewelry site) with a fully-functioning backend interface with confidence that it’s actually going to work. And I don’t have to split the check with a programmer.

On a completely unrelated note, you might be interested to know that I’ve updated my portfolio for the first time in THREE YEARS.

If you’ve got the generic views bug and you want to know how to really use them to your advantage, check out James Bennett’s tips on how to get the most out of generic views.


  1. 10 May 2006


    Great post. Thanks for shedding some more light on Django for those of us who are unfamiliar with it. Your site and Jeff Croft’s both look and work great.

  2. 11 May 2006

    Adam Messinger

    This makes for a great follow-on to Jeff’s post about Django. The more I learn about this framework, the more I want to get my hands dirty using it.

  3. 11 May 2006

    Joshua Brewer

    This is awesome. I have been following along with you and Jeff’s progress and have just recently dug in and started learning… wow, very cool but also a whole other universe.

    Have you thought about adding an RSS feed for your articles?

    Quick question: is django.db something you had already defined? If so, would you be willing to let us in on how that was built? I learn best by tearing apart…

  4. 11 May 2006

    Wilson Miner

    Joshua: I do have an RSS feed of posts. It’s linked on the homepage, but I should probably add some links on the inside pages too. (The syndication framework in Django makes setting up RSS feeds very easy, by the way.)

    django.db is a core component of Django itself. If you want to really tear things apart, I’d suggest poking around the official documentation or digging in to the tutorials

  5. 15 May 2006


    This is great.

    Combined with open source designs designers aren’t needed either!

  6. 15 May 2006

    Nicola Larosa

    That’s a great intro for non-programmers, and I concur, Django is the first framework I’ve seen that allows one to build (simple) dynamic sites without writing code.

    However, as a programmer, I take exception with your statement ‘…views are where what programmers like to call “business logic” happens…’. Actually, they’re not. :-)

    Business logic is supposed to live near the data. It defines the evolution that the data goes through.

    Views are just, well, views: they take the data and generate a web representation for them, parameterized with the URL (and the request). They contain logic, but it’s just for representation’s sake: it should not affect the data.

    Think about using the data for a 3-D world, or from the command prompt: these are just different representations, the data should be kept correct and consistent, no matter what their representation is.

    Apart from that quibble, a great article.

    (mmh, the preview’s not working, let’s hope for the best :-) )

  7. 15 May 2006

    kenneth gonsalves

    I am a programmer - tend to look down on design weenies (but am secretly envious of their skills). I am now openly envious of yours, and this has given me a handle on how programming looks like from the other side. I now know how to involve the design people more actively in my projects.

  8. 15 May 2006

    Wilson Miner

    Nicola: I obviously don’t really know what I’m talking about, but my understanding about Django was that in Django what is called the “view” contains some of what might be called the “controller” in more pure MVC systems. I still might be wrong in calling it “business logic”, but I think it’s more than just representational logic (some of which actually happens in the template).

  9. 15 May 2006


    Nicola: well, Wilson is right here. Django is not a pure MVC framework, but as they define it, a Model-View-Template. Here the View would be the Controller and the Template the View, more or less, so the logic goes on their “view”.

    Maybe a not much fortunate choice on names if you come with an MVC idea, but it’s that way. More info about that on Django’s own site.

  10. 15 May 2006

    An Onymouse

    Great primer Wison, you have gone over some things which have driven me up the wall regarding the magic of django.

    I would still like someone to explain the so called regexes which you are using. Most django tutorials just mention the fact that it is a regex and leave it at that.

    I’m trying to understand why the first one will match only /work/ and the other will match /work/ ??

    What exactly does ‘^work/(?P[-w]+)/$’ match? can you give some sample url patterns which this will match? what does ?P mean? Could you have put ?P[-w]+/$ and that would have still matched the slug because you are defining the extra field in the dict part? or does the part have to match the field which is extra in the dict part?

    I think you guys need to have some convention in these Django for non-programmer tutorials where the “magic” (I know you’ve de-magic-fied it but still its magic for us clueless ones) parts are identified by the Django signature green color or something.

    for example, does the info_dict part have to have “queryset” key or can it be anything? if Django requires it to be key, perhaps it could be colorcoded as a “django keyword” or something like that?

    right now its hard to tell what you defined arbitrarily, or what one can define arbitrarily and the bits which are required by Django for the generic views to work properly.

    I now understand what this info_dict thingy is all about (and that’s no small feat). A lot of tutorials have sort of glossed over it, but for designers and non-programmers these can quickly become annoynces.

    Thanks for a great writeup!

  11. 15 May 2006

    An Onymouse

    Sorry for the regex mixup. I was trying to ask what the second regex exactly do? ie; what do all those different parts in it are supposed to match?

    I’d appreciate it if someone could explain this for me! thx.

    p.s. the preview on this comment form is broken it seems.

  12. 15 May 2006

    Wilson Miner

    Anonymouse: If you want more detailed information about what’s going on behind the scenes in the URL configuration, I’d suggest taking a look through the Django documentation on the subject. It covers the topics you asked about in detail (see the notes on raw strings and named groups), which I didn’t do here.

    Also, the generic views documentation should give you a better idea of where the @info_dict@ and the @queryset@ variable came from.

    Tutorials and intros are great to get a quick start, but for going “behind the magic”, there’s no substitute for the real thing. Extensive documentation is one of Django’s strengths—don’t forget about it!

  13. 17 May 2006

    James Wheare

    Hi Wilson,

    Another designer here.

    A quick skim of this article and Jeff’s tutorials were the shunt I needed to get stuck in with Django. I think this is the answer to a side project I’ve had on the go for more than 2 years now. Thanks!

    Tried Rails. Hit a wall. Bought the book. Stalled. Hooray for good, friendly documentation!

    I’d recommend any other newbies out there follow the tutorials. Two days ago I’d never touched Python; I’ve now written my first toy Django app and feel pretty confident I’ll be able to churn out a useful one in no time!

    I might write a tutorial for setting up a development system though, it took me a bit of flumoxing to get everything sorted on OS X. Probably my own fault but it could do with some explicit clarification.

    A question about your portfolio code:

    In your first urls pattern, is it redundant to specify the template_name? Doesn't the object_list generic view automatically look in <app>/<module>_list.html for the template?

    Also, a slight correction (I think):

    The object detail generic view provides a list of the objects I passed to it (in this case projects) in a variable called `object_list`.

    Should that be “The object list generic view”?

    Awesome write-up Wilson, if only all open-source projects had such effective advocates :)

  14. 17 May 2006

    Wilson Miner


    In your first urls pattern, is it redundant to specify the template_name? Doesn't the object_list generic view automatically look in <app>/<module>_list.html for the template?

    Yes, you’re absolutely right. I’m just in the habit of declaring the template name in the urlpattern so I don’t have to look it up. I have some other non-generic views in the same list, so I like to have all the templates there for reference.

    Should that be “The object list generic view”?

    It should indeed. Good catch—thanks!

  15. 17 May 2006

    An Onymous

    Thanks Wilson, I checked the docs as you mentioned, it makes more sense now. Again, excellent tutorial!

  16. 17 May 2006


    Wilson — between you and Jeff, boy, am I amped to try out Django sometime soon. It seems like the perfect tool for doing what I need to do. So thanks for that.

    And on another belated note: dig the redesign. It’s a nice evolution of the old site.

  17. 18 May 2006

    John H

    How come this fine write-up doesn’t appear on (or the associated RSS feed)?

    I found it by accidentally when reading

    I’d like to strongly encourage the consistent keeping/aggregation of all this good stuff in one place.

  18. 19 May 2006

    Wilson Miner

    John H: The only reason I hadn’t added it yet is that I didn’t have feeds per category. Which took me about 2 minutes to set up. Should be showing up in the Django community aggregator shortly. Thanks for the tip!

  19. 23 May 2006

    Armin Ronacher

    from django.db import Models should be from django.db import models

    But nice blog post anyway :)

  20. 26 May 2006

    Will Henderson

    I dabbled with Rails back when it first came out, but wasn’t terribly impressed or excited. That’s probably more of a reaction to dealing with a framework though than a judgement on Rails.

    I’m interested to give Django a spin, but at the end of the day I think I’m a little more of a programmer than a designer, and I actually ENJOY the process of creating a system from the ground up each time. PHP makes sense to me while fameworks that serve as middlemen for function don’t.

    But I realize that may be an atypical point of view.

    Thanks for the step by step overview of the process - it was an interesting read.

  21. 1 June 2006

    Chris H

    Great write up. And beautiful designs. The wedding invitations were stunning. But back to Django, I was involved in a similar project recently and there are a couple of little traps in the templates if you are using latest SVN of Django. First, with a ForeignKeyField you can get it with, a small change. Second, with a ManyToManyField you have to set up a for loop, (for medium in, then get the name of each medium with and close with an endfor. It probably took me half any hour to figure that out. Thanks for the inspiration.

  22. 5 June 2006


    Another designer checking in….

    Wow, I’m really tempted to give this whole Django thing a shot now!

    Nice article. Hope it’s as easy as it looks

  23. 5 August 2006

    Werner Hartnagel

    Hi Chris,

    i think u made a typo and u mean:

    {% for medium in %}

    {{ }}
    {% endfor %}

  24. 18 August 2006


    That’s really what I was looking for for my upcoming blog. Thanks for the great article and keep up the good writing! :)

  25. 5 September 2006


    I’ve been looking at Django for a while - I’m currently using MT (new blog:… but Django looks at lot more functional. I think I’ll read up more then decide.

    Nice article.

  26. 1 October 2006

    Jim Moses

    This is VERY cool! But did I miss the explanation of the detail template somewhere? I see the list template and the “call” in the for the list.html…but no similar detail template?

    Also, can you show how the list can be designed to provide entry clicking to bring up a detail template?


  27. 9 October 2006


    Shouldn’t def repr(self): return


    def str(self): return

    My admin didn’t display names correctly until I changed repr to str.

  28. 30 December 2006


    I keep getting an error saying that “User tampered with cookie,” what is wrong with what I am doing if you know? Not only this project but others I try to do as am slowly learning django.. Great tutorial though, really helped me along and learn about django and will soon be able to write my own app and consequently have something decent to show on the web…

  29. 31 December 2006


    Wait got it going properly, keep forgetting to delete cookies :) Anyways great tutorial, keep up the good work!!!!!

  30. 6 January 2007



    I come from the programmer’s side of the fence but I have a deep appreciation for fine graphics work — yours is spectacular. With Django, it’s not the View or Model code that trips me up, it’s the templates.

    I was wondering if you would be so kind as to reveal your process for creating templates. For example, do you use a WYSIWYG tool such as GoLive or Dreamweaver as a starting point? Do you mock-up your pages first?

  31. 6 February 2007

    Andy Skogrand

    Every time a django tutorial comes out, I jump right on it and then do a little dance when I complete it without too much hassle. I got to do a little jig tonight, thanks Wilson.

    Is there any filter you can place in the templates to limit the number of entries displayed in the loop? Let’s say if you had nine portfolio items, but you only wanted six to display?