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 Initialized empty Git repository in /Users/josh/Dropbox/Projects/jakt-django-example/.git/
$: 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?
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
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
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
fronted to our
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
$: 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
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.
r'' piece inside
jakt/urls.py is a regular expression that says “anything that matches this, send to the url patterns located in
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.
# 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!')
home is matched with the url route in
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'), )
patterns('frontend.views' we save having to write
Want to test out this url route the old fashioned way? Open up a python shell using Django’s
$: 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.