| 1 |
================== |
|---|
| 2 |
Django at a glance |
|---|
| 3 |
================== |
|---|
| 4 |
|
|---|
| 5 |
Because Django was developed in a fast-paced newsroom environment, it was |
|---|
| 6 |
designed to make common Web-development tasks fast and easy. Here's an informal |
|---|
| 7 |
overview of how to write a database-driven Web app with Django. |
|---|
| 8 |
|
|---|
| 9 |
The goal of this document is to give you enough technical specifics to |
|---|
| 10 |
understand how Django works, but this isn't intended to be a tutorial or |
|---|
| 11 |
reference. Please see our more-detailed Django documentation_ when you're ready |
|---|
| 12 |
to start a project. |
|---|
| 13 |
|
|---|
| 14 |
.. _documentation: http://www.djangoproject.com/documentation/ |
|---|
| 15 |
|
|---|
| 16 |
Design your model |
|---|
| 17 |
================= |
|---|
| 18 |
|
|---|
| 19 |
Start by describing your database layout in Python code. Django's data-model API |
|---|
| 20 |
offers many rich ways of representing your models -- so far, it's been |
|---|
| 21 |
solving two years' worth of database-schema problems. Here's a quick example:: |
|---|
| 22 |
|
|---|
| 23 |
class Reporter(meta.Model): |
|---|
| 24 |
full_name = meta.CharField(maxlength=70) |
|---|
| 25 |
|
|---|
| 26 |
def __repr__(self): |
|---|
| 27 |
return self.full_name |
|---|
| 28 |
|
|---|
| 29 |
class Article(meta.Model): |
|---|
| 30 |
pub_date = meta.DateTimeField() |
|---|
| 31 |
headline = meta.CharField(maxlength=200) |
|---|
| 32 |
article = meta.TextField() |
|---|
| 33 |
reporter = meta.ForeignKey(Reporter) |
|---|
| 34 |
|
|---|
| 35 |
def __repr__(self): |
|---|
| 36 |
return self.headline |
|---|
| 37 |
|
|---|
| 38 |
Install it |
|---|
| 39 |
========== |
|---|
| 40 |
|
|---|
| 41 |
Next, run the Django command-line utility. It'll create the database tables for |
|---|
| 42 |
you automatically, in the database specified in your Django settings. Django |
|---|
| 43 |
works best with PostgreSQL, although we've recently added beta MySQL |
|---|
| 44 |
support and other database adapters are on the way:: |
|---|
| 45 |
|
|---|
| 46 |
django-admin.py install news |
|---|
| 47 |
|
|---|
| 48 |
Enjoy the free API |
|---|
| 49 |
================== |
|---|
| 50 |
|
|---|
| 51 |
With that, you've got a free, and rich, Python API to access your data. The API |
|---|
| 52 |
is created on the fly: No code generation necessary:: |
|---|
| 53 |
|
|---|
| 54 |
# Modules are dynamically created within django.models. |
|---|
| 55 |
# Their names are plural versions of the model class names. |
|---|
| 56 |
>>> from django.models.news import reporters, articles |
|---|
| 57 |
|
|---|
| 58 |
# No reporters are in the system yet. |
|---|
| 59 |
>>> reporters.get_list() |
|---|
| 60 |
[] |
|---|
| 61 |
|
|---|
| 62 |
# Create a new Reporter. |
|---|
| 63 |
>>> r = reporters.Reporter(full_name='John Smith') |
|---|
| 64 |
|
|---|
| 65 |
# Save the object into the database. You have to call save() explicitly. |
|---|
| 66 |
>>> r.save() |
|---|
| 67 |
|
|---|
| 68 |
# Now it has an ID. |
|---|
| 69 |
>>> r.id |
|---|
| 70 |
1 |
|---|
| 71 |
|
|---|
| 72 |
# Now the new reporter is in the database. |
|---|
| 73 |
>>> reporters.get_list() |
|---|
| 74 |
[John Smith] |
|---|
| 75 |
|
|---|
| 76 |
# Fields are represented as attributes on the Python object. |
|---|
| 77 |
>>> r.full_name |
|---|
| 78 |
'John Smith' |
|---|
| 79 |
|
|---|
| 80 |
# Django provides a rich database lookup API that's entirely driven by keyword arguments. |
|---|
| 81 |
>>> reporters.get_object(id__exact=1) |
|---|
| 82 |
John Smith |
|---|
| 83 |
>>> reporters.get_object(full_name__startswith='John') |
|---|
| 84 |
John Smith |
|---|
| 85 |
>>> reporters.get_object(full_name__contains='mith') |
|---|
| 86 |
John Smith |
|---|
| 87 |
>>> reporters.get_object(id__exact=2) |
|---|
| 88 |
Traceback (most recent call last): |
|---|
| 89 |
... |
|---|
| 90 |
django.models.news.ReporterDoesNotExist: Reporter does not exist for {'id__exact': 2} |
|---|
| 91 |
|
|---|
| 92 |
# Lookup by a primary key is the most common case, so Django provides a |
|---|
| 93 |
# shortcut for primary-key exact lookups. |
|---|
| 94 |
# The following is identical to reporters.get_object(id__exact=1). |
|---|
| 95 |
>>> reporters.get_object(pk=1) |
|---|
| 96 |
John Smith |
|---|
| 97 |
|
|---|
| 98 |
# Create an article. |
|---|
| 99 |
>>> from datetime import datetime |
|---|
| 100 |
>>> a = articles.Article(pub_date=datetime.now(), headline='Django is cool', article='Yeah.', reporter_id=1) |
|---|
| 101 |
>>> a.save() |
|---|
| 102 |
|
|---|
| 103 |
# Now the article is in the database. |
|---|
| 104 |
>>> articles.get_list() |
|---|
| 105 |
[Django is cool] |
|---|
| 106 |
|
|---|
| 107 |
# Article objects get API access to related Reporter objects. |
|---|
| 108 |
>>> r = a.get_reporter() |
|---|
| 109 |
>>> r.full_name |
|---|
| 110 |
'John Smith' |
|---|
| 111 |
|
|---|
| 112 |
# And vice versa: Reporter objects get API access to Article objects. |
|---|
| 113 |
>>> r.get_article_list() |
|---|
| 114 |
[Django is cool] |
|---|
| 115 |
|
|---|
| 116 |
# The API follows relationships as far as you need. |
|---|
| 117 |
# Find all articles by a reporter whose name starts with "John". |
|---|
| 118 |
>>> articles.get_list(reporter__full_name__startswith="John") |
|---|
| 119 |
[Django is cool] |
|---|
| 120 |
|
|---|
| 121 |
# Change an object by altering its attributes and calling save(). |
|---|
| 122 |
>>> r.full_name = 'Billy Goat' |
|---|
| 123 |
>>> r.save() |
|---|
| 124 |
|
|---|
| 125 |
# Delete an object with delete(). |
|---|
| 126 |
>>> r.delete() |
|---|
| 127 |
|
|---|
| 128 |
A dynamic admin interface: It's not just scaffolding -- it's the whole house |
|---|
| 129 |
============================================================================ |
|---|
| 130 |
|
|---|
| 131 |
Once your models are defined, Django can automatically create an administrative |
|---|
| 132 |
interface -- a Web site that lets authenticated users add, change and |
|---|
| 133 |
delete objects. It's as easy as adding an extra ``admin`` attribute to your |
|---|
| 134 |
model classes:: |
|---|
| 135 |
|
|---|
| 136 |
class Article(meta.Model): |
|---|
| 137 |
pub_date = meta.DateTimeField() |
|---|
| 138 |
headline = meta.CharField(maxlength=200) |
|---|
| 139 |
article = meta.TextField() |
|---|
| 140 |
reporter = meta.ForeignKey(Reporter) |
|---|
| 141 |
class META: |
|---|
| 142 |
admin = meta.Admin() |
|---|
| 143 |
|
|---|
| 144 |
The philosophy here is that your site is edited by a staff, or a client, or |
|---|
| 145 |
maybe just you -- and you don't want to have to deal with creating backend |
|---|
| 146 |
interfaces just to manage content. |
|---|
| 147 |
|
|---|
| 148 |
Our typical workflow at World Online is to create models and get the admin sites |
|---|
| 149 |
up and running as fast as possible, so our staff journalists can start |
|---|
| 150 |
populating data. Then we develop the way data is presented to the public. |
|---|
| 151 |
|
|---|
| 152 |
Design your URLs |
|---|
| 153 |
================ |
|---|
| 154 |
|
|---|
| 155 |
A clean, elegant URL scheme is an important detail in a high-quality Web |
|---|
| 156 |
application. Django lets you design URLs however you want, with no framework |
|---|
| 157 |
limitations. |
|---|
| 158 |
|
|---|
| 159 |
To design URLs for an app, you create a Python module. For the above |
|---|
| 160 |
Reporter/Article example, here's what that might look like:: |
|---|
| 161 |
|
|---|
| 162 |
from django.conf.urls.defaults import * |
|---|
| 163 |
|
|---|
| 164 |
urlpatterns = patterns('', |
|---|
| 165 |
(r'^/articles/(?P<year>\d{4})/$', 'myproject.news.views.year_archive'), |
|---|
| 166 |
(r'^/articles/(?P<year>\d{4})/(?P<month>\d{2})/$', 'myproject.news.views.month_archive'), |
|---|
| 167 |
(r'^/articles/(?P<year>\d{4})/(?P<month>\d{2})/(?P<article_id>\d+)/$', 'myproject.news.views.article_detail'), |
|---|
| 168 |
) |
|---|
| 169 |
|
|---|
| 170 |
The code above maps URLs, as regular expressions, to the location of Python |
|---|
| 171 |
callback functions (views). The regular expressions use parenthesis to "capture" |
|---|
| 172 |
values from the URLs. When a user requests a page, Django runs through each |
|---|
| 173 |
regular expression, in order, and stops at the first one that matches the |
|---|
| 174 |
requested URL. (If none of them matches, Django calls a special 404 view.) This |
|---|
| 175 |
is blazingly fast, because the regular expressions are compiled at load time. |
|---|
| 176 |
|
|---|
| 177 |
Once one of the regexes matches, Django imports and calls the given view, which |
|---|
| 178 |
is a simple Python function. Each view gets passed a request object -- |
|---|
| 179 |
which contains request metadata and lets you access GET and POST data as simple |
|---|
| 180 |
dictionaries -- and the values captured in the regex, via keyword |
|---|
| 181 |
arguments. |
|---|
| 182 |
|
|---|
| 183 |
For example, if a user requested the URL "/articles/2005/05/39323/", Django |
|---|
| 184 |
would call the function ``myproject.news.views.article_detail(request, |
|---|
| 185 |
year='2005', month='05', article_id='39323')``. |
|---|
| 186 |
|
|---|
| 187 |
Write your views |
|---|
| 188 |
================ |
|---|
| 189 |
|
|---|
| 190 |
Each view is responsible for doing one of two things: Returning an |
|---|
| 191 |
``HttpResponse`` object containing the content for the requested page, or |
|---|
| 192 |
raising an exception such as ``Http404``. The rest is up to you. |
|---|
| 193 |
|
|---|
| 194 |
Generally, a view retrieves data according to the parameters, loads a template |
|---|
| 195 |
and renders the template with the retrieved data. Here's an example view for |
|---|
| 196 |
article_detail from above:: |
|---|
| 197 |
|
|---|
| 198 |
def article_detail(request, year, month, article_id): |
|---|
| 199 |
# Use the Django API to find an object matching the URL criteria. |
|---|
| 200 |
a = get_object_or_404(articles, pub_date__year=year, pub_date__month=month, pk=article_id) |
|---|
| 201 |
return render_to_response('news/article_detail', {'article': a}) |
|---|
| 202 |
|
|---|
| 203 |
This example uses Django's template system, which has several key features. |
|---|
| 204 |
|
|---|
| 205 |
Design your templates |
|---|
| 206 |
===================== |
|---|
| 207 |
|
|---|
| 208 |
The code above loads the ``news/article_detail`` template. |
|---|
| 209 |
|
|---|
| 210 |
Django has a template search path, which allows you to minimize redundancy among |
|---|
| 211 |
templates. In your Django settings, you specify a list of directories to check |
|---|
| 212 |
for templates. If a template doesn't exist in the first directory, it checks the |
|---|
| 213 |
second, and so on. |
|---|
| 214 |
|
|---|
| 215 |
Let's say the ``news/article_detail`` template was found. Here's what that might |
|---|
| 216 |
look like:: |
|---|
| 217 |
|
|---|
| 218 |
{% extends "base" %} |
|---|
| 219 |
|
|---|
| 220 |
{% block title %}{{ article.headline }}{% endblock %} |
|---|
| 221 |
|
|---|
| 222 |
{% block content %} |
|---|
| 223 |
<h1>{{ article.headline }}</h1> |
|---|
| 224 |
<p>By {{ article.get_reporter.full_name }}</p> |
|---|
| 225 |
<p>Published {{ article.pub_date|date:"F j, Y" }}</p> |
|---|
| 226 |
{{ article.article }} |
|---|
| 227 |
{% endblock %} |
|---|
| 228 |
|
|---|
| 229 |
|
|---|
| 230 |
It should look straightforward. Variables are surrounded by double-curly braces. |
|---|
| 231 |
``{{ article.headline }}`` means "Output the value of the article's headline |
|---|
| 232 |
attribute." But dots aren't used only for attribute lookup: They also can do |
|---|
| 233 |
dictionary-key lookup, index lookup and function calls (as is the case with |
|---|
| 234 |
``article.get_reporter``). |
|---|
| 235 |
|
|---|
| 236 |
Note ``{{ article.pub_date|date:"F j, Y" }}`` uses a Unix-style "pipe" (the "|" |
|---|
| 237 |
character). This is called a template filter, and it's a way to filter the value |
|---|
| 238 |
of a variable. In this case, the date filter formats a Python datetime object in |
|---|
| 239 |
the given format (as found in PHP's date function; yes, there is one good idea |
|---|
| 240 |
in PHP). |
|---|
| 241 |
|
|---|
| 242 |
You can chain together as many filters as you'd like. You can write custom |
|---|
| 243 |
filters. You can write custom template tags, which run custom Python code behind |
|---|
| 244 |
the scenes. |
|---|
| 245 |
|
|---|
| 246 |
Finally, Django uses the concept of template inheritance: That's what the ``{% |
|---|
| 247 |
extends "base" %}`` does. It means "First load the template called 'base', which |
|---|
| 248 |
has defined a bunch of blocks, and fill the blocks with the following blocks." |
|---|
| 249 |
In short, that lets you dramatically cut down on redundancy in templates: Each |
|---|
| 250 |
template has to define only what's unique to that template. |
|---|
| 251 |
|
|---|
| 252 |
Here's what the "base" template might look like:: |
|---|
| 253 |
|
|---|
| 254 |
<html> |
|---|
| 255 |
<head> |
|---|
| 256 |
<title>{% block title %}{% endblock %}</title> |
|---|
| 257 |
</head> |
|---|
| 258 |
<body> |
|---|
| 259 |
<img src="sitelogo.gif" alt="Logo" /> |
|---|
| 260 |
{% block content %}{% endblock %} |
|---|
| 261 |
</body> |
|---|
| 262 |
</html> |
|---|
| 263 |
|
|---|
| 264 |
Simplistically, it defines the look-and-feel of the site (with the site's logo), |
|---|
| 265 |
and provides "holes" for child templates to fill. This makes a site redesign as |
|---|
| 266 |
easy as changing a single file -- the base template. |
|---|
| 267 |
|
|---|
| 268 |
Note that you don't have to use Django's template system if you prefer another |
|---|
| 269 |
system. While Django's template system is particularly well-integrated with |
|---|
| 270 |
Django's model layer, nothing forces you to use it. For that matter, you don't |
|---|
| 271 |
have to use Django's API, either. You can use another database abstraction |
|---|
| 272 |
layer, you can read XML files, you can read files off disk, or anything you |
|---|
| 273 |
want. Each piece of Django -- models, views, templates -- is decoupled |
|---|
| 274 |
from the next. |
|---|
| 275 |
|
|---|
| 276 |
This is just the surface |
|---|
| 277 |
======================== |
|---|
| 278 |
|
|---|
| 279 |
This has been only a quick overview of Django's functionality. Some more useful |
|---|
| 280 |
features: |
|---|
| 281 |
|
|---|
| 282 |
* A caching framework that integrates with memcached or other backends. |
|---|
| 283 |
* A syndication framework that makes creating RSS and Atom feeds as easy as |
|---|
| 284 |
writing a small Python class. |
|---|
| 285 |
* More sexy automatically-generated admin features -- this overview barely |
|---|
| 286 |
scratched the surface. |
|---|
| 287 |
|
|---|
| 288 |
The next obvious steps are for you to `download Django`_, read `the tutorial`_ |
|---|
| 289 |
and join `the community`_. Thanks for your interest! |
|---|
| 290 |
|
|---|
| 291 |
.. _download Django: http://www.djangoproject.com/download/ |
|---|
| 292 |
.. _the tutorial: http://www.djangoproject.com/documentation/tutorial1/ |
|---|
| 293 |
.. _the community: http://www.djangoproject.com/community/ |
|---|