Intro to Django — Part 4

Django 1.3 edition

Steven F. Lott


Code Kata

Review: Model, View


Dynamic Content and Templates

Generic List/Detail Views

Code Kata

Simple Inventory of ingredients, recipes and locations.


Use Case



Model Code

from django.db import models

class Ingredient( models.Model ):
    name = models.CharField( max_length=64 )
    safety = models.CharField( max_length=64 )

UNITS = ( ("ea.","Each"), ("lb.","Pounds"), ("qt.","Quarts") )

class OnHand( models.Model ):
    ingredient = models.ForeignKey( Ingredient )
    count = models.FloatField( )
    units = models.CharField( max_length=64, choices=UNITS )


Several standard pieces to a handling a request.

Common Aspects:

All those interlocking pieces and parts...


Three parts:

Template File

Best to use a "base" template for the overall page structure.

{% extends "base.html" %}

Often a good idea to keep the "base" outside any specific application.

Example base.html

<?xml version="1.0" encoding="utf-8"?>
<html xmlns="" xml:lang="en">
<div id="body">
{%block body%}

Other Stuff

Your .CSS, .JS and .PNG's are just static files.

They're referenced in your HTML.

They reside on your Apache server.

They're downloaded by Apache outside Django.

The STATIC_URL setting must match your Apache configuration.

The {% Tags

Django template tags.

Lots and lots of features for decisions, iteration, and some reformatting.

This is not the wild-west (i.e. JSP or PHP)

This is only presentation.

The {%block%} Tag

A "place-holder" block of HTML.

A template that {%extends%} this may replace the block.

If a block isn't replaced, the default value will be rendered.

Keep it Simple.

"Real" processing happened in the view function.

Example home.html

{% extends "base.html"%}
{% block body %}
<p><a href="{%url tutorial.inventory.views.ingredient%}">Ingredients</a></p>
{% endblock %}

All global layout changes in base.html

Any local changes in home.html

The {%url%} Tag

{%url tutorial.inventory.views.ingredient%}

Seriously cool.

This maps the view function name (ingredient) backwards through to create the URL path.

Creates the correct path to invoke the given view function.

Never "hard-code" a URL path.

Don't Repeat Yourself.

Rendering A Template

def home( request ):
    return render( request, "home.html" )



Run the developer server.

./ runserver

Runs a Django service on

HTTP Request → url pattern match → view function → HTTP Response.


You'll want to change the title and the branding.

These are template blocks that you can override.

The words Site administration is hard-wired into admin.sites module AdminSites.index().

Dynamic Content and Templates

Parse the URL path and capture data values.


Three steps:

  1. Parsing Rules in
  2. View Function Parameters in
  3. More Data in Templates

Parsing Rules

from django.conf.urls.defaults import patterns, include, url

urlpatterns = patterns('tutorial.inventory.views',
    url(r'^$', 'home' ),
    url(r'^ingredient/(?P<name>.*?)/$', 'ingredient' ),
    url(r'^ingredient/$', 'ingredient' ),
    #url(r'^location/$', 'location' ),
    #url(r'^onhand/$', 'on_hand' ),

/(?P<name>.*?)/ part of the path captured as name; a named argument to the view function.

View Function Parameters

def ingredient( request, name=None ):
    if name:
        data = Ingredient.objects.filter(
            name__icontains=name )
        return render( request, "ingredient_detail.html",
            {'objects':data, 'name':name}, )
        data = Ingredient.objects.all()
        return render( request, "ingredient_list.html",
            {'objects':data, 'name':'All'}, )

More Data in Templates

{% extends "base.html"%}
{% block body %}
<p>Ingredients {{name}}<p>
    {%for ing in objects%}
      <td>{%if ing.perishable %}Perishable{%endif%}</td>
{% endblock %}

The {{variable}} Notation

Looks up the variable in the page context.

There's a obj.attr notation to get attributes of an object.

The ORM manages attribute references as SQL SELECT columns.

Also, you can use Python @property decorator to evaluate simple (no argument) methods of a model class.

ingredient_detail.html Template

{%for ing in objects%}
{%if ing.perishable %}<p>Perishable</p>{%endif%}
    {%for oh in ing.onhand_set.all%}

Object References and Navigation

objects is an iterator over Ingredient instances.

ing is an Ingredient instance.

for oh in ing.onhand_set.all is an iterator over all OnHand instances.

oh is an an OnHand instance

oh.location is a Location instance

Lazy fetches from the database. Works with Paginator.

Role-Specific Navigation


  1. Define a Profile to carry additional properties and attributes of each User.
  2. Update Settings to use the Profile.
  3. Customize Links based on the Profile.

Define A Profile


from django.contrib.auth.models import User
class Profile( models.Model ):
    user= models.OneToOneField( User )
    def is_galley( self ):
        return self.ingroup( 'galley' )
    def ingroup( self, name ):
        return name in (
                for g in self.user.groups.all())

Update Settings

Must tweak settings to use our profile

AUTH_PROFILE_MODULE = 'inventory.Profile'

Profile Objects for Users

>>> from django.contrib.auth.models import User
>>> User.objects.all()
[<User: slott>, <User: cookie>]
>>> slott, cookie = _
>>> slott.get_profile()
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/Django-1.3-py2.6.egg/django/contrib/auth/", line 383, in get_profile
    self._profile_cache = model._default_manager.using(self._state.db).get(
  File "/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/Django-1.3-py2.6.egg/django/db/models/", line 349, in get
    % self.model._meta.object_name)
DoesNotExist: Profile matching query does not exist.

Create Profile Objects

>>> from inventory.models import Profile
>>> Profile.objects.create( user=slott )
<Profile: >
>>> Profile.objects.create( user=cookie )
<Profile: galley>

Generic List/Detail Views

I'm already tired of repeating myself.

Many view functions are very simple-minded.

Why repeat this boilerplate?

Generic Views.

Simple Generic View

from tutorial.inventory.models import Location
from django.views.generic import ListView


No code at all. Just a template.

Typical Generic View

from tutorial.inventory.models import Location
from tutorial.inventory.views import Location_Filter
from django.views.generic import ListView

    name='location' ),

Typical Generic Views

Subclass the built-in ListView to provide a get_queryset method.

from django.views.generic import ListView

class Location_Filter( ListView ):
    model= Location
    def get_queryset( self, **args ):
        return self.model.objects.filter(
            name__icontains=self.kwargs['name'] ).all()

Now that we have a named location...

{%url location}


We provide a URL name for a generic view.

With a tiny bit of planning (and a naming convention) we can assure that our data is throughly linked.

Without hard-coding a single URL.


We're not even close to done with the Django feature set.