Intro to Django — Part 1

Django 1.3 edition

Steven F. Lott


Install, Philosophy, Code Kata

Basic Model, Database Implementation, Navigation

Next Parts: View, Presentation, and more



Assume Python 2.6

sudo easy_install-2.6 django

That was fun.

Check your PATH environment variable to be sure you have access to the Django script:

Bigger Install

For scalability and security, you'll usually do this.


Plus handy middleware and settings


"Convention over Configuration"

"Don't Repeat Yourself"

What About?

Javascript and CSS?

Static media?

Code Kata

Simple Inventory of ingredients, recipes and locations.


Use Case



Getting Started

  1. Create the "Site".
  2. Create an "App".
  3. Configure the settings.
  4. Define model and tests.
  5. Sync the DB.

What's a "site"?

For simple applications it could be the entire Apache server.

Or. Multple sites on a single server (virtual host configuration).

Or. Site spread across multiple servers (highly scalable).

This is all Apache and mod_wsgi configuration.

What's an "app"?

The Django unit of reuse.

App = Model + View is the minimum.

Separate site-specific templates.

App = Model + View + Template is typical.

App = Model + Forms + Admin + View + Template + Tests

All neatly separated to permit reuse and customization

Let's start a project

Handy getting started utility. startproject tutorial

Creates a tutorial directory with some boilerplate files.

Add an app to a project

Often, we'll have many resuable apps within a larger web site.

cd tutorial
./ startapp inventory

Creates the inventory directory with some boilerplate files.


Many, many settings. For now, we'll look at a few

Model Code 1

from django.db import models

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

Class with attributes.

Model Code 2

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 )

Class with foreign key reference to another class.

Also, use of choices to populate drop-downs in admin forms.

Build the DB

./ syncdb


That's it

Play Time

./ syncdb
./ shell

Now you have interactive acccess to DB via Django ORM.


>>> from inventory.models import Ingredient
>>> Ingredient.objects.all()
>>> Ingredient.objects.create( name="lime" )
<Ingredient: Ingredient object>
>>> Ingredient.objects.create( name="coconut" )
<Ingredient: Ingredient object>
>>> Ingredient.objects.all()
[<Ingredient: Ingredient object>, <Ingredient: Ingredient object>]

Hmm... <Ingredient: Ingredient object> Ugly.

Fix the Model

Add __unicode__ methods to make model instances show something useful

class Ingredient( models.Model ):
    name = models.CharField( max_length=64 )
    perishable = models.BooleanField()
    def __unicode__( self ):

How's This?

>>> from inventory.models import Ingredient
>>> Ingredient.objects.all()
[<Ingredient: lime>, <Ingredient: coconut>]
>>> [ for i in Ingredient.objects.all() ]
[u'lime', u'coconut']

We can live with that.

Test the Model

from django.utils import unittest
class TestOnHand( unittest.TestCase ):
    def setUp( self ):
        self.gin, _ = Ingredient.objects.get_or_create( name="gin", perishable=False )
        self.ginger_ale, _ = Ingredient.objects.get_or_create( name="ginger ale", perishable=False )
        self.lime, _ = Ingredient.objects.get_or_create( name="lime", perishable=True )
        self.cooler, _ = Location.objects.get_or_create( name="galley cooler", side="port" ), _ = Location.objects.get_or_create( name="saloon", side="starboard" )
        OnHand.objects.get_or_create( ingredient=self.gin,, count=.75, units="l" )
        OnHand.objects.get_or_create( ingredient=self.ginger_ale, location=self.cooler, count=6, units="ea." )
        OnHand.objects.get_or_create( ingredient=self.lime, location=self.cooler, count=2, units="ea." )
    def test_should_inventory( self ):
        self.assertEqual( 3, OnHand.objects.count() )


./ test inventory
Creating test database for alias 'default'...
Ran 4 tests in 0.039s

Destroying test database for alias 'default'...

Database Implementation

The ORM does many, many things for us.

Database Migration

The ORM cannot, however, handle schema migration.

When you make a schema change, Django can't (and won't) modify an existing table.

How It Works

Django ORM added a bunch of navigation methods to our classes.

OnHand had ingredient which will fetch from the DB.

Ingredient, it turns out, has an attribute onhand_set.

>>> from tutorial.inventory.models import Ingredient
>>> Ingredient.objects.get( name='lime' )
<Ingredient: lime>
>>> lime= _
>>> lime.onhand_set.all()
[<OnHand: 3.0 ea. lime port Cooler>]

How Much Code I Wrote


What To Do

  1. Populate objects manually.
  2. Play interactively.
  3. Use dumpdata to preserve test fixtures.
  1. Write formal unit tests.


Several pieces to view functions.

All those interlocking pieces and parts


Several pieces to presentation.

Next Parts


Presentation, Dynamic Content

Admin Pages (Batteries Included)


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