Starting with Django

I hate classifying ourselves as a “Django shop” but the reality is a lot of our work is done with Django. We made this decision in October after landing a client that needed something beyond our current setup of web.py or Pyramid.1

After spending ~2,000 hours (conservative estimate) developing applications with Django I wanted to write out some basic steps to getting a Django application up and off the ground.

Want to follow along? Purchase the Starting with Django Source Files

What You’ll Need

  • A computer running some form of Unix
  • Python 2.7
  • pip
  • git

Structuring Your Project

Our basic app directory structure looks like this (showing folders on top level only):

- jakt/
  - manage.py
  - an_app/
    - models.py
    - urls.py
    - views.py
    - …
- templates/
  - layouts/
    - base_layout.html
  - an_app/
    - some_template.html
- static/
  - css/
  - js/
  - images/

Main App vs Other Apps

Django compartmentalizes functionality through apps. I haven’t gotten to the point where I’m crafting completely reusable apps2, but in a nutshell apps contain url routes, view functions, and models to act on. You add apps to the INSTALLED_APPS tuple to activate them and tell Django that it needs to load urls and models from this app.

I put everything under a folder called jakt so it cleans up the main repository directory. I also put templates and static files at that same level so they can be accessed separately from the apps themselves. Often the apps remain similar while the templates and assets change around them.

Starting Django With Nothing

Let’s walk through starting a Django application without having anything pre-existing.

Create a folder to store this app. Call it something fun like jakt-django-example. Then switch into this directory.

$: mkdir jakt-django-example
$: cd jakt-django-example

Initialize a git repository here using git init.

$: git init
Initialized empty Git repository in /Users/josh/Dropbox/Projects/jakt-django-example/.git/

Add a .gitignore file to ignore any compiled python files and the virtual environment we’ll be setting up.

$: echo "*.pyc\nvenv" > .gitignore
$: cat .gitignore
*.pyc
venv

Create a virtual environment and activate it.

$: virtualenv venv
New python executable in venv/bin/python
Installing setuptools............done.
Installing pip...............done.
$: source venv/bin/activate

Install Django using pip.

$: pip install django
Downloading/unpacking django
  Downloading Django-1.5.1.tar.gz (8.0MB): 8.0MB downloaded
  Running setup.py egg_info for package django
Installing collected packages: django
  Running setup.py install for django
    changing mode of build/scripts-2.7/django-admin.py from 644 to 755
    changing mode of /Users/josh/Dropbox/Projects/jakt-django-example/venv/bin/django-admin.py to 755
Successfully installed django
Cleaning up...

Now you have Django. Feels nice doesn’t it?

Wait, what about making it all work?

Of course it works. Try this out:

>>> import django
>>> django.VERSION
(1, 5, 1, 'final', 0)

That isn’t working. Where’s the actual site?

Oh. Right.

Starting A Project

Here we’re going to start a project called jakt, start an app called frontend, configure some url routes, and return some trivial HttpResponse objects.

I like to put everything Django related inside it’s own top level folder in the repo.

$: django-admin.py startproject jakt
$: cd jakt
$ ls
drwxr-xr-x  6   204 May 31 00:01 jakt/
-rw-r--r--  1   247 May 31 00:01 manage.py
$ ls jakt/
-rw-r--r--  1      0 May 31 00:01 __init__.py
-rw-r--r--  1   5344 May 31 00:01 settings.py
-rw-r--r--  1    550 May 31 00:01 urls.py
-rw-r--r--  1   1413 May 31 00:01 wsgi.py

What’s this app called jakt? That’s Django’s main entry point. It contains your settings, initial url routes, and the wsgi configuration.

Now we need to create an app called frontend.

$: pwd
/Users/josh/Dropbox/Projects/jakt-django-example/jakt
$: python manage.py startapp frontend
$: ls frontend/
total 24
drwxr-xr-x  6   204 May 31 00:16 ./
drwxr-xr-x  5   170 May 31 00:16 ../
-rw-r--r--  1     0 May 31 00:16 __init__.py
-rw-r--r--  1    57 May 31 00:16 models.py
-rw-r--r--  1   383 May 31 00:16 tests.py
-rw-r--r--  1    26 May 31 00:16 views.py

Add fronted to our INSTALLED_APPS inside jakt/settings.py. It should look like this:

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'frontend', # <--- This is what you added
    # Uncomment the next line to enable the admin:
    # 'django.contrib.admin',
    # Uncomment the next line to enable admin documentation:
    # 'django.contrib.admindocs',
)

Add this to our urls routes inside jakt/urls.py. It should look like this:

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

# Uncomment the next two lines to enable the admin:
# from django.contrib import admin
# admin.autodiscover()

urlpatterns = patterns('',
    # Examples:
    # url(r'^$', 'jakt.views.home', name='home'),
    # url(r'^jakt/', include('jakt.foo.urls')),
    url(r'^', include('frontend.urls')),

    # Uncomment the admin/doc line below to enable admin documentation:
    # url(r'^admin/doc/', include('django.contrib.admindocs.urls')),

    # Uncomment the next line to enable the admin:
    # url(r'^admin/', include(admin.site.urls)),
)

You can remove the example and admin/doc lines to clean it up:

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

urlpatterns = patterns('',
    url(r'^', include('frontend.urls')),
)

Now create a file called urls.py inside frontend.

$: pwd
/Users/josh/Dropbox/Projects/jakt-django-example/jakt
$: touch frontend/urls.py

Add a route to frontend/urls.py that points to home. It should look like this:

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

urlpatterns = patterns('frontend.views',
    url(r'^$', 'home'),
)

Add a function called home to frontend/views.py. It should look like this:

from django.http import HttpResponse

def home (request):
    return HttpResponse('This is a Django app. Hello!')

Now run the built-in server to see your app:

$: pwd
/Users/josh/Dropbox/Projects/jakt-django-example/jakt
$: python manage.py runserver
Validating models...

0 errors found
May 30, 2013 - 23:25:56
Django version 1.5.1, using settings 'jakt.settings'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

Load up http://127.0.0.1:8000/ in your browser and you should see this.

This is a Django app. Hello!

In the terminal you should see this log line appear:

[30/May/2013 23:22:17] "GET / HTTP/1.1" 200 28

Explaining URLs

How do these url routes work in Django?

A url is a uniform resource locator. This is sent to the server and tells it what the browser is looking for. Urls in Django are chainable, and this is a great example.

jakt/urls.py:

url(r'', include('frontend/urls.py)),

The r'' piece inside jakt/urls.py is a regular expression that says “anything that matches this, send to the url patterns located in frontend/urls.py.

frontend/urls.py:

url(r'^$', 'home'),

Here r'^$' is a regular expression that matches anything empty. A / matches, see the above log line.

What if you put something in that doesn’t match?

Page not found at /nomatch

With the corresponding log line:

[30/May/2013 23:45:28] "GET /nomatch HTTP/1.1" 404 1956

Django searched the only url defined (^ ^$) and couldn’t find a match. This caused a 404 error to be sent.3

Explaining View Functions

What is executed when for a given url route?

A view function gets executed when a matching url route is called.

frontend/views.py:

# Import `HttpResponse` which allows us to send a simple string
# back to the browser
from django.http import HttpResponse

# Declare a function called `home` that takes a single argument
# `request` and returns an `HttpResponse`.
def home (request):
    return HttpResponse('This is a Django app. Hello!')

This function home is matched with the url route in frontend/urls.py.

urlpatterns = patterns('frontend.views',
    # The second argument here ('home') is the name of
    # the function we want executed when this url route
    # is triggered.
    url(r'^$', 'home'),
)

By writing patterns('frontend.views' we save having to write url(r'^$', 'frontend.views.home').

Want to test out this url route the old fashioned way? Open up a python shell using Django’s manage.py:

$: pwd
/Users/josh/Dropbox/Projects/jakt-django-example/jakt
$: python manage.py shell
>>>

Now we can import the home function from frontend.views and use it.

>>> from frontend.views import home
>>> response = home(None)
>>> type(response)
<class 'django.http.response.HttpResponse'>
>>> response.status_code
200
>>> response.content
'This is a Django app. Hello!'

That is your simple Django app. It’s more minimalistic than the [Writing your first Django app, part 1][1.5 tutorial], but I’ll continue this with more work on templating, layouts, and developing a Django skeleton that will make this initial config simpler.

You can purchase the Starting with Django Source Files This helps us gauge interest in the source files and material we provide.


  1. I also hate the connotation that we’re a Python shop, but reality is… ↩︎

  2. Which is why the templates/ dir is outside the jakt/ main app. ↩︎

  3. Note that these error pages will only appear when DEBUG is set to True in your settings.py. DEBUG should always be False in production. ↩︎

written May 30th, 2013

May 2013

Can’t find what you’re looking for? Try hitting the home page or viewing all archives.