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
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.
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?
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.