Massive reorganization of the docs. See the new docs online at http://docs.djangoproject.com/.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@8506 bcc190cf-cafb-0310-a4f2-bffc1f526a37
1
AUTHORS
|
@ -67,6 +67,7 @@ answer newbie questions, and generally made Django that much better:
|
||||||
Jiri Barton
|
Jiri Barton
|
||||||
Ned Batchelder <http://www.nedbatchelder.com/>
|
Ned Batchelder <http://www.nedbatchelder.com/>
|
||||||
batiste@dosimple.ch
|
batiste@dosimple.ch
|
||||||
|
Batman
|
||||||
Shannon -jj Behrens <http://jjinux.blogspot.com/>
|
Shannon -jj Behrens <http://jjinux.blogspot.com/>
|
||||||
Esdras Beleza <linux@esdrasbeleza.com>
|
Esdras Beleza <linux@esdrasbeleza.com>
|
||||||
Chris Bennett <chrisrbennett@yahoo.com>
|
Chris Bennett <chrisrbennett@yahoo.com>
|
||||||
|
|
|
@ -11,12 +11,12 @@ PAPEROPT_a4 = -D latex_paper_size=a4
|
||||||
PAPEROPT_letter = -D latex_paper_size=letter
|
PAPEROPT_letter = -D latex_paper_size=letter
|
||||||
ALLSPHINXOPTS = -d _build/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
ALLSPHINXOPTS = -d _build/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||||
|
|
||||||
.PHONY: help clean html web htmlhelp latex changes linkcheck
|
.PHONY: help clean html web pickle htmlhelp latex changes linkcheck
|
||||||
|
|
||||||
help:
|
help:
|
||||||
@echo "Please use \`make <target>' where <target> is one of"
|
@echo "Please use \`make <target>' where <target> is one of"
|
||||||
@echo " html to make standalone HTML files"
|
@echo " html to make standalone HTML files"
|
||||||
@echo " web to make files usable by Sphinx.web"
|
@echo " pickle to make pickle files (usable by e.g. sphinx-web)"
|
||||||
@echo " htmlhelp to make HTML files and a HTML help project"
|
@echo " htmlhelp to make HTML files and a HTML help project"
|
||||||
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
|
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
|
||||||
@echo " changes to make an overview over all changed/added/deprecated items"
|
@echo " changes to make an overview over all changed/added/deprecated items"
|
||||||
|
@ -31,13 +31,15 @@ html:
|
||||||
@echo
|
@echo
|
||||||
@echo "Build finished. The HTML pages are in _build/html."
|
@echo "Build finished. The HTML pages are in _build/html."
|
||||||
|
|
||||||
web:
|
pickle:
|
||||||
mkdir -p _build/web _build/doctrees
|
mkdir -p _build/pickle _build/doctrees
|
||||||
$(SPHINXBUILD) -b web $(ALLSPHINXOPTS) _build/web
|
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) _build/pickle
|
||||||
@echo
|
@echo
|
||||||
@echo "Build finished; now you can run"
|
@echo "Build finished; now you can process the pickle files or run"
|
||||||
@echo " python -m sphinx.web _build/web"
|
@echo " sphinx-web _build/pickle"
|
||||||
@echo "to start the server."
|
@echo "to start the sphinx-web server."
|
||||||
|
|
||||||
|
web: pickle
|
||||||
|
|
||||||
htmlhelp:
|
htmlhelp:
|
||||||
mkdir -p _build/htmlhelp _build/doctrees
|
mkdir -p _build/htmlhelp _build/doctrees
|
||||||
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
"""Adds xref targets to the top of files."""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
|
testing = False
|
||||||
|
|
||||||
|
DONT_TOUCH = (
|
||||||
|
'./index.txt',
|
||||||
|
)
|
||||||
|
|
||||||
|
def target_name(fn):
|
||||||
|
if fn.endswith('.txt'):
|
||||||
|
fn = fn[:-4]
|
||||||
|
return '_' + fn.lstrip('./').replace('/', '-')
|
||||||
|
|
||||||
|
def process_file(fn, lines):
|
||||||
|
lines.insert(0, '\n')
|
||||||
|
lines.insert(0, '.. %s:\n' % target_name(fn))
|
||||||
|
try:
|
||||||
|
f = open(fn, 'w')
|
||||||
|
except IOError:
|
||||||
|
print("Can't open %s for writing. Not touching it." % fn)
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
f.writelines(lines)
|
||||||
|
except IOError:
|
||||||
|
print("Can't write to %s. Not touching it." % fn)
|
||||||
|
finally:
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
def has_target(fn):
|
||||||
|
try:
|
||||||
|
f = open(fn, 'r')
|
||||||
|
except IOError:
|
||||||
|
print("Can't open %s. Not touching it." % fn)
|
||||||
|
return (True, None)
|
||||||
|
readok = True
|
||||||
|
try:
|
||||||
|
lines = f.readlines()
|
||||||
|
except IOError:
|
||||||
|
print("Can't read %s. Not touching it." % fn)
|
||||||
|
readok = False
|
||||||
|
finally:
|
||||||
|
f.close()
|
||||||
|
if not readok:
|
||||||
|
return (True, None)
|
||||||
|
|
||||||
|
#print fn, len(lines)
|
||||||
|
if len(lines) < 1:
|
||||||
|
print("Not touching empty file %s." % fn)
|
||||||
|
return (True, None)
|
||||||
|
if lines[0].startswith('.. _'):
|
||||||
|
return (True, None)
|
||||||
|
return (False, lines)
|
||||||
|
|
||||||
|
def main(argv=None):
|
||||||
|
if argv is None:
|
||||||
|
argv = sys.argv
|
||||||
|
|
||||||
|
if len(argv) == 1:
|
||||||
|
argv.extend('.')
|
||||||
|
|
||||||
|
files = []
|
||||||
|
for root in argv[1:]:
|
||||||
|
for (dirpath, dirnames, filenames) in os.walk(root):
|
||||||
|
files.extend([(dirpath, f) for f in filenames])
|
||||||
|
files.sort()
|
||||||
|
files = [os.path.join(p, fn) for p, fn in files if fn.endswith('.txt')]
|
||||||
|
#print files
|
||||||
|
|
||||||
|
for fn in files:
|
||||||
|
if fn in DONT_TOUCH:
|
||||||
|
print("Skipping blacklisted file %s." % fn)
|
||||||
|
continue
|
||||||
|
|
||||||
|
target_found, lines = has_target(fn)
|
||||||
|
if not target_found:
|
||||||
|
if testing:
|
||||||
|
print '%s: %s' % (fn, lines[0]),
|
||||||
|
else:
|
||||||
|
print "Adding xref to %s" % fn
|
||||||
|
process_file(fn, lines)
|
||||||
|
else:
|
||||||
|
print "Skipping %s: already has a xref" % fn
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
sys.exit(main())
|
|
@ -0,0 +1,146 @@
|
||||||
|
"""
|
||||||
|
Sphinx plugins for Django documentation.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import docutils.nodes
|
||||||
|
import docutils.transforms
|
||||||
|
import sphinx
|
||||||
|
import sphinx.addnodes
|
||||||
|
import sphinx.builder
|
||||||
|
import sphinx.directives
|
||||||
|
import sphinx.environment
|
||||||
|
import sphinx.htmlwriter
|
||||||
|
|
||||||
|
def setup(app):
|
||||||
|
app.add_crossref_type(
|
||||||
|
directivename = "setting",
|
||||||
|
rolename = "setting",
|
||||||
|
indextemplate = "pair: %s; setting",
|
||||||
|
)
|
||||||
|
app.add_crossref_type(
|
||||||
|
directivename = "templatetag",
|
||||||
|
rolename = "ttag",
|
||||||
|
indextemplate = "pair: %s; template tag"
|
||||||
|
)
|
||||||
|
app.add_crossref_type(
|
||||||
|
directivename = "templatefilter",
|
||||||
|
rolename = "tfilter",
|
||||||
|
indextemplate = "pair: %s; template filter"
|
||||||
|
)
|
||||||
|
app.add_crossref_type(
|
||||||
|
directivename = "fieldlookup",
|
||||||
|
rolename = "lookup",
|
||||||
|
indextemplate = "pair: %s, field lookup type",
|
||||||
|
)
|
||||||
|
app.add_description_unit(
|
||||||
|
directivename = "django-admin",
|
||||||
|
rolename = "djadmin",
|
||||||
|
indextemplate = "pair: %s; django-admin command",
|
||||||
|
parse_node = parse_django_admin_node,
|
||||||
|
)
|
||||||
|
app.add_description_unit(
|
||||||
|
directivename = "django-admin-option",
|
||||||
|
rolename = "djadminopt",
|
||||||
|
indextemplate = "pair: %s; django-admin command-line option",
|
||||||
|
parse_node = lambda env, sig, signode: sphinx.directives.parse_option_desc(signode, sig),
|
||||||
|
)
|
||||||
|
app.add_transform(SuppressBlockquotes)
|
||||||
|
|
||||||
|
# Monkeypatch PickleHTMLBuilder so that it doesn't die in Sphinx 0.4.2
|
||||||
|
if sphinx.__version__ == '0.4.2':
|
||||||
|
monkeypatch_pickle_builder()
|
||||||
|
|
||||||
|
class SuppressBlockquotes(docutils.transforms.Transform):
|
||||||
|
"""
|
||||||
|
Remove the default blockquotes that encase indented list, tables, etc.
|
||||||
|
"""
|
||||||
|
default_priority = 300
|
||||||
|
|
||||||
|
suppress_blockquote_child_nodes = (
|
||||||
|
docutils.nodes.bullet_list,
|
||||||
|
docutils.nodes.enumerated_list,
|
||||||
|
docutils.nodes.definition_list,
|
||||||
|
docutils.nodes.literal_block,
|
||||||
|
docutils.nodes.doctest_block,
|
||||||
|
docutils.nodes.line_block,
|
||||||
|
docutils.nodes.table
|
||||||
|
)
|
||||||
|
|
||||||
|
def apply(self):
|
||||||
|
for node in self.document.traverse(docutils.nodes.block_quote):
|
||||||
|
if len(node.children) == 1 and isinstance(node.children[0], self.suppress_blockquote_child_nodes):
|
||||||
|
node.replace_self(node.children[0])
|
||||||
|
|
||||||
|
class DjangoHTMLTranslator(sphinx.htmlwriter.SmartyPantsHTMLTranslator):
|
||||||
|
"""
|
||||||
|
Django-specific reST to HTML tweaks.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Don't use border=1, which docutils does by default.
|
||||||
|
def visit_table(self, node):
|
||||||
|
self.body.append(self.starttag(node, 'table', CLASS='docutils'))
|
||||||
|
|
||||||
|
# Give each section a unique ID -- nice for custom CSS hooks
|
||||||
|
# This is different on docutils 0.5 vs. 0.4...
|
||||||
|
|
||||||
|
# The docutils 0.4 override.
|
||||||
|
if hasattr(sphinx.htmlwriter.SmartyPantsHTMLTranslator, 'start_tag_with_title'):
|
||||||
|
def start_tag_with_title(self, node, tagname, **atts):
|
||||||
|
node = {
|
||||||
|
'classes': node.get('classes', []),
|
||||||
|
'ids': ['s-%s' % i for i in node.get('ids', [])]
|
||||||
|
}
|
||||||
|
return self.starttag(node, tagname, **atts)
|
||||||
|
|
||||||
|
# The docutils 0.5 override.
|
||||||
|
else:
|
||||||
|
def visit_section(self, node):
|
||||||
|
old_ids = node.get('ids', [])
|
||||||
|
node['ids'] = ['s-' + i for i in old_ids]
|
||||||
|
sphinx.htmlwriter.SmartyPantsHTMLTranslator.visit_section(self, node)
|
||||||
|
node['ids'] = old_ids
|
||||||
|
|
||||||
|
def parse_django_admin_node(env, sig, signode):
|
||||||
|
command = sig.split(' ')[0]
|
||||||
|
env._django_curr_admin_command = command
|
||||||
|
title = "django-admin.py %s" % sig
|
||||||
|
signode += sphinx.addnodes.desc_name(title, title)
|
||||||
|
return sig
|
||||||
|
|
||||||
|
def monkeypatch_pickle_builder():
|
||||||
|
import shutil
|
||||||
|
from os import path
|
||||||
|
try:
|
||||||
|
import cPickle as pickle
|
||||||
|
except ImportError:
|
||||||
|
import pickle
|
||||||
|
from sphinx.util.console import bold
|
||||||
|
|
||||||
|
def handle_finish(self):
|
||||||
|
# dump the global context
|
||||||
|
outfilename = path.join(self.outdir, 'globalcontext.pickle')
|
||||||
|
f = open(outfilename, 'wb')
|
||||||
|
try:
|
||||||
|
pickle.dump(self.globalcontext, f, 2)
|
||||||
|
finally:
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
self.info(bold('dumping search index...'))
|
||||||
|
self.indexer.prune(self.env.all_docs)
|
||||||
|
f = open(path.join(self.outdir, 'searchindex.pickle'), 'wb')
|
||||||
|
try:
|
||||||
|
self.indexer.dump(f, 'pickle')
|
||||||
|
finally:
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
# copy the environment file from the doctree dir to the output dir
|
||||||
|
# as needed by the web app
|
||||||
|
shutil.copyfile(path.join(self.doctreedir, sphinx.builder.ENV_PICKLE_FILENAME),
|
||||||
|
path.join(self.outdir, sphinx.builder.ENV_PICKLE_FILENAME))
|
||||||
|
|
||||||
|
# touch 'last build' file, used by the web application to determine
|
||||||
|
# when to reload its environment and clear the cache
|
||||||
|
open(path.join(self.outdir, sphinx.builder.LAST_BUILD_FILENAME), 'w').close()
|
||||||
|
|
||||||
|
sphinx.builder.PickleHTMLBuilder.handle_finish = handle_finish
|
||||||
|
|
|
@ -0,0 +1,171 @@
|
||||||
|
"""
|
||||||
|
Runs through a reST file looking for old-style literals, and helps replace them
|
||||||
|
with new-style references.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
import shelve
|
||||||
|
|
||||||
|
refre = re.compile(r'``([^`\s]+?)``')
|
||||||
|
|
||||||
|
ROLES = (
|
||||||
|
'attr',
|
||||||
|
'class',
|
||||||
|
"djadmin",
|
||||||
|
'data',
|
||||||
|
'exc',
|
||||||
|
'file',
|
||||||
|
'func',
|
||||||
|
'lookup',
|
||||||
|
'meth',
|
||||||
|
'mod' ,
|
||||||
|
"djadminopt",
|
||||||
|
"ref",
|
||||||
|
"setting",
|
||||||
|
"term",
|
||||||
|
"tfilter",
|
||||||
|
"ttag",
|
||||||
|
|
||||||
|
# special
|
||||||
|
"skip"
|
||||||
|
)
|
||||||
|
|
||||||
|
ALWAYS_SKIP = [
|
||||||
|
"NULL",
|
||||||
|
"True",
|
||||||
|
"False",
|
||||||
|
]
|
||||||
|
|
||||||
|
def fixliterals(fname):
|
||||||
|
data = open(fname).read()
|
||||||
|
|
||||||
|
last = 0
|
||||||
|
new = []
|
||||||
|
storage = shelve.open("/tmp/literals_to_xref.shelve")
|
||||||
|
lastvalues = storage.get("lastvalues", {})
|
||||||
|
|
||||||
|
for m in refre.finditer(data):
|
||||||
|
|
||||||
|
new.append(data[last:m.start()])
|
||||||
|
last = m.end()
|
||||||
|
|
||||||
|
line_start = data.rfind("\n", 0, m.start())
|
||||||
|
line_end = data.find("\n", m.end())
|
||||||
|
prev_start = data.rfind("\n", 0, line_start)
|
||||||
|
next_end = data.find("\n", line_end + 1)
|
||||||
|
|
||||||
|
# Skip always-skip stuff
|
||||||
|
if m.group(1) in ALWAYS_SKIP:
|
||||||
|
new.append(m.group(0))
|
||||||
|
continue
|
||||||
|
|
||||||
|
# skip when the next line is a title
|
||||||
|
next_line = data[m.end():next_end].strip()
|
||||||
|
if next_line[0] in "!-/:-@[-`{-~" and all(c == next_line[0] for c in next_line):
|
||||||
|
new.append(m.group(0))
|
||||||
|
continue
|
||||||
|
|
||||||
|
sys.stdout.write("\n"+"-"*80+"\n")
|
||||||
|
sys.stdout.write(data[prev_start+1:m.start()])
|
||||||
|
sys.stdout.write(colorize(m.group(0), fg="red"))
|
||||||
|
sys.stdout.write(data[m.end():next_end])
|
||||||
|
sys.stdout.write("\n\n")
|
||||||
|
|
||||||
|
replace_type = None
|
||||||
|
while replace_type is None:
|
||||||
|
replace_type = raw_input(
|
||||||
|
colorize("Replace role: ", fg="yellow")
|
||||||
|
).strip().lower()
|
||||||
|
if replace_type and replace_type not in ROLES:
|
||||||
|
replace_type = None
|
||||||
|
|
||||||
|
if replace_type == "":
|
||||||
|
new.append(m.group(0))
|
||||||
|
continue
|
||||||
|
|
||||||
|
if replace_type == "skip":
|
||||||
|
new.append(m.group(0))
|
||||||
|
ALWAYS_SKIP.append(m.group(1))
|
||||||
|
continue
|
||||||
|
|
||||||
|
default = lastvalues.get(m.group(1), m.group(1))
|
||||||
|
if default.endswith("()") and replace_type in ("class", "func", "meth"):
|
||||||
|
default = default[:-2]
|
||||||
|
replace_value = raw_input(
|
||||||
|
colorize("Text <target> [", fg="yellow") + default + colorize("]: ", fg="yellow")
|
||||||
|
).strip()
|
||||||
|
if not replace_value:
|
||||||
|
replace_value = default
|
||||||
|
new.append(":%s:`%s`" % (replace_type, replace_value))
|
||||||
|
lastvalues[m.group(1)] = replace_value
|
||||||
|
|
||||||
|
new.append(data[last:])
|
||||||
|
open(fname, "w").write("".join(new))
|
||||||
|
|
||||||
|
storage["lastvalues"] = lastvalues
|
||||||
|
storage.close()
|
||||||
|
|
||||||
|
#
|
||||||
|
# The following is taken from django.utils.termcolors and is copied here to
|
||||||
|
# avoid the dependancy.
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
def colorize(text='', opts=(), **kwargs):
|
||||||
|
"""
|
||||||
|
Returns your text, enclosed in ANSI graphics codes.
|
||||||
|
|
||||||
|
Depends on the keyword arguments 'fg' and 'bg', and the contents of
|
||||||
|
the opts tuple/list.
|
||||||
|
|
||||||
|
Returns the RESET code if no parameters are given.
|
||||||
|
|
||||||
|
Valid colors:
|
||||||
|
'black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white'
|
||||||
|
|
||||||
|
Valid options:
|
||||||
|
'bold'
|
||||||
|
'underscore'
|
||||||
|
'blink'
|
||||||
|
'reverse'
|
||||||
|
'conceal'
|
||||||
|
'noreset' - string will not be auto-terminated with the RESET code
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
colorize('hello', fg='red', bg='blue', opts=('blink',))
|
||||||
|
colorize()
|
||||||
|
colorize('goodbye', opts=('underscore',))
|
||||||
|
print colorize('first line', fg='red', opts=('noreset',))
|
||||||
|
print 'this should be red too'
|
||||||
|
print colorize('and so should this')
|
||||||
|
print 'this should not be red'
|
||||||
|
"""
|
||||||
|
color_names = ('black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white')
|
||||||
|
foreground = dict([(color_names[x], '3%s' % x) for x in range(8)])
|
||||||
|
background = dict([(color_names[x], '4%s' % x) for x in range(8)])
|
||||||
|
|
||||||
|
RESET = '0'
|
||||||
|
opt_dict = {'bold': '1', 'underscore': '4', 'blink': '5', 'reverse': '7', 'conceal': '8'}
|
||||||
|
|
||||||
|
text = str(text)
|
||||||
|
code_list = []
|
||||||
|
if text == '' and len(opts) == 1 and opts[0] == 'reset':
|
||||||
|
return '\x1b[%sm' % RESET
|
||||||
|
for k, v in kwargs.iteritems():
|
||||||
|
if k == 'fg':
|
||||||
|
code_list.append(foreground[v])
|
||||||
|
elif k == 'bg':
|
||||||
|
code_list.append(background[v])
|
||||||
|
for o in opts:
|
||||||
|
if o in opt_dict:
|
||||||
|
code_list.append(opt_dict[o])
|
||||||
|
if 'noreset' not in opts:
|
||||||
|
text = text + '\x1b[%sm' % RESET
|
||||||
|
return ('\x1b[%sm' % ';'.join(code_list)) + text
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
try:
|
||||||
|
fixliterals(sys.argv[1])
|
||||||
|
except (KeyboardInterrupt, SystemExit):
|
||||||
|
print
|
|
@ -0,0 +1,3 @@
|
||||||
|
@import url(reset-fonts-grids.css);
|
||||||
|
@import url(djangodocs.css);
|
||||||
|
@import url(homepage.css);
|
|
@ -0,0 +1,126 @@
|
||||||
|
/*** setup ***/
|
||||||
|
html { background:#092e20;}
|
||||||
|
body { font:12px/1.5 Verdana,sans-serif; background:#092e20; color: white;}
|
||||||
|
#custom-doc { width:76.54em;*width:74.69em;min-width:995px; max-width:100em; margin:auto; text-align:left; padding-top:16px; margin-top:0;}
|
||||||
|
#hd { padding: 4px 0 12px 0; }
|
||||||
|
#bd { background:#234F32; }
|
||||||
|
#ft { color:#487858; font-size:90%; padding-bottom: 2em; }
|
||||||
|
|
||||||
|
/*** links ***/
|
||||||
|
a {text-decoration: none;}
|
||||||
|
a img {border: none;}
|
||||||
|
a:link, a:visited { color:#ffc757; }
|
||||||
|
#bd a:link, #bd a:visited { color:#ab5603; text-decoration:underline; }
|
||||||
|
#bd #sidebar a:link, #bd #sidebar a:visited { color:#ffc757; text-decoration:none; }
|
||||||
|
a:hover { color:#ffe761; }
|
||||||
|
#bd a:hover { background-color:#E0FFB8; color:#234f32; text-decoration:none; }
|
||||||
|
#bd #sidebar a:hover { color:#ffe761; background:none; }
|
||||||
|
h2 a, h3 a, h4 a { text-decoration:none !important; }
|
||||||
|
a.reference em { font-style: normal; }
|
||||||
|
|
||||||
|
/*** sidebar ***/
|
||||||
|
#sidebar div.sphinxsidebarwrapper { font-size:92%; margin-right: 14px; }
|
||||||
|
#sidebar h3, #sidebar h4 { color: white; font-size: 125%; }
|
||||||
|
#sidebar a { color: white; }
|
||||||
|
#sidebar ul ul { margin-top:0; margin-bottom:0; }
|
||||||
|
#sidebar li { margin-top: 0.2em; margin-bottom: 0.2em; }
|
||||||
|
|
||||||
|
/*** nav ***/
|
||||||
|
div.nav { margin: 0; font-size: 11px; text-align: right; color: #487858;}
|
||||||
|
#hd div.nav { margin-top: -27px; }
|
||||||
|
#ft div.nav { margin-bottom: -18px; }
|
||||||
|
#hd h1 a { color: white; }
|
||||||
|
#global-nav { position:absolute; top:5px; margin-left: -5px; padding:7px 0; color:#263E2B; }
|
||||||
|
#global-nav a:link, #global-nav a:visited {color:#487858;}
|
||||||
|
#global-nav a {padding:0 4px;}
|
||||||
|
#global-nav a.about {padding-left:0;}
|
||||||
|
#global-nav:hover {color:#fff;}
|
||||||
|
#global-nav:hover a:link, #global-nav:hover a:visited { color:#ffc757; }
|
||||||
|
|
||||||
|
/*** content ***/
|
||||||
|
#yui-main div.yui-b { position: relative; }
|
||||||
|
#yui-main div.yui-b { margin: 0 0 0 20px; background: white; color: black; padding: 0.3em 2em 1em 2em; }
|
||||||
|
|
||||||
|
/*** basic styles ***/
|
||||||
|
dd { margin-left:15px; }
|
||||||
|
h1,h2,h3,h4 { margin-top:1em; font-family:"Trebuchet MS",sans-serif; font-weight:normal; }
|
||||||
|
h1 { font-size:218%; margin-top:0.6em; margin-bottom:.4em; line-height:1.1em; }
|
||||||
|
h2 { font-size:175%; margin-bottom:.6em; line-height:1.2em; color:#092e20; }
|
||||||
|
h3 { font-size:150%; font-weight:bold; margin-bottom:.2em; color:#487858; }
|
||||||
|
h4 { font-size:125%; font-weight:bold; margin-top:1.5em; margin-bottom:3px; }
|
||||||
|
div.figure { text-align: center; }
|
||||||
|
div.figure p.caption { font-size:1em; margin-top:0; margin-bottom:1.5em; color: #555;}
|
||||||
|
hr { color:#ccc; background-color:#ccc; height:1px; border:0; }
|
||||||
|
p, ul, dl { margin-top:.6em; margin-bottom:1em; padding-bottom: 0.1em;}
|
||||||
|
#yui-main div.yui-b img { max-width: 50em; margin-left: auto; margin-right: auto; display: block; }
|
||||||
|
caption { font-size:1em; font-weight:bold; margin-top:0.5em; margin-bottom:0.5em; margin-left: 2px; text-align: center; }
|
||||||
|
blockquote { padding: 0 1em; margin: 1em 0; font:125%/1.2em "Trebuchet MS", sans-serif; color:#234f32; border-left:2px solid #94da3a; }
|
||||||
|
strong { font-weight: bold; }
|
||||||
|
em { font-style: italic; }
|
||||||
|
ins { font-weight: bold; text-decoration: none; }
|
||||||
|
|
||||||
|
/*** lists ***/
|
||||||
|
ul { padding-left:30px; }
|
||||||
|
ol { padding-left:30px; }
|
||||||
|
ol.arabic { list-style-type: decimal; }
|
||||||
|
ul li { list-style-type:square; margin-bottom:.4em; }
|
||||||
|
ol li { margin-bottom: .4em; }
|
||||||
|
ul ul { padding-left:1.2em; }
|
||||||
|
ul ul ul { padding-left:1em; }
|
||||||
|
ul.linklist, ul.toc { padding-left:0; }
|
||||||
|
ul.toc ul { margin-left:.6em; }
|
||||||
|
ul.toc ul li { list-style-type:square; }
|
||||||
|
ul.toc ul ul li { list-style-type:disc; }
|
||||||
|
ul.linklist li, ul.toc li { list-style-type:none; }
|
||||||
|
dt { font-weight:bold; margin-top:.5em; font-size:1.1em; }
|
||||||
|
dd { margin-bottom:.8em; }
|
||||||
|
ol.toc { margin-bottom: 2em; }
|
||||||
|
ol.toc li { font-size:125%; padding: .5em; line-height:1.2em; clear: right; }
|
||||||
|
ol.toc li.b { background-color: #E0FFB8; }
|
||||||
|
ol.toc li a:hover { background-color: transparent !important; text-decoration: underline !important; }
|
||||||
|
ol.toc span.release-date { color:#487858; float: right; font-size: 85%; padding-right: .5em; }
|
||||||
|
ol.toc span.comment-count { font-size: 75%; color: #999; }
|
||||||
|
|
||||||
|
/*** tables ***/
|
||||||
|
table { color:#000; margin-bottom: 1em; width: 100%; }
|
||||||
|
table.docutils td p { margin-top:0; margin-bottom:.5em; }
|
||||||
|
table.docutils td, table.docutils th { border-bottom:1px solid #dfdfdf; padding:4px 2px;}
|
||||||
|
table.docutils thead th { border-bottom:2px solid #dfdfdf; text-align:left; font-weight: bold; white-space: nowrap; }
|
||||||
|
table.docutils thead th p { margin: 0; padding: 0; }
|
||||||
|
table.docutils { border-collapse:collapse; }
|
||||||
|
|
||||||
|
/*** code blocks ***/
|
||||||
|
.literal { white-space:nowrap; }
|
||||||
|
.literal { color:#234f32; }
|
||||||
|
#sidebar .literal { color:white; background:transparent; font-size:11px; }
|
||||||
|
h4 .literal { color: #234f32; font-size: 13px; }
|
||||||
|
pre { font-size:small; background:#E0FFB8; border:1px solid #94da3a; border-width:1px 0; margin: 1em 0; padding: .3em .4em; overflow: hidden; line-height: 1.3em;}
|
||||||
|
dt .literal, table .literal { background:none; }
|
||||||
|
#bd a.reference { text-decoration: none; }
|
||||||
|
#bd a.reference tt.literal { border-bottom: 1px #234f32 dotted; }
|
||||||
|
|
||||||
|
/*** notes & admonitions ***/
|
||||||
|
.note, .admonition { padding:.8em 1em .8em; margin: 1em 0; border:1px solid #94da3a; }
|
||||||
|
.admonition-title { font-weight:bold; margin-top:0 !important; margin-bottom:0 !important;}
|
||||||
|
.admonition .last { margin-bottom:0 !important; }
|
||||||
|
.note, .admonition { padding-left:65px; background:url(docicons-note.gif) .8em .8em no-repeat;}
|
||||||
|
div.admonition-philosophy { padding-left:65px; background:url(docicons-philosophy.gif) .8em .8em no-repeat;}
|
||||||
|
div.admonition-behind-the-scenes { padding-left:65px; background:url(docicons-behindscenes.gif) .8em .8em no-repeat;}
|
||||||
|
|
||||||
|
/*** p-links ***/
|
||||||
|
a.headerlink { color: #c60f0f; font-size: 0.8em; padding: 0 4px 0 4px; text-decoration: none; visibility: hidden; }
|
||||||
|
h1:hover > a.headerlink, h2:hover > a.headerlink, h3:hover > a.headerlink, h4:hover > a.headerlink, h5:hover > a.headerlink, h6:hover > a.headerlink, dt:hover > a.headerlink { visibility: visible; }
|
||||||
|
|
||||||
|
/*** index ***/
|
||||||
|
table.indextable td { text-align: left; vertical-align: top;}
|
||||||
|
table.indextable dl, table.indextable dd { margin-top: 0; margin-bottom: 0; }
|
||||||
|
table.indextable tr.pcap { height: 10px; }
|
||||||
|
table.indextable tr.cap { margin-top: 10px; background-color: #f2f2f2;}
|
||||||
|
|
||||||
|
/*** page-specific overrides ***/
|
||||||
|
div#contents ul { margin-bottom: 0;}
|
||||||
|
div#contents ul li { margin-bottom: 0;}
|
||||||
|
div#contents ul ul li { margin-top: 0.3em;}
|
||||||
|
|
||||||
|
/*** IE hacks ***/
|
||||||
|
* pre { width: 100%; }
|
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 632 B |
After Width: | Height: | Size: 799 B |
|
@ -0,0 +1,22 @@
|
||||||
|
#index p.rubric { font-size:150%; font-weight:normal; margin-bottom:.2em; color:#487858; }
|
||||||
|
|
||||||
|
#index div.section dt { font-weight: normal; }
|
||||||
|
|
||||||
|
#index #s-getting-help { float: right; width: 35em; background: #E1ECE2; padding: 1em; margin: 2em 0 2em 2em; }
|
||||||
|
#index #s-getting-help h2 { margin: 0; }
|
||||||
|
|
||||||
|
#index #s-django-documentation div.section div.section h3 { margin: 0; }
|
||||||
|
#index #s-django-documentation div.section div.section { background: #E1ECE2; padding: 1em; margin: 2em 0 2em 40.3em; }
|
||||||
|
#index #s-django-documentation div.section div.section a.reference { white-space: nowrap; }
|
||||||
|
|
||||||
|
#index #s-using-django dl,
|
||||||
|
#index #s-add-on-contrib-applications dl,
|
||||||
|
#index #s-solving-specific-problems dl,
|
||||||
|
#index #s-reference dl
|
||||||
|
{ float: left; width: 41em; }
|
||||||
|
|
||||||
|
#index #s-add-on-contrib-applications,
|
||||||
|
#index #s-solving-specific-problems,
|
||||||
|
#index #s-reference,
|
||||||
|
#index #s-and-all-the-rest
|
||||||
|
{ clear: left; }
|
|
@ -0,0 +1,8 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2008, Yahoo! Inc. All rights reserved.
|
||||||
|
Code licensed under the BSD License:
|
||||||
|
http://developer.yahoo.net/yui/license.txt
|
||||||
|
version: 2.5.1
|
||||||
|
*/
|
||||||
|
html{color:#000;background:#FFF;}body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,textarea,p,blockquote,th,td{margin:0;padding:0;}table{border-collapse:collapse;border-spacing:0;}fieldset,img{border:0;}address,caption,cite,code,dfn,em,strong,th,var{font-style:normal;font-weight:normal;}li{list-style:none;}caption,th{text-align:left;}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal;}q:before,q:after{content:'';}abbr,acronym {border:0;font-variant:normal;}sup {vertical-align:text-top;}sub {vertical-align:text-bottom;}input,textarea,select{font-family:inherit;font-size:inherit;font-weight:inherit;}input,textarea,select{*font-size:100%;}legend{color:#000;}body {font:13px/1.231 arial,helvetica,clean,sans-serif;*font-size:small;*font:x-small;}table {font-size:inherit;font:100%;}pre,code,kbd,samp,tt{font-family:monospace;*font-size:108%;line-height:100%;}
|
||||||
|
body{text-align:center;}#ft{clear:both;}#doc,#doc2,#doc3,#doc4,.yui-t1,.yui-t2,.yui-t3,.yui-t4,.yui-t5,.yui-t6,.yui-t7{margin:auto;text-align:left;width:57.69em;*width:56.25em;min-width:750px;}#doc2{width:73.076em;*width:71.25em;}#doc3{margin:auto 10px;width:auto;}#doc4{width:74.923em;*width:73.05em;}.yui-b{position:relative;}.yui-b{_position:static;}#yui-main .yui-b{position:static;}#yui-main{width:100%;}.yui-t1 #yui-main,.yui-t2 #yui-main,.yui-t3 #yui-main{float:right;margin-left:-25em;}.yui-t4 #yui-main,.yui-t5 #yui-main,.yui-t6 #yui-main{float:left;margin-right:-25em;}.yui-t1 .yui-b{float:left;width:12.30769em;*width:12.00em;}.yui-t1 #yui-main .yui-b{margin-left:13.30769em;*margin-left:13.05em;}.yui-t2 .yui-b{float:left;width:13.8461em;*width:13.50em;}.yui-t2 #yui-main .yui-b{margin-left:14.8461em;*margin-left:14.55em;}.yui-t3 .yui-b{float:left;width:23.0769em;*width:22.50em;}.yui-t3 #yui-main .yui-b{margin-left:24.0769em;*margin-left:23.62em;}.yui-t4 .yui-b{float:right;width:13.8456em;*width:13.50em;}.yui-t4 #yui-main .yui-b{margin-right:14.8456em;*margin-right:14.55em;}.yui-t5 .yui-b{float:right;width:18.4615em;*width:18.00em;}.yui-t5 #yui-main .yui-b{margin-right:19.4615em;*margin-right:19.125em;}.yui-t6 .yui-b{float:right;width:23.0769em;*width:22.50em;}.yui-t6 #yui-main .yui-b{margin-right:24.0769em;*margin-right:23.62em;}.yui-t7 #yui-main .yui-b{display:block;margin:0 0 1em 0;}#yui-main .yui-b{float:none;width:auto;}.yui-gb .yui-u,.yui-g .yui-gb .yui-u,.yui-gb .yui-g,.yui-gb .yui-gb,.yui-gb .yui-gc,.yui-gb .yui-gd,.yui-gb .yui-ge,.yui-gb .yui-gf,.yui-gc .yui-u,.yui-gc .yui-g,.yui-gd .yui-u{float:left;}.yui-g .yui-u,.yui-g .yui-g,.yui-g .yui-gb,.yui-g .yui-gc,.yui-g .yui-gd,.yui-g .yui-ge,.yui-g .yui-gf,.yui-gc .yui-u,.yui-gd .yui-g,.yui-g .yui-gc .yui-u,.yui-ge .yui-u,.yui-ge .yui-g,.yui-gf .yui-g,.yui-gf .yui-u{float:right;}.yui-g div.first,.yui-gb div.first,.yui-gc div.first,.yui-gd div.first,.yui-ge div.first,.yui-gf div.first,.yui-g .yui-gc div.first,.yui-g .yui-ge div.first,.yui-gc div.first div.first{float:left;}.yui-g .yui-u,.yui-g .yui-g,.yui-g .yui-gb,.yui-g .yui-gc,.yui-g .yui-gd,.yui-g .yui-ge,.yui-g .yui-gf{width:49.1%;}.yui-gb .yui-u,.yui-g .yui-gb .yui-u,.yui-gb .yui-g,.yui-gb .yui-gb,.yui-gb .yui-gc,.yui-gb .yui-gd,.yui-gb .yui-ge,.yui-gb .yui-gf,.yui-gc .yui-u,.yui-gc .yui-g,.yui-gd .yui-u{width:32%;margin-left:1.99%;}.yui-gb .yui-u{*margin-left:1.9%;*width:31.9%;}.yui-gc div.first,.yui-gd .yui-u{width:66%;}.yui-gd div.first{width:32%;}.yui-ge div.first,.yui-gf .yui-u{width:74.2%;}.yui-ge .yui-u,.yui-gf div.first{width:24%;}.yui-g .yui-gb div.first,.yui-gb div.first,.yui-gc div.first,.yui-gd div.first{margin-left:0;}.yui-g .yui-g .yui-u,.yui-gb .yui-g .yui-u,.yui-gc .yui-g .yui-u,.yui-gd .yui-g .yui-u,.yui-ge .yui-g .yui-u,.yui-gf .yui-g .yui-u{width:49%;*width:48.1%;*margin-left:0;}.yui-g .yui-gb div.first,.yui-gb .yui-gb div.first{*margin-right:0;*width:32%;_width:31.7%;}.yui-g .yui-gc div.first,.yui-gd .yui-g{width:66%;}.yui-gb .yui-g div.first{*margin-right:4%;_margin-right:1.3%;}.yui-gb .yui-gc div.first,.yui-gb .yui-gd div.first{*margin-right:0;}.yui-gb .yui-gb .yui-u,.yui-gb .yui-gc .yui-u{*margin-left:1.8%;_margin-left:4%;}.yui-g .yui-gb .yui-u{_margin-left:1.0%;}.yui-gb .yui-gd .yui-u{*width:66%;_width:61.2%;}.yui-gb .yui-gd div.first{*width:31%;_width:29.5%;}.yui-g .yui-gc .yui-u,.yui-gb .yui-gc .yui-u{width:32%;_float:right;margin-right:0;_margin-left:0;}.yui-gb .yui-gc div.first{width:66%;*float:left;*margin-left:0;}.yui-gb .yui-ge .yui-u,.yui-gb .yui-gf .yui-u{margin:0;}.yui-gb .yui-gb .yui-u{_margin-left:.7%;}.yui-gb .yui-g div.first,.yui-gb .yui-gb div.first{*margin-left:0;}.yui-gc .yui-g .yui-u,.yui-gd .yui-g .yui-u{*width:48.1%;*margin-left:0;}s .yui-gb .yui-gd div.first{width:32%;}.yui-g .yui-gd div.first{_width:29.9%;}.yui-ge .yui-g{width:24%;}.yui-gf .yui-g{width:74.2%;}.yui-gb .yui-ge div.yui-u,.yui-gb .yui-gf div.yui-u{float:right;}.yui-gb .yui-ge div.first,.yui-gb .yui-gf div.first{float:left;}.yui-gb .yui-ge .yui-u,.yui-gb .yui-gf div.first{*width:24%;_width:20%;}.yui-gb .yui-ge div.first,.yui-gb .yui-gf .yui-u{*width:73.5%;_width:65.5%;}.yui-ge div.first .yui-gd .yui-u{width:65%;}.yui-ge div.first .yui-gd div.first{width:32%;}#bd:after,.yui-g:after,.yui-gb:after,.yui-gc:after,.yui-gd:after,.yui-ge:after,.yui-gf:after{content:".";display:block;height:0;clear:both;visibility:hidden;}#bd,.yui-g,.yui-gb,.yui-gc,.yui-gd,.yui-ge,.yui-gf{zoom:1;}
|
|
@ -0,0 +1,4 @@
|
||||||
|
{% extends "!genindex.html" %}
|
||||||
|
|
||||||
|
{% block bodyclass %}{% endblock %}
|
||||||
|
{% block sidebarwrapper %}{% endblock %}
|
|
@ -0,0 +1,87 @@
|
||||||
|
{% extends "!layout.html" %}
|
||||||
|
|
||||||
|
{%- macro secondnav %}
|
||||||
|
{%- if prev %}
|
||||||
|
« <a href="{{ prev.link|e }}" title="{{ prev.title|e }}">previous</a>
|
||||||
|
{{ reldelim2 }}
|
||||||
|
{%- endif %}
|
||||||
|
{%- if parents %}
|
||||||
|
<a href="{{ parents.0.link|e }}" title="{{ parents.0.title|e }}" accesskey="U">up</a>
|
||||||
|
{%- else %}
|
||||||
|
<a title="{{ docstitle }}" href="{{ pathto('index') }}" accesskey="U">up</a>
|
||||||
|
{%- endif %}
|
||||||
|
{%- if next %}
|
||||||
|
{{ reldelim2 }}
|
||||||
|
<a href="{{ next.link|e }}" title="{{ next.title|e }}">next</a> »
|
||||||
|
{%- endif %}
|
||||||
|
{%- endmacro %}
|
||||||
|
|
||||||
|
{% block document %}
|
||||||
|
<div id="custom-doc" class="{% block bodyclass %}{{ 'yui-t6' if pagename != 'index' else '' }}{% endblock %}">
|
||||||
|
<div id="hd">
|
||||||
|
<h1><a href="{{ pathto('index') }}">{{ docstitle }}</a></h1>
|
||||||
|
<div id="global-nav">
|
||||||
|
<a title="Home page" href="{{ pathto('index') }}">Home</a> {{ reldelim2 }}
|
||||||
|
<a title="Table of contents" href="{{ pathto('contents') }}">Table of contents</a> {{ reldelim2 }}
|
||||||
|
<a title="Global index" href="{{ pathto('genindex') }}">Index</a> {{ reldelim2 }}
|
||||||
|
<a title="Search" href="{{ pathto('modindex') }}">Modules</a>
|
||||||
|
</div>
|
||||||
|
<div class="nav">{{ secondnav() }}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="bd">
|
||||||
|
<div id="yui-main">
|
||||||
|
<div class="yui-b">
|
||||||
|
<div class="yui-g" id="{{ pagename|replace('/', '-') }}">
|
||||||
|
{% block body %}{% endblock %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% block sidebarwrapper %}
|
||||||
|
{% if pagename != 'index' %}
|
||||||
|
<div class="yui-b" id="sidebar">
|
||||||
|
{{ sidebar() }}
|
||||||
|
{%- if last_updated %}
|
||||||
|
<h3>Last update:</h3>
|
||||||
|
<p class="topless">{{ last_updated }}</p>
|
||||||
|
{%- endif %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="ft">
|
||||||
|
<div class="nav">{{ secondnav() }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block sidebarrel %}
|
||||||
|
<h3>Browse</h3>
|
||||||
|
<ul>
|
||||||
|
{% if prev %}
|
||||||
|
<li>Prev: <a href="{{ prev.link }}">{{ prev.title }}</a></li>
|
||||||
|
{% endif %}
|
||||||
|
{% if next %}
|
||||||
|
<li>Next: <a href="{{ next.link }}">{{ next.title }}</a></li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
<h3>You are here:</h3>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a href="{{ pathto('index') }}">{{ docstitle }}</a>
|
||||||
|
{% for p in parents %}
|
||||||
|
<ul><li><a href="{{ p.link }}">{{ p.title }}</a>
|
||||||
|
{% endfor %}
|
||||||
|
<ul><li>{{ title }}</li></ul>
|
||||||
|
{% for p in parents %}</li></ul>{% endfor %}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{# Empty some default blocks out #}
|
||||||
|
{% block relbar1 %}{% endblock %}
|
||||||
|
{% block relbar2 %}{% endblock %}
|
||||||
|
{% block sidebar1 %}{% endblock %}
|
||||||
|
{% block sidebar2 %}{% endblock %}
|
||||||
|
{% block footer %}{% endblock %}
|
|
@ -0,0 +1,3 @@
|
||||||
|
{% extends "!modindex.html" %}
|
||||||
|
{% block bodyclass %}{% endblock %}
|
||||||
|
{% block sidebarwrapper %}{% endblock %}
|
|
@ -0,0 +1,3 @@
|
||||||
|
{% extends "!search.html" %}
|
||||||
|
{% block bodyclass %}{% endblock %}
|
||||||
|
{% block sidebarwrapper %}{% endblock %}
|
|
@ -1,119 +0,0 @@
|
||||||
=============
|
|
||||||
API stability
|
|
||||||
=============
|
|
||||||
|
|
||||||
Although Django has not reached a 1.0 release, the bulk of Django's public APIs are
|
|
||||||
stable as of the 0.95 release. This document explains which APIs will and will not
|
|
||||||
change before the 1.0 release.
|
|
||||||
|
|
||||||
What "stable" means
|
|
||||||
===================
|
|
||||||
|
|
||||||
In this context, stable means:
|
|
||||||
|
|
||||||
- All the public APIs -- everything documented in the linked documents, and
|
|
||||||
all methods that don't begin with an underscore -- will not be moved or
|
|
||||||
renamed without providing backwards-compatible aliases.
|
|
||||||
|
|
||||||
- If new features are added to these APIs -- which is quite possible --
|
|
||||||
they will not break or change the meaning of existing methods. In other
|
|
||||||
words, "stable" does not (necessarily) mean "complete."
|
|
||||||
|
|
||||||
- If, for some reason, an API declared stable must be removed or replaced, it
|
|
||||||
will be declared deprecated but will remain in the API until at least
|
|
||||||
version 1.1. Warnings will be issued when the deprecated method is
|
|
||||||
called.
|
|
||||||
|
|
||||||
- We'll only break backwards compatibility of these APIs if a bug or
|
|
||||||
security hole makes it completely unavoidable.
|
|
||||||
|
|
||||||
Stable APIs
|
|
||||||
===========
|
|
||||||
|
|
||||||
These APIs are stable:
|
|
||||||
|
|
||||||
- `Caching`_.
|
|
||||||
|
|
||||||
- `Custom template tags and libraries`_ (with the possible exception for a
|
|
||||||
small change in the way templates are registered and loaded).
|
|
||||||
|
|
||||||
- `Database lookup`_ (with the exception of validation; see below).
|
|
||||||
|
|
||||||
- `django-admin utility`_.
|
|
||||||
|
|
||||||
- `FastCGI integration`_.
|
|
||||||
|
|
||||||
- `Flatpages`_.
|
|
||||||
|
|
||||||
- `Generic views`_.
|
|
||||||
|
|
||||||
- `Internationalization`_.
|
|
||||||
|
|
||||||
- `Legacy database integration`_.
|
|
||||||
|
|
||||||
- `Model definition`_ (with the exception of generic relations; see below).
|
|
||||||
|
|
||||||
- `mod_python integration`_.
|
|
||||||
|
|
||||||
- `Redirects`_.
|
|
||||||
|
|
||||||
- `Request/response objects`_.
|
|
||||||
|
|
||||||
- `Sending e-mail`_.
|
|
||||||
|
|
||||||
- `Sessions`_.
|
|
||||||
|
|
||||||
- `Settings`_.
|
|
||||||
|
|
||||||
- `Syndication`_.
|
|
||||||
|
|
||||||
- `Template language`_ (with the exception of some possible disambiguation
|
|
||||||
of how tag arguments are passed to tags and filters).
|
|
||||||
|
|
||||||
- `Transactions`_.
|
|
||||||
|
|
||||||
- `URL dispatch`_.
|
|
||||||
|
|
||||||
You'll notice that this list comprises the bulk of Django's APIs. That's right
|
|
||||||
-- most of the changes planned between now and Django 1.0 are either under the
|
|
||||||
hood, feature additions, or changes to a few select bits. A good estimate is
|
|
||||||
that 90% of Django can be considered forwards-compatible at this point.
|
|
||||||
|
|
||||||
That said, these APIs should *not* be considered stable, and are likely to
|
|
||||||
change:
|
|
||||||
|
|
||||||
- `Serialization`_ is under heavy development; changes are likely.
|
|
||||||
|
|
||||||
- The `authentication`_ framework is changing to be far more flexible, and
|
|
||||||
API changes may be necessary.
|
|
||||||
|
|
||||||
- Generic relations will most likely be moved out of core and into the
|
|
||||||
content-types contrib package to avoid core dependencies on optional
|
|
||||||
components.
|
|
||||||
|
|
||||||
- The comments framework, which is yet undocumented, will likely get a complete
|
|
||||||
rewrite before Django 1.0. Even if the change isn't quite that drastic,
|
|
||||||
there will at least be moderate changes.
|
|
||||||
|
|
||||||
.. _caching: ../cache/
|
|
||||||
.. _custom template tags and libraries: ../templates_python/
|
|
||||||
.. _database lookup: ../db-api/
|
|
||||||
.. _django-admin utility: ../django-admin/
|
|
||||||
.. _fastcgi integration: ../fastcgi/
|
|
||||||
.. _flatpages: ../flatpages/
|
|
||||||
.. _generic views: ../generic_views/
|
|
||||||
.. _internationalization: ../i18n/
|
|
||||||
.. _legacy database integration: ../legacy_databases/
|
|
||||||
.. _model definition: ../model-api/
|
|
||||||
.. _mod_python integration: ../modpython/
|
|
||||||
.. _redirects: ../redirects/
|
|
||||||
.. _request/response objects: ../request_response/
|
|
||||||
.. _sending e-mail: ../email/
|
|
||||||
.. _sessions: ../sessions/
|
|
||||||
.. _settings: ../settings/
|
|
||||||
.. _syndication: ../syndication_feeds/
|
|
||||||
.. _template language: ../templates/
|
|
||||||
.. _transactions: ../transactions/
|
|
||||||
.. _url dispatch: ../url_dispatch/
|
|
||||||
.. _serialization: ../serialization/
|
|
||||||
.. _authentication: ../authentication/
|
|
31
docs/conf.py
|
@ -12,35 +12,36 @@
|
||||||
# serve to show the default value.
|
# serve to show the default value.
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
# If your extensions are in another directory, add it here.
|
# If your extensions are in another directory, add it here.
|
||||||
#sys.path.append('some/directory')
|
sys.path.append(os.path.join(os.path.dirname(__file__), "_ext"))
|
||||||
|
|
||||||
# General configuration
|
# General configuration
|
||||||
# ---------------------
|
# ---------------------
|
||||||
|
|
||||||
# Add any Sphinx extension module names here, as strings. They can be extensions
|
# Add any Sphinx extension module names here, as strings. They can be extensions
|
||||||
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||||
#extensions = []
|
extensions = ["djangodocs"]
|
||||||
|
|
||||||
# Add any paths that contain templates here, relative to this directory.
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
templates_path = []
|
templates_path = ["_templates"]
|
||||||
|
|
||||||
# The suffix of source filenames.
|
# The suffix of source filenames.
|
||||||
source_suffix = '.txt'
|
source_suffix = '.txt'
|
||||||
|
|
||||||
# The master toctree document.
|
# The master toctree document.
|
||||||
master_doc = 'index'
|
master_doc = 'contents'
|
||||||
|
|
||||||
# General substitutions.
|
# General substitutions.
|
||||||
project = 'Django'
|
project = 'Django'
|
||||||
copyright = '2008, Django Software Foundation'
|
copyright = 'Django Software Foundation and contributors'
|
||||||
|
|
||||||
# The default replacements for |version| and |release|, also used in various
|
# The default replacements for |version| and |release|, also used in various
|
||||||
# other places throughout the built documents.
|
# other places throughout the built documents.
|
||||||
#
|
#
|
||||||
# The short X.Y version.
|
# The short X.Y version.
|
||||||
version = 'SVN'
|
version = '1.0'
|
||||||
# The full version, including alpha/beta/rc tags.
|
# The full version, including alpha/beta/rc tags.
|
||||||
release = version
|
release = version
|
||||||
|
|
||||||
|
@ -65,7 +66,7 @@ add_module_names = False
|
||||||
show_authors = False
|
show_authors = False
|
||||||
|
|
||||||
# The name of the Pygments (syntax highlighting) style to use.
|
# The name of the Pygments (syntax highlighting) style to use.
|
||||||
pygments_style = 'sphinx'
|
pygments_style = 'trac'
|
||||||
|
|
||||||
|
|
||||||
# Options for HTML output
|
# Options for HTML output
|
||||||
|
@ -79,7 +80,7 @@ html_style = 'default.css'
|
||||||
# Add any paths that contain custom static files (such as style sheets) here,
|
# Add any paths that contain custom static files (such as style sheets) here,
|
||||||
# relative to this directory. They are copied after the builtin static files,
|
# relative to this directory. They are copied after the builtin static files,
|
||||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||||
html_static_path = []
|
html_static_path = ["_static"]
|
||||||
|
|
||||||
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
||||||
# using the given strftime format.
|
# using the given strftime format.
|
||||||
|
@ -89,6 +90,9 @@ html_last_updated_fmt = '%b %d, %Y'
|
||||||
# typographically correct entities.
|
# typographically correct entities.
|
||||||
html_use_smartypants = True
|
html_use_smartypants = True
|
||||||
|
|
||||||
|
# HTML translator class for the builder
|
||||||
|
html_translator_class = "djangodocs.DjangoHTMLTranslator"
|
||||||
|
|
||||||
# Content template for the index page.
|
# Content template for the index page.
|
||||||
#html_index = ''
|
#html_index = ''
|
||||||
|
|
||||||
|
@ -97,7 +101,7 @@ html_use_smartypants = True
|
||||||
|
|
||||||
# Additional templates that should be rendered to pages, maps page names to
|
# Additional templates that should be rendered to pages, maps page names to
|
||||||
# template names.
|
# template names.
|
||||||
#html_additional_pages = {}
|
html_additional_pages = {}
|
||||||
|
|
||||||
# If false, no module index is generated.
|
# If false, no module index is generated.
|
||||||
#html_use_modindex = True
|
#html_use_modindex = True
|
||||||
|
@ -121,6 +125,9 @@ htmlhelp_basename = 'Djangodoc'
|
||||||
# Grouping the document tree into LaTeX files. List of tuples
|
# Grouping the document tree into LaTeX files. List of tuples
|
||||||
# (source start file, target name, title, author, document class [howto/manual]).
|
# (source start file, target name, title, author, document class [howto/manual]).
|
||||||
#latex_documents = []
|
#latex_documents = []
|
||||||
|
latex_documents = [
|
||||||
|
('index', 'django.tex', 'Django Documentation', 'Django Software Foundation', 'manual'),
|
||||||
|
]
|
||||||
|
|
||||||
# Additional stuff for the LaTeX preamble.
|
# Additional stuff for the LaTeX preamble.
|
||||||
#latex_preamble = ''
|
#latex_preamble = ''
|
||||||
|
@ -130,3 +137,9 @@ htmlhelp_basename = 'Djangodoc'
|
||||||
|
|
||||||
# If false, no module index is generated.
|
# If false, no module index is generated.
|
||||||
#latex_use_modindex = True
|
#latex_use_modindex = True
|
||||||
|
|
||||||
|
# For "manual" documents, if this is true, then toplevel headings are parts,
|
||||||
|
# not chapters.
|
||||||
|
# If this isn't set to True, the LaTex writer can only handle six levels of headers.
|
||||||
|
latex_use_parts = True
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
.. _contents:
|
||||||
|
|
||||||
|
=============================
|
||||||
|
Django documentation contents
|
||||||
|
=============================
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
intro/index
|
||||||
|
topics/index
|
||||||
|
howto/index
|
||||||
|
faq/index
|
||||||
|
ref/index
|
||||||
|
misc/index
|
||||||
|
glossary
|
||||||
|
releases/index
|
||||||
|
internals/index
|
||||||
|
|
||||||
|
Indices, glossary and tables
|
||||||
|
============================
|
||||||
|
|
||||||
|
* :ref:`genindex`
|
||||||
|
* :ref:`modindex`
|
||||||
|
* :ref:`glossary`
|
||||||
|
|
||||||
|
Deprecated/obsolete documentation
|
||||||
|
=================================
|
||||||
|
|
||||||
|
The following documentation covers features that have been deprecated or that
|
||||||
|
have been replaced in newer versions of Django.
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
obsolete/index
|
|
@ -1,297 +0,0 @@
|
||||||
==========================
|
|
||||||
The contenttypes framework
|
|
||||||
==========================
|
|
||||||
|
|
||||||
Django includes a "contenttypes" application that can track all of
|
|
||||||
the models installed in your Django-powered project, providing a
|
|
||||||
high-level, generic interface for working with your models.
|
|
||||||
|
|
||||||
Overview
|
|
||||||
========
|
|
||||||
|
|
||||||
At the heart of the contenttypes application is the ``ContentType``
|
|
||||||
model, which lives at
|
|
||||||
``django.contrib.contenttypes.models.ContentType``. Instances of
|
|
||||||
``ContentType`` represent and store information about the models
|
|
||||||
installed in your project, and new instances of ``ContentType`` are
|
|
||||||
automatically created whenever new models are installed.
|
|
||||||
|
|
||||||
Instances of ``ContentType`` have methods for returning the model
|
|
||||||
classes they represent and for querying objects from those models.
|
|
||||||
``ContentType`` also has a `custom manager`_ that adds methods for
|
|
||||||
working with ``ContentType`` and for obtaining instances of
|
|
||||||
``ContentType`` for a particular model.
|
|
||||||
|
|
||||||
Relations between your models and ``ContentType`` can also be used to
|
|
||||||
enable "generic" relationships between an instance of one of your
|
|
||||||
models and instances of any model you have installed.
|
|
||||||
|
|
||||||
.. _custom manager: ../model-api/#custom-managers
|
|
||||||
|
|
||||||
Installing the contenttypes framework
|
|
||||||
=====================================
|
|
||||||
|
|
||||||
The contenttypes framework is included in the default
|
|
||||||
``INSTALLED_APPS`` list created by ``django-admin.py startproject``,
|
|
||||||
but if you've removed it or if you manually set up your
|
|
||||||
``INSTALLED_APPS`` list, you can enable it by adding
|
|
||||||
``'django.contrib.contenttypes'`` to your ``INSTALLED_APPS`` setting.
|
|
||||||
|
|
||||||
It's generally a good idea to have the contenttypes framework
|
|
||||||
installed; several of Django's other bundled applications require it:
|
|
||||||
|
|
||||||
* The admin application uses it to log the history of each object
|
|
||||||
added or changed through the admin interface.
|
|
||||||
|
|
||||||
* Django's `authentication framework`_ uses it to tie user permissions
|
|
||||||
to specific models.
|
|
||||||
|
|
||||||
* Django's comments system (``django.contrib.comments``) uses it to
|
|
||||||
"attach" comments to any installed model.
|
|
||||||
|
|
||||||
.. _authentication framework: ../authentication/
|
|
||||||
|
|
||||||
The ``ContentType`` model
|
|
||||||
=========================
|
|
||||||
|
|
||||||
Each instance of ``ContentType`` has three fields which, taken
|
|
||||||
together, uniquely describe an installed model:
|
|
||||||
|
|
||||||
``app_label``
|
|
||||||
The name of the application the model is part of. This is taken from
|
|
||||||
the ``app_label`` attribute of the model, and includes only the *last*
|
|
||||||
part of the application's Python import path;
|
|
||||||
"django.contrib.contenttypes", for example, becomes an ``app_label``
|
|
||||||
of "contenttypes".
|
|
||||||
|
|
||||||
``model``
|
|
||||||
The name of the model class.
|
|
||||||
|
|
||||||
``name``
|
|
||||||
The human-readable name of the model. This is taken from
|
|
||||||
`the verbose_name attribute`_ of the model.
|
|
||||||
|
|
||||||
Let's look at an example to see how this works. If you already have
|
|
||||||
the contenttypes application installed, and then add `the sites application`_
|
|
||||||
to your ``INSTALLED_APPS`` setting and run ``manage.py syncdb`` to install it,
|
|
||||||
the model ``django.contrib.sites.models.Site`` will be installed into your
|
|
||||||
database. Along with it a new instance of ``ContentType`` will be created with
|
|
||||||
the following values:
|
|
||||||
|
|
||||||
* ``app_label`` will be set to ``'sites'`` (the last part of the Python
|
|
||||||
path "django.contrib.sites").
|
|
||||||
|
|
||||||
* ``model`` will be set to ``'site'``.
|
|
||||||
|
|
||||||
* ``name`` will be set to ``'site'``.
|
|
||||||
|
|
||||||
.. _the verbose_name attribute: ../model-api/#verbose_name
|
|
||||||
.. _the sites application: ../sites/
|
|
||||||
|
|
||||||
Methods on ``ContentType`` instances
|
|
||||||
====================================
|
|
||||||
|
|
||||||
Each ``ContentType`` instance has methods that allow you to get from a
|
|
||||||
``ContentType`` instance to the model it represents, or to retrieve objects
|
|
||||||
from that model:
|
|
||||||
|
|
||||||
``get_object_for_this_type(**kwargs)``
|
|
||||||
Takes a set of valid `lookup arguments`_ for the model the
|
|
||||||
``ContentType`` represents, and does `a get() lookup`_ on that
|
|
||||||
model, returning the corresponding object.
|
|
||||||
|
|
||||||
``model_class()``
|
|
||||||
Returns the model class represented by this ``ContentType``
|
|
||||||
instance.
|
|
||||||
|
|
||||||
For example, we could look up the ``ContentType`` for the ``User`` model::
|
|
||||||
|
|
||||||
>>> from django.contrib.contenttypes.models import ContentType
|
|
||||||
>>> user_type = ContentType.objects.get(app_label="auth", model="user")
|
|
||||||
>>> user_type
|
|
||||||
<ContentType: user>
|
|
||||||
|
|
||||||
And then use it to query for a particular ``User``, or to get access
|
|
||||||
to the ``User`` model class::
|
|
||||||
|
|
||||||
>>> user_type.model_class()
|
|
||||||
<class 'django.contrib.auth.models.User'>
|
|
||||||
>>> user_type.get_object_for_this_type(username='Guido')
|
|
||||||
<User: Guido>
|
|
||||||
|
|
||||||
Together, ``get_object_for_this_type`` and ``model_class`` enable two
|
|
||||||
extremely important use cases:
|
|
||||||
|
|
||||||
1. Using these methods, you can write high-level generic code that
|
|
||||||
performs queries on any installed model -- instead of importing and
|
|
||||||
using a single specific model class, you can pass an ``app_label``
|
|
||||||
and ``model`` into a ``ContentType`` lookup at runtime, and then
|
|
||||||
work with the model class or retrieve objects from it.
|
|
||||||
|
|
||||||
2. You can relate another model to ``ContentType`` as a way of tying
|
|
||||||
instances of it to particular model classes, and use these methods
|
|
||||||
to get access to those model classes.
|
|
||||||
|
|
||||||
Several of Django's bundled applications make use of the latter
|
|
||||||
technique. For example, `the permissions system`_ in Django's
|
|
||||||
authentication framework uses a ``Permission`` model with a foreign
|
|
||||||
key to ``ContentType``; this lets ``Permission`` represent concepts
|
|
||||||
like "can add blog entry" or "can delete news story".
|
|
||||||
|
|
||||||
.. _lookup arguments: ../db-api/#field-lookups
|
|
||||||
.. _a get() lookup: ../db-api/#get-kwargs
|
|
||||||
.. _the permissions system: ../authentication/#permissions
|
|
||||||
|
|
||||||
The ``ContentTypeManager``
|
|
||||||
--------------------------
|
|
||||||
|
|
||||||
``ContentType`` also has a custom manager, ``ContentTypeManager``,
|
|
||||||
which adds the following methods:
|
|
||||||
|
|
||||||
``clear_cache()``
|
|
||||||
Clears an internal cache used by ``ContentType`` to keep track of which
|
|
||||||
models for which it has created ``ContentType`` instances. You probably
|
|
||||||
won't ever need to call this method yourself; Django will call it
|
|
||||||
automatically when it's needed.
|
|
||||||
|
|
||||||
``get_for_model(model)``
|
|
||||||
Takes either a model class or an instance of a model, and returns the
|
|
||||||
``ContentType`` instance representing that model.
|
|
||||||
|
|
||||||
The ``get_for_model`` method is especially useful when you know you
|
|
||||||
need to work with a ``ContentType`` but don't want to go to the
|
|
||||||
trouble of obtaining the model's metadata to perform a manual lookup::
|
|
||||||
|
|
||||||
>>> from django.contrib.auth.models import User
|
|
||||||
>>> user_type = ContentType.objects.get_for_model(User)
|
|
||||||
>>> user_type
|
|
||||||
<ContentType: user>
|
|
||||||
|
|
||||||
Generic relations
|
|
||||||
=================
|
|
||||||
|
|
||||||
Adding a foreign key from one of your own models to ``ContentType``
|
|
||||||
allows your model to effectively tie itself to another model class, as
|
|
||||||
in the example of the ``Permission`` model above. But it's possible to
|
|
||||||
go one step further and use ``ContentType`` to enable truly generic
|
|
||||||
(sometimes called "polymorphic") relationships between models.
|
|
||||||
|
|
||||||
A simple example is a tagging system, which might look like this::
|
|
||||||
|
|
||||||
from django.db import models
|
|
||||||
from django.contrib.contenttypes.models import ContentType
|
|
||||||
from django.contrib.contenttypes import generic
|
|
||||||
|
|
||||||
class TaggedItem(models.Model):
|
|
||||||
tag = models.SlugField()
|
|
||||||
content_type = models.ForeignKey(ContentType)
|
|
||||||
object_id = models.PositiveIntegerField()
|
|
||||||
content_object = generic.GenericForeignKey('content_type', 'object_id')
|
|
||||||
|
|
||||||
def __unicode__(self):
|
|
||||||
return self.tag
|
|
||||||
|
|
||||||
A normal ``ForeignKey`` can only "point to" one other model, which
|
|
||||||
means that if the ``TaggedItem`` model used a ``ForeignKey`` it would have to
|
|
||||||
choose one and only one model to store tags for. The contenttypes
|
|
||||||
application provides a special field type --
|
|
||||||
``django.contrib.contenttypes.generic.GenericForeignKey`` -- which
|
|
||||||
works around this and allows the relationship to be with any
|
|
||||||
model. There are three parts to setting up a ``GenericForeignKey``:
|
|
||||||
|
|
||||||
1. Give your model a ``ForeignKey`` to ``ContentType``.
|
|
||||||
|
|
||||||
2. Give your model a field that can store a primary-key value from the
|
|
||||||
models you'll be relating to. (For most models, this means an
|
|
||||||
``IntegerField`` or ``PositiveIntegerField``.)
|
|
||||||
|
|
||||||
This field must be of the same type as the primary key of the models
|
|
||||||
that will be involved in the generic relation. For example, if you use
|
|
||||||
``IntegerField``, you won't be able to form a generic relation with a
|
|
||||||
model that uses a ``CharField`` as a primary key.
|
|
||||||
|
|
||||||
3. Give your model a ``GenericForeignKey``, and pass it the names of
|
|
||||||
the two fields described above. If these fields are named
|
|
||||||
"content_type" and "object_id", you can omit this -- those are the
|
|
||||||
default field names ``GenericForeignKey`` will look for.
|
|
||||||
|
|
||||||
This will enable an API similar to the one used for a normal ``ForeignKey``;
|
|
||||||
each ``TaggedItem`` will have a ``content_object`` field that returns the
|
|
||||||
object it's related to, and you can also assign to that field or use it when
|
|
||||||
creating a ``TaggedItem``::
|
|
||||||
|
|
||||||
>>> from django.contrib.auth.models import User
|
|
||||||
>>> guido = User.objects.get(username='Guido')
|
|
||||||
>>> t = TaggedItem(content_object=guido, tag='bdfl')
|
|
||||||
>>> t.save()
|
|
||||||
>>> t.content_object
|
|
||||||
<User: Guido>
|
|
||||||
|
|
||||||
Due to the way ``GenericForeignKey`` is implemeneted, you cannot use such
|
|
||||||
fields directly with filters (``filter()`` and ``exclude()``, for example) via
|
|
||||||
the database API. They aren't normal field objects. These examples will *not*
|
|
||||||
work::
|
|
||||||
|
|
||||||
# This will fail
|
|
||||||
>>> TaggedItem.objects.filter(content_object=guido)
|
|
||||||
# This will also fail
|
|
||||||
>>> TaggedItem.objects.get(content_object=guido)
|
|
||||||
|
|
||||||
Reverse generic relations
|
|
||||||
-------------------------
|
|
||||||
|
|
||||||
If you know which models you'll be using most often, you can also add
|
|
||||||
a "reverse" generic relationship to enable an additional API. For example::
|
|
||||||
|
|
||||||
class Bookmark(models.Model):
|
|
||||||
url = models.URLField()
|
|
||||||
tags = generic.GenericRelation(TaggedItem)
|
|
||||||
|
|
||||||
``Bookmark`` instances will each have a ``tags`` attribute, which can
|
|
||||||
be used to retrieve their associated ``TaggedItems``::
|
|
||||||
|
|
||||||
>>> b = Bookmark(url='http://www.djangoproject.com/')
|
|
||||||
>>> b.save()
|
|
||||||
>>> t1 = TaggedItem(content_object=b, tag='django')
|
|
||||||
>>> t1.save()
|
|
||||||
>>> t2 = TaggedItem(content_object=b, tag='python')
|
|
||||||
>>> t2.save()
|
|
||||||
>>> b.tags.all()
|
|
||||||
[<TaggedItem: django>, <TaggedItem: python>]
|
|
||||||
|
|
||||||
If you don't add the reverse relationship, you can do the lookup manually::
|
|
||||||
|
|
||||||
>>> b = Bookmark.objects.get(url='http://www.djangoproject.com/)
|
|
||||||
>>> bookmark_type = ContentType.objects.get_for_model(b)
|
|
||||||
>>> TaggedItem.objects.filter(content_type__pk=bookmark_type.id,
|
|
||||||
... object_id=b.id)
|
|
||||||
[<TaggedItem: django>, <TaggedItem: python>]
|
|
||||||
|
|
||||||
Note that if you delete an object that has a ``GenericRelation``, any objects
|
|
||||||
which have a ``GenericForeignKey`` pointing at it will be deleted as well. In
|
|
||||||
the example above, this means that if a ``Bookmark`` object were deleted, any
|
|
||||||
``TaggedItem`` objects pointing at it would be deleted at the same time.
|
|
||||||
|
|
||||||
Generic relations in forms and admin
|
|
||||||
------------------------------------
|
|
||||||
|
|
||||||
``django.contrib.contenttypes.generic`` provides both a ``GenericInlineFormSet``
|
|
||||||
and ``GenericInlineModelAdmin``. This enables the use of generic relations in
|
|
||||||
forms and the admin. See the `model formset`_ and `admin`_ documentation for
|
|
||||||
more information.
|
|
||||||
|
|
||||||
``GenericInlineModelAdmin`` options
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
The ``GenericInlineModelAdmin`` class inherits all properties from an
|
|
||||||
``InlineModelAdmin`` class. However, it adds a couple of its own for working
|
|
||||||
with the generic relation:
|
|
||||||
|
|
||||||
* ``ct_field`` - The name of the ``ContentType`` foreign key field on the
|
|
||||||
model. Defaults to ``content_type``.
|
|
||||||
|
|
||||||
* ``ct_fk_field`` - The name of the integer field that represents the ID
|
|
||||||
of the related object. Defaults to ``object_id``.
|
|
||||||
|
|
||||||
.. _model formset: ../modelforms/
|
|
||||||
.. _admin: ../admin/
|
|
2421
docs/db-api.txt
|
@ -1,138 +0,0 @@
|
||||||
====================================
|
|
||||||
How to read the Django documentation
|
|
||||||
====================================
|
|
||||||
|
|
||||||
We've put a lot of effort into making Django's documentation useful, easy to
|
|
||||||
read and as complete as possible. Here are a few tips on how to make the best
|
|
||||||
of it, along with some style guidelines.
|
|
||||||
|
|
||||||
(Yes, this is documentation about documentation. Rest assured we have no plans
|
|
||||||
to write a document about how to read the document about documentation.)
|
|
||||||
|
|
||||||
How documentation is updated
|
|
||||||
============================
|
|
||||||
|
|
||||||
Just as the Django code base is developed and improved on a daily basis, our
|
|
||||||
documentation is consistently improving. We improve documentation for several
|
|
||||||
reasons:
|
|
||||||
|
|
||||||
* To make content fixes, such as grammar/typo corrections.
|
|
||||||
* To add information and/or examples to existing sections that need to be
|
|
||||||
expanded.
|
|
||||||
* To document Django features that aren't yet documented. (The list of
|
|
||||||
such features is shrinking but exists nonetheless.)
|
|
||||||
* To add documentation for new features as new features get added, or as
|
|
||||||
Django APIs or behaviors change.
|
|
||||||
|
|
||||||
Django's documentation is kept in the same source control system as its code.
|
|
||||||
It lives in the `django/trunk/docs`_ directory of our Subversion repository.
|
|
||||||
Each document is a separate text file that covers a narrowly focused topic,
|
|
||||||
such as the "generic views" framework or how to construct a database model.
|
|
||||||
|
|
||||||
.. _django/trunk/docs: http://code.djangoproject.com/browser/django/trunk/docs
|
|
||||||
|
|
||||||
Where to get it
|
|
||||||
===============
|
|
||||||
|
|
||||||
You can read Django documentation in several ways. They are, in order of
|
|
||||||
preference:
|
|
||||||
|
|
||||||
On the Web
|
|
||||||
----------
|
|
||||||
|
|
||||||
The most recent version of the Django documentation lives at
|
|
||||||
http://www.djangoproject.com/documentation/ . These HTML pages are generated
|
|
||||||
automatically from the text files in source control. That means they reflect
|
|
||||||
the "latest and greatest" in Django -- they include the very latest
|
|
||||||
corrections and additions, and they discuss the latest Django features,
|
|
||||||
which may only be available to users of the Django development version. (See
|
|
||||||
"Differences between versions" below.)
|
|
||||||
|
|
||||||
We encourage you to help improve the docs by submitting changes, corrections
|
|
||||||
and suggestions in the `ticket system`_. The Django developers actively monitor
|
|
||||||
the ticket system and use your feedback to improve the documentation for
|
|
||||||
everybody.
|
|
||||||
|
|
||||||
Note, however, that tickets should explicitly relate to the documentation,
|
|
||||||
rather than asking broad tech-support questions. If you need help with your
|
|
||||||
particular Django setup, try the `django-users mailing list`_ or the
|
|
||||||
`#django IRC channel`_ instead.
|
|
||||||
|
|
||||||
.. _ticket system: http://code.djangoproject.com/simpleticket?component=Documentation
|
|
||||||
.. _django-users mailing list: http://groups.google.com/group/django-users
|
|
||||||
.. _#django IRC channel: irc://irc.freenode.net/django
|
|
||||||
|
|
||||||
In plain text
|
|
||||||
-------------
|
|
||||||
|
|
||||||
For offline reading, or just for convenience, you can read the Django
|
|
||||||
documentation in plain text.
|
|
||||||
|
|
||||||
If you're using an official release of Django, note that the zipped package
|
|
||||||
(tarball) of the code includes a ``docs/`` directory, which contains all the
|
|
||||||
documentation for that release.
|
|
||||||
|
|
||||||
If you're using the development version of Django (aka the Subversion "trunk"),
|
|
||||||
note that the ``docs/`` directory contains all of the documentation. You can
|
|
||||||
``svn update`` it, just as you ``svn update`` the Python code, in order to get
|
|
||||||
the latest changes.
|
|
||||||
|
|
||||||
You can check out the latest Django documentation from Subversion using this
|
|
||||||
shell command::
|
|
||||||
|
|
||||||
svn co http://code.djangoproject.com/svn/django/trunk/docs/ django_docs
|
|
||||||
|
|
||||||
One low-tech way of taking advantage of the text documentation is by using the
|
|
||||||
Unix ``grep`` utility to search for a phrase in all of the documentation. For
|
|
||||||
example, this will show you each mention of the phrase "edit_inline" in any
|
|
||||||
Django document::
|
|
||||||
|
|
||||||
grep edit_inline /path/to/django/docs/*.txt
|
|
||||||
|
|
||||||
Formatting
|
|
||||||
~~~~~~~~~~
|
|
||||||
|
|
||||||
The text documentation is written in ReST (ReStructured Text) format. That
|
|
||||||
means it's easy to read but is also formatted in a way that makes it easy to
|
|
||||||
convert into other formats, such as HTML. If you have the `reStructuredText`_
|
|
||||||
library installed, you can use ``rst2html`` to generate your own HTML files.
|
|
||||||
|
|
||||||
.. _reStructuredText: http://docutils.sourceforge.net/rst.html
|
|
||||||
|
|
||||||
Differences between versions
|
|
||||||
============================
|
|
||||||
|
|
||||||
As previously mentioned, the text documentation in our Subversion repository
|
|
||||||
contains the "latest and greatest" changes and additions. These changes often
|
|
||||||
include documentation of new features added in the Django development version
|
|
||||||
-- the Subversion ("trunk") version of Django. For that reason, it's worth
|
|
||||||
pointing out our policy on keeping straight the documentation for various
|
|
||||||
versions of the framework.
|
|
||||||
|
|
||||||
We follow this policy:
|
|
||||||
|
|
||||||
* The primary documentation on djangoproject.com is an HTML version of the
|
|
||||||
latest docs in Subversion. These docs always correspond to the latest
|
|
||||||
official Django release, plus whatever features we've added/changed in
|
|
||||||
the framework *since* the latest release.
|
|
||||||
|
|
||||||
* As we add features to Django's development version, we try to update the
|
|
||||||
documentation in the same Subversion commit transaction.
|
|
||||||
|
|
||||||
* To distinguish feature changes/additions in the docs, we use the phrase
|
|
||||||
**New in Django development version**. In practice, this means that the
|
|
||||||
current documentation on djangoproject.com can be used by users of either
|
|
||||||
the latest release *or* the development version.
|
|
||||||
|
|
||||||
* Documentation for a particular Django release is frozen once the version
|
|
||||||
has been released officially. It remains a snapshot of the docs as of the
|
|
||||||
moment of the release. We will make exceptions to this rule in
|
|
||||||
the case of retroactive security updates or other such retroactive
|
|
||||||
changes. Once documentation is frozen, we add a note to the top of each
|
|
||||||
frozen document that says "These docs are frozen for Django version XXX"
|
|
||||||
and links to the current version of that document.
|
|
||||||
|
|
||||||
* The `main documentation Web page`_ includes links to documentation for
|
|
||||||
all previous versions.
|
|
||||||
|
|
||||||
.. _main documentation Web page: http://www.djangoproject.com/documentation/
|
|
744
docs/faq.txt
|
@ -1,744 +0,0 @@
|
||||||
==========
|
|
||||||
Django FAQ
|
|
||||||
==========
|
|
||||||
|
|
||||||
General questions
|
|
||||||
=================
|
|
||||||
|
|
||||||
Why does this project exist?
|
|
||||||
----------------------------
|
|
||||||
|
|
||||||
Django grew from a very practical need: World Online, a newspaper Web
|
|
||||||
operation, is responsible for building intensive Web applications on journalism
|
|
||||||
deadlines. In the fast-paced newsroom, World Online often has only a matter of
|
|
||||||
hours to take a complicated Web application from concept to public launch.
|
|
||||||
|
|
||||||
At the same time, the World Online Web developers have consistently been
|
|
||||||
perfectionists when it comes to following best practices of Web development.
|
|
||||||
|
|
||||||
In fall 2003, the World Online developers (Adrian Holovaty and Simon Willison)
|
|
||||||
ditched PHP and began using Python to develop its Web sites. As they built
|
|
||||||
intensive, richly interactive sites such as Lawrence.com, they began to extract
|
|
||||||
a generic Web development framework that let them build Web applications more
|
|
||||||
and more quickly. They tweaked this framework constantly, adding improvements
|
|
||||||
over two years.
|
|
||||||
|
|
||||||
In summer 2005, World Online decided to open-source the resulting software,
|
|
||||||
Django. Django would not be possible without a whole host of open-source
|
|
||||||
projects -- `Apache`_, `Python`_, and `PostgreSQL`_ to name a few -- and we're
|
|
||||||
thrilled to be able to give something back to the open-source community.
|
|
||||||
|
|
||||||
.. _Apache: http://httpd.apache.org/
|
|
||||||
.. _Python: http://www.python.org/
|
|
||||||
.. _PostgreSQL: http://www.postgresql.org/
|
|
||||||
|
|
||||||
What does "Django" mean, and how do you pronounce it?
|
|
||||||
-----------------------------------------------------
|
|
||||||
|
|
||||||
Django is named after `Django Reinhardt`_, a gypsy jazz guitarist from the 1930s
|
|
||||||
to early 1950s. To this day, he's considered one of the best guitarists of all time.
|
|
||||||
|
|
||||||
Listen to his music. You'll like it.
|
|
||||||
|
|
||||||
Django is pronounced **JANG**-oh. Rhymes with FANG-oh. The "D" is silent.
|
|
||||||
|
|
||||||
We've also recorded an `audio clip of the pronunciation`_.
|
|
||||||
|
|
||||||
.. _Django Reinhardt: http://en.wikipedia.org/wiki/Django_Reinhardt
|
|
||||||
.. _audio clip of the pronunciation: http://red-bean.com/~adrian/django_pronunciation.mp3
|
|
||||||
|
|
||||||
Is Django stable?
|
|
||||||
-----------------
|
|
||||||
|
|
||||||
Yes. World Online has been using Django for more than three years. Sites built
|
|
||||||
on Django have weathered traffic spikes of over one million hits an hour and a
|
|
||||||
number of Slashdottings. Yes, it's quite stable.
|
|
||||||
|
|
||||||
Does Django scale?
|
|
||||||
------------------
|
|
||||||
|
|
||||||
Yes. Compared to development time, hardware is cheap, and so Django is
|
|
||||||
designed to take advantage of as much hardware as you can throw at it.
|
|
||||||
|
|
||||||
Django uses a "shared-nothing" architecture, which means you can add hardware
|
|
||||||
at any level -- database servers, caching servers or Web/application servers.
|
|
||||||
|
|
||||||
The framework cleanly separates components such as its database layer and
|
|
||||||
application layer. And it ships with a simple-yet-powerful `cache framework`_.
|
|
||||||
|
|
||||||
.. _`cache framework`: ../cache/
|
|
||||||
|
|
||||||
Who's behind this?
|
|
||||||
------------------
|
|
||||||
|
|
||||||
Django was developed at `World Online`_, the Web department of a newspaper in
|
|
||||||
Lawrence, Kansas, USA.
|
|
||||||
|
|
||||||
`Adrian Holovaty`_
|
|
||||||
Adrian is a Web developer with a background in journalism. He was lead
|
|
||||||
developer at World Online for 2.5 years, during which time Django was
|
|
||||||
developed and implemented on World Online's sites. Now he works for
|
|
||||||
washingtonpost.com building rich, database-backed information sites, and
|
|
||||||
continues to oversee Django development. He likes playing guitar (Django
|
|
||||||
Reinhardt style) and hacking on side projects such as `chicagocrime.org`_.
|
|
||||||
He lives in Chicago.
|
|
||||||
|
|
||||||
On IRC, Adrian goes by ``adrian_h``.
|
|
||||||
|
|
||||||
`Jacob Kaplan-Moss`_
|
|
||||||
Jacob is a whipper-snapper from California who spends equal time coding and
|
|
||||||
cooking. He's lead developer at World Online and actively hacks on various
|
|
||||||
cool side projects. He's contributed to the Python-ObjC bindings and was
|
|
||||||
the first guy to figure out how to write Tivo apps in Python. Lately he's
|
|
||||||
been messing with Python on the PSP. He lives in Lawrence, Kansas.
|
|
||||||
|
|
||||||
On IRC, Jacob goes by ``jacobkm``.
|
|
||||||
|
|
||||||
`Simon Willison`_
|
|
||||||
Simon is a well-respected Web developer from England. He had a one-year
|
|
||||||
internship at World Online, during which time he and Adrian developed
|
|
||||||
Django from scratch. The most enthusiastic Brit you'll ever meet, he's
|
|
||||||
passionate about best practices in Web development and has maintained a
|
|
||||||
well-read Web-development blog for years at http://simon.incutio.com.
|
|
||||||
He works for Yahoo UK, where he managed to score the title "Hacker Liason."
|
|
||||||
He lives in London.
|
|
||||||
|
|
||||||
On IRC, Simon goes by ``SimonW``.
|
|
||||||
|
|
||||||
`Wilson Miner`_
|
|
||||||
Wilson's design-fu makes us all look like rock stars. By day, he's an
|
|
||||||
interactive designer for `Apple`_. Don't ask him what he's working on, or
|
|
||||||
he'll have to kill you. He lives in San Francisco.
|
|
||||||
|
|
||||||
On IRC, Wilson goes by ``wilsonian``.
|
|
||||||
|
|
||||||
.. _`World Online`: http://code.djangoproject.com/wiki/WorldOnline
|
|
||||||
.. _`Adrian Holovaty`: http://www.holovaty.com/
|
|
||||||
.. _`washingtonpost.com`: http://www.washingtonpost.com/
|
|
||||||
.. _`chicagocrime.org`: http://www.chicagocrime.org/
|
|
||||||
.. _`Simon Willison`: http://simon.incutio.com/
|
|
||||||
.. _`simon.incutio.com`: http://simon.incutio.com/
|
|
||||||
.. _`Jacob Kaplan-Moss`: http://www.jacobian.org/
|
|
||||||
.. _`Wilson Miner`: http://www.wilsonminer.com/
|
|
||||||
.. _`Apple`: http://www.apple.com/
|
|
||||||
|
|
||||||
Which sites use Django?
|
|
||||||
-----------------------
|
|
||||||
|
|
||||||
The Django wiki features a consistently growing `list of Django-powered sites`_.
|
|
||||||
Feel free to add your Django-powered site to the list.
|
|
||||||
|
|
||||||
.. _list of Django-powered sites: http://code.djangoproject.com/wiki/DjangoPoweredSites
|
|
||||||
|
|
||||||
Django appears to be a MVC framework, but you call the Controller the "view", and the View the "template". How come you don't use the standard names?
|
|
||||||
-----------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
Well, the standard names are debatable.
|
|
||||||
|
|
||||||
In our interpretation of MVC, the "view" describes the data that gets presented
|
|
||||||
to the user. It's not necessarily *how* the data *looks*, but *which* data is
|
|
||||||
presented. The view describes *which data you see*, not *how you see it.* It's
|
|
||||||
a subtle distinction.
|
|
||||||
|
|
||||||
So, in our case, a "view" is the Python callback function for a particular URL,
|
|
||||||
because that callback function describes which data is presented.
|
|
||||||
|
|
||||||
Furthermore, it's sensible to separate content from presentation -- which is
|
|
||||||
where templates come in. In Django, a "view" describes which data is presented,
|
|
||||||
but a view normally delegates to a template, which describes *how* the data is
|
|
||||||
presented.
|
|
||||||
|
|
||||||
Where does the "controller" fit in, then? In Django's case, it's probably the
|
|
||||||
framework itself: the machinery that sends a request to the appropriate view,
|
|
||||||
according to the Django URL configuration.
|
|
||||||
|
|
||||||
If you're hungry for acronyms, you might say that Django is a "MTV" framework
|
|
||||||
-- that is, "model", "template", and "view." That breakdown makes much more
|
|
||||||
sense.
|
|
||||||
|
|
||||||
At the end of the day, of course, it comes down to getting stuff done. And,
|
|
||||||
regardless of how things are named, Django gets stuff done in a way that's most
|
|
||||||
logical to us.
|
|
||||||
|
|
||||||
<Framework X> does <feature Y> -- why doesn't Django?
|
|
||||||
-----------------------------------------------------
|
|
||||||
|
|
||||||
We're well aware that there are other awesome Web frameworks out there, and
|
|
||||||
we're not averse to borrowing ideas where appropriate. However, Django was
|
|
||||||
developed precisely because we were unhappy with the status quo, so please be
|
|
||||||
aware that "because <Framework X> does it" is not going to be sufficient reason
|
|
||||||
to add a given feature to Django.
|
|
||||||
|
|
||||||
Why did you write all of Django from scratch, instead of using other Python libraries?
|
|
||||||
--------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
When Django was originally written a couple of years ago, Adrian and Simon
|
|
||||||
spent quite a bit of time exploring the various Python Web frameworks
|
|
||||||
available.
|
|
||||||
|
|
||||||
In our opinion, none of them were completely up to snuff.
|
|
||||||
|
|
||||||
We're picky. You might even call us perfectionists. (With deadlines.)
|
|
||||||
|
|
||||||
Over time, we stumbled across open-source libraries that did things we'd
|
|
||||||
already implemented. It was reassuring to see other people solving similar
|
|
||||||
problems in similar ways, but it was too late to integrate outside code: We'd
|
|
||||||
already written, tested and implemented our own framework bits in several
|
|
||||||
production settings -- and our own code met our needs delightfully.
|
|
||||||
|
|
||||||
In most cases, however, we found that existing frameworks/tools inevitably had
|
|
||||||
some sort of fundamental, fatal flaw that made us squeamish. No tool fit our
|
|
||||||
philosophies 100%.
|
|
||||||
|
|
||||||
Like we said: We're picky.
|
|
||||||
|
|
||||||
We've documented our philosophies on the `design philosophies page`_.
|
|
||||||
|
|
||||||
.. _design philosophies page: ../design_philosophies/
|
|
||||||
|
|
||||||
Do you have any of those nifty "screencast" things?
|
|
||||||
---------------------------------------------------
|
|
||||||
|
|
||||||
You can bet your bottom they're on the way. But, since we're still hammering
|
|
||||||
out a few points, we want to make sure they reflect the final state of things
|
|
||||||
at Django 1.0, not some intermediary step. In other words, we don't want to
|
|
||||||
spend a lot of energy creating screencasts yet, because Django APIs will shift.
|
|
||||||
|
|
||||||
Is Django a content-management-system (CMS)?
|
|
||||||
--------------------------------------------
|
|
||||||
|
|
||||||
No, Django is not a CMS, or any sort of "turnkey product" in and of itself.
|
|
||||||
It's a Web framework; it's a programming tool that lets you build Web sites.
|
|
||||||
|
|
||||||
For example, it doesn't make much sense to compare Django to something like
|
|
||||||
Drupal_, because Django is something you use to *create* things like Drupal.
|
|
||||||
|
|
||||||
Of course, Django's automatic admin site is fantastic and timesaving -- but
|
|
||||||
the admin site is one module of Django the framework. Furthermore, although
|
|
||||||
Django has special conveniences for building "CMS-y" apps, that doesn't mean
|
|
||||||
it's not just as appropriate for building "non-CMS-y" apps (whatever that
|
|
||||||
means!).
|
|
||||||
|
|
||||||
.. _Drupal: http://drupal.org/
|
|
||||||
|
|
||||||
When will you release Django 1.0?
|
|
||||||
---------------------------------
|
|
||||||
|
|
||||||
See our `version one roadmap`_ for the detailed timeline. We're aiming for
|
|
||||||
September 2, 2008.
|
|
||||||
|
|
||||||
.. _version one roadmap: http://code.djangoproject.com/wiki/VersionOneRoadmap
|
|
||||||
|
|
||||||
How can I download the Django documentation to read it offline?
|
|
||||||
---------------------------------------------------------------
|
|
||||||
|
|
||||||
The Django docs are available in the ``docs`` directory of each Django tarball
|
|
||||||
release. These docs are in ReST (ReStructured Text) format, and each text file
|
|
||||||
corresponds to a Web page on the official Django site.
|
|
||||||
|
|
||||||
Because the documentation is `stored in revision control`_, you can browse
|
|
||||||
documentation changes just like you can browse code changes.
|
|
||||||
|
|
||||||
Technically, the docs on Django's site are generated from the latest development
|
|
||||||
versions of those ReST documents, so the docs on the Django site may offer more
|
|
||||||
information than the docs that come with the latest Django release.
|
|
||||||
|
|
||||||
.. _stored in revision control: http://code.djangoproject.com/browser/django/trunk/docs
|
|
||||||
|
|
||||||
Where can I find Django developers for hire?
|
|
||||||
--------------------------------------------
|
|
||||||
|
|
||||||
Consult our `developers for hire page`_ for a list of Django developers who
|
|
||||||
would be happy to help you.
|
|
||||||
|
|
||||||
You might also be interested in posting a job to http://djangogigs.com/ .
|
|
||||||
If you want to find Django-capable people in your local area, try
|
|
||||||
http://djangopeople.net/ .
|
|
||||||
|
|
||||||
.. _developers for hire page: http://code.djangoproject.com/wiki/DevelopersForHire
|
|
||||||
|
|
||||||
Installation questions
|
|
||||||
======================
|
|
||||||
|
|
||||||
How do I get started?
|
|
||||||
---------------------
|
|
||||||
|
|
||||||
#. `Download the code`_.
|
|
||||||
#. Install Django (read the `installation guide`_).
|
|
||||||
#. Walk through the tutorial_.
|
|
||||||
#. Check out the rest of the documentation_, and `ask questions`_ if you
|
|
||||||
run into trouble.
|
|
||||||
|
|
||||||
.. _`Download the code`: http://www.djangoproject.com/download/
|
|
||||||
.. _`installation guide`: ../install/
|
|
||||||
.. _tutorial: ../tutorial01/
|
|
||||||
.. _documentation: ../
|
|
||||||
.. _ask questions: http://www.djangoproject.com/community/
|
|
||||||
|
|
||||||
How do I fix the "install a later version of setuptools" error?
|
|
||||||
---------------------------------------------------------------
|
|
||||||
|
|
||||||
Just run the ``ez_setup.py`` script in the Django distribution.
|
|
||||||
|
|
||||||
What are Django's prerequisites?
|
|
||||||
--------------------------------
|
|
||||||
|
|
||||||
Django requires Python_ 2.3 or later. No other Python libraries are required
|
|
||||||
for basic Django usage.
|
|
||||||
|
|
||||||
For a development environment -- if you just want to experiment with Django --
|
|
||||||
you don't need to have a separate Web server installed; Django comes with its
|
|
||||||
own lightweight development server. For a production environment, we recommend
|
|
||||||
`Apache 2`_ and mod_python_, although Django follows the WSGI_ spec, which
|
|
||||||
means it can run on a variety of server platforms.
|
|
||||||
|
|
||||||
If you want to use Django with a database, which is probably the case, you'll
|
|
||||||
also need a database engine. PostgreSQL_ is recommended, because we're
|
|
||||||
PostgreSQL fans, and MySQL_, `SQLite 3`_, and Oracle_ are also supported.
|
|
||||||
|
|
||||||
.. _Python: http://www.python.org/
|
|
||||||
.. _Apache 2: http://httpd.apache.org/
|
|
||||||
.. _mod_python: http://www.modpython.org/
|
|
||||||
.. _WSGI: http://www.python.org/peps/pep-0333.html
|
|
||||||
.. _PostgreSQL: http://www.postgresql.org/
|
|
||||||
.. _MySQL: http://www.mysql.com/
|
|
||||||
.. _`SQLite 3`: http://www.sqlite.org/
|
|
||||||
.. _Oracle: http://www.oracle.com/
|
|
||||||
|
|
||||||
Do I lose anything by using Python 2.3 versus newer Python versions, such as Python 2.5?
|
|
||||||
----------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
No. Django itself is guaranteed to work with any version of Python from 2.3
|
|
||||||
and higher.
|
|
||||||
|
|
||||||
If you use a Python version newer than 2.3, you will, of course, be able to
|
|
||||||
take advantage of newer Python features in your own code, along with the speed
|
|
||||||
improvements and other optimizations that have been made to the Python language
|
|
||||||
itself. But the Django framework itself should work equally well on 2.3 as it
|
|
||||||
does on 2.4 or 2.5.
|
|
||||||
|
|
||||||
Do I have to use mod_python?
|
|
||||||
----------------------------
|
|
||||||
|
|
||||||
Although we recommend mod_python for production use, you don't have to use it,
|
|
||||||
thanks to the fact that Django uses an arrangement called WSGI_. Django can
|
|
||||||
talk to any WSGI-enabled server. Other non-mod_python deployment setups are
|
|
||||||
FastCGI, SCGI or AJP. See `How to use Django with FastCGI, SCGI or AJP`_ for
|
|
||||||
full information.
|
|
||||||
|
|
||||||
Also, see the `server arrangements wiki page`_ for other deployment strategies.
|
|
||||||
|
|
||||||
If you just want to play around and develop things on your local computer, use
|
|
||||||
the development Web server that comes with Django. Things should Just Work.
|
|
||||||
|
|
||||||
.. _WSGI: http://www.python.org/peps/pep-0333.html
|
|
||||||
.. _How to use Django with FastCGI, SCGI or AJP: ../fastcgi/
|
|
||||||
.. _server arrangements wiki page: http://code.djangoproject.com/wiki/ServerArrangements
|
|
||||||
|
|
||||||
How do I install mod_python on Windows?
|
|
||||||
---------------------------------------
|
|
||||||
|
|
||||||
* For Python 2.4, grab mod_python from `win32 build of mod_python for
|
|
||||||
Python 2.4`_.
|
|
||||||
* For Python 2.4, check out this `Django on Windows howto`_.
|
|
||||||
* For Python 2.3, grab mod_python from http://www.modpython.org/ and read
|
|
||||||
`Running mod_python on Apache on Windows2000`_.
|
|
||||||
* Also, try this (not Windows-specific) `guide to getting mod_python
|
|
||||||
working`_.
|
|
||||||
|
|
||||||
.. _`win32 build of mod_python for Python 2.4`: http://www.lehuen.com/nicolas/index.php/2005/02/21/39-win32-build-of-mod_python-314-for-python-24
|
|
||||||
.. _`Django on Windows howto`: http://thinkhole.org/wp/django-on-windows/
|
|
||||||
.. _`Running mod_python on Apache on Windows2000`: http://groups-beta.google.com/group/comp.lang.python/msg/139af8c83a5a9d4f
|
|
||||||
.. _`guide to getting mod_python working`: http://www.dscpl.com.au/articles/modpython-001.html
|
|
||||||
|
|
||||||
Will Django run under shared hosting (like TextDrive or Dreamhost)?
|
|
||||||
-------------------------------------------------------------------
|
|
||||||
|
|
||||||
See our `Django-friendly Web hosts`_ page.
|
|
||||||
|
|
||||||
.. _`Django-friendly Web hosts`: http://code.djangoproject.com/wiki/DjangoFriendlyWebHosts
|
|
||||||
|
|
||||||
Should I use the official version or development version?
|
|
||||||
---------------------------------------------------------
|
|
||||||
|
|
||||||
The Django developers improve Django every day and are pretty good about not
|
|
||||||
checking in broken code. We use the development code (from the Subversion
|
|
||||||
repository) directly on our servers, so we consider it stable. With that in
|
|
||||||
mind, we recommend that you use the latest development code, because it
|
|
||||||
generally contains more features and fewer bugs than the "official" releases.
|
|
||||||
|
|
||||||
Using Django
|
|
||||||
============
|
|
||||||
|
|
||||||
Why do I get an error about importing DJANGO_SETTINGS_MODULE?
|
|
||||||
-------------------------------------------------------------
|
|
||||||
|
|
||||||
Make sure that:
|
|
||||||
|
|
||||||
* The environment variable DJANGO_SETTINGS_MODULE is set to a fully-qualified
|
|
||||||
Python module (i.e. "mysite.settings").
|
|
||||||
|
|
||||||
* Said module is on ``sys.path`` (``import mysite.settings`` should work).
|
|
||||||
|
|
||||||
* The module doesn't contain syntax errors (of course).
|
|
||||||
|
|
||||||
* If you're using mod_python but *not* using Django's request handler,
|
|
||||||
you'll need to work around a mod_python bug related to the use of
|
|
||||||
``SetEnv``; before you import anything from Django you'll need to do
|
|
||||||
the following::
|
|
||||||
|
|
||||||
os.environ.update(req.subprocess_env)
|
|
||||||
|
|
||||||
(where ``req`` is the mod_python request object).
|
|
||||||
|
|
||||||
I can't stand your template language. Do I have to use it?
|
|
||||||
----------------------------------------------------------
|
|
||||||
|
|
||||||
We happen to think our template engine is the best thing since chunky bacon,
|
|
||||||
but we recognize that choosing a template language runs close to religion.
|
|
||||||
There's nothing about Django that requires using the template language, so
|
|
||||||
if you're attached to ZPT, Cheetah, or whatever, feel free to use those.
|
|
||||||
|
|
||||||
Do I have to use your model/database layer?
|
|
||||||
-------------------------------------------
|
|
||||||
|
|
||||||
Nope. Just like the template system, the model/database layer is decoupled from
|
|
||||||
the rest of the framework.
|
|
||||||
|
|
||||||
The one exception is: If you use a different database library, you won't get to
|
|
||||||
use Django's automatically-generated admin site. That app is coupled to the
|
|
||||||
Django database layer.
|
|
||||||
|
|
||||||
How do I use image and file fields?
|
|
||||||
-----------------------------------
|
|
||||||
|
|
||||||
Using a ``FileField`` or an ``ImageField`` in a model takes a few steps:
|
|
||||||
|
|
||||||
#. In your settings file, define ``MEDIA_ROOT`` as the full path to
|
|
||||||
a directory where you'd like Django to store uploaded files. (For
|
|
||||||
performance, these files are not stored in the database.) Define
|
|
||||||
``MEDIA_URL`` as the base public URL of that directory. Make sure that
|
|
||||||
this directory is writable by the Web server's user account.
|
|
||||||
|
|
||||||
#. Add the ``FileField`` or ``ImageField`` to your model, making sure
|
|
||||||
to define the ``upload_to`` option to tell Django to which subdirectory
|
|
||||||
of ``MEDIA_ROOT`` it should upload files.
|
|
||||||
|
|
||||||
#. All that will be stored in your database is a path to the file
|
|
||||||
(relative to ``MEDIA_ROOT``). You'll most likely want to use the
|
|
||||||
convenience ``get_<fieldname>_url`` function provided by Django. For
|
|
||||||
example, if your ``ImageField`` is called ``mug_shot``, you can get the
|
|
||||||
absolute URL to your image in a template with
|
|
||||||
``{{ object.get_mug_shot_url }}``.
|
|
||||||
|
|
||||||
Databases and models
|
|
||||||
====================
|
|
||||||
|
|
||||||
How can I see the raw SQL queries Django is running?
|
|
||||||
----------------------------------------------------
|
|
||||||
|
|
||||||
Make sure your Django ``DEBUG`` setting is set to ``True``. Then, just do
|
|
||||||
this::
|
|
||||||
|
|
||||||
>>> from django.db import connection
|
|
||||||
>>> connection.queries
|
|
||||||
[{'sql': 'SELECT polls_polls.id,polls_polls.question,polls_polls.pub_date FROM polls_polls',
|
|
||||||
'time': '0.002'}]
|
|
||||||
|
|
||||||
``connection.queries`` is only available if ``DEBUG`` is ``True``. It's a list
|
|
||||||
of dictionaries in order of query execution. Each dictionary has the following::
|
|
||||||
|
|
||||||
``sql`` -- The raw SQL statement
|
|
||||||
``time`` -- How long the statement took to execute, in seconds.
|
|
||||||
|
|
||||||
``connection.queries`` includes all SQL statements -- INSERTs, UPDATES,
|
|
||||||
SELECTs, etc. Each time your app hits the database, the query will be recorded.
|
|
||||||
|
|
||||||
Can I use Django with a pre-existing database?
|
|
||||||
----------------------------------------------
|
|
||||||
|
|
||||||
Yes. See `Integrating with a legacy database`_.
|
|
||||||
|
|
||||||
.. _`Integrating with a legacy database`: ../legacy_databases/
|
|
||||||
|
|
||||||
If I make changes to a model, how do I update the database?
|
|
||||||
-----------------------------------------------------------
|
|
||||||
|
|
||||||
If you don't mind clearing data, your project's ``manage.py`` utility has an
|
|
||||||
option to reset the SQL for a particular application::
|
|
||||||
|
|
||||||
manage.py reset appname
|
|
||||||
|
|
||||||
This drops any tables associated with ``appname`` and recreates them.
|
|
||||||
|
|
||||||
If you do care about deleting data, you'll have to execute the ``ALTER TABLE``
|
|
||||||
statements manually in your database. That's the way we've always done it,
|
|
||||||
because dealing with data is a very sensitive operation that we've wanted to
|
|
||||||
avoid automating. That said, there's some work being done to add partially
|
|
||||||
automated database-upgrade functionality.
|
|
||||||
|
|
||||||
Do Django models support multiple-column primary keys?
|
|
||||||
------------------------------------------------------
|
|
||||||
|
|
||||||
No. Only single-column primary keys are supported.
|
|
||||||
|
|
||||||
But this isn't an issue in practice, because there's nothing stopping you from
|
|
||||||
adding other constraints (using the ``unique_together`` model option or
|
|
||||||
creating the constraint directly in your database), and enforcing the
|
|
||||||
uniqueness at that level. Single-column primary keys are needed for things such
|
|
||||||
as the admin interface to work; e.g., you need a simple way of being able to
|
|
||||||
specify an object to edit or delete.
|
|
||||||
|
|
||||||
How do I add database-specific options to my CREATE TABLE statements, such as specifying MyISAM as the table type?
|
|
||||||
------------------------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
We try to avoid adding special cases in the Django code to accommodate all the
|
|
||||||
database-specific options such as table type, etc. If you'd like to use any of
|
|
||||||
these options, create an `SQL initial data file`_ that contains ``ALTER TABLE``
|
|
||||||
statements that do what you want to do. The initial data files are executed in
|
|
||||||
your database after the ``CREATE TABLE`` statements.
|
|
||||||
|
|
||||||
For example, if you're using MySQL and want your tables to use the MyISAM table
|
|
||||||
type, create an initial data file and put something like this in it::
|
|
||||||
|
|
||||||
ALTER TABLE myapp_mytable ENGINE=MyISAM;
|
|
||||||
|
|
||||||
As explained in the `SQL initial data file`_ documentation, this SQL file can
|
|
||||||
contain arbitrary SQL, so you can make any sorts of changes you need to make.
|
|
||||||
|
|
||||||
.. _SQL initial data file: ../model-api/#providing-initial-sql-data
|
|
||||||
|
|
||||||
Why is Django leaking memory?
|
|
||||||
-----------------------------
|
|
||||||
|
|
||||||
Django isn't known to leak memory. If you find your Django processes are
|
|
||||||
allocating more and more memory, with no sign of releasing it, check to make
|
|
||||||
sure your ``DEBUG`` setting is set to ``True``. If ``DEBUG`` is ``True``, then
|
|
||||||
Django saves a copy of every SQL statement it has executed.
|
|
||||||
|
|
||||||
(The queries are saved in ``django.db.connection.queries``. See
|
|
||||||
`How can I see the raw SQL queries Django is running?`_.)
|
|
||||||
|
|
||||||
To fix the problem, set ``DEBUG`` to ``False``.
|
|
||||||
|
|
||||||
If you need to clear the query list manually at any point in your functions,
|
|
||||||
just call ``reset_queries()``, like this::
|
|
||||||
|
|
||||||
from django import db
|
|
||||||
db.reset_queries()
|
|
||||||
|
|
||||||
The admin site
|
|
||||||
==============
|
|
||||||
|
|
||||||
I can't log in. When I enter a valid username and password, it just brings up the login page again, with no error messages.
|
|
||||||
---------------------------------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
The login cookie isn't being set correctly, because the domain of the cookie
|
|
||||||
sent out by Django doesn't match the domain in your browser. Try these two
|
|
||||||
things:
|
|
||||||
|
|
||||||
* Set the ``SESSION_COOKIE_DOMAIN`` setting in your admin config file
|
|
||||||
to match your domain. For example, if you're going to
|
|
||||||
"http://www.mysite.com/admin/" in your browser, in
|
|
||||||
"myproject.settings" you should set ``SESSION_COOKIE_DOMAIN = 'www.mysite.com'``.
|
|
||||||
|
|
||||||
* Some browsers (Firefox?) don't like to accept cookies from domains that
|
|
||||||
don't have dots in them. If you're running the admin site on "localhost"
|
|
||||||
or another domain that doesn't have a dot in it, try going to
|
|
||||||
"localhost.localdomain" or "127.0.0.1". And set
|
|
||||||
``SESSION_COOKIE_DOMAIN`` accordingly.
|
|
||||||
|
|
||||||
I can't log in. When I enter a valid username and password, it brings up the login page again, with a "Please enter a correct username and password" error.
|
|
||||||
-----------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
If you're sure your username and password are correct, make sure your user
|
|
||||||
account has ``is_active`` and ``is_staff`` set to True. The admin site only
|
|
||||||
allows access to users with those two fields both set to True.
|
|
||||||
|
|
||||||
How can I prevent the cache middleware from caching the admin site?
|
|
||||||
-------------------------------------------------------------------
|
|
||||||
|
|
||||||
Set the ``CACHE_MIDDLEWARE_ANONYMOUS_ONLY`` setting to ``True``. See the
|
|
||||||
`cache documentation`_ for more information.
|
|
||||||
|
|
||||||
.. _cache documentation: ../cache/#the-per-site-cache
|
|
||||||
|
|
||||||
How do I automatically set a field's value to the user who last edited the object in the admin?
|
|
||||||
-----------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
At this point, Django doesn't have an official way to do this. But it's an oft-requested
|
|
||||||
feature, so we're discussing how it can be implemented. The problem is we don't want to couple
|
|
||||||
the model layer with the admin layer with the request layer (to get the current user). It's a
|
|
||||||
tricky problem.
|
|
||||||
|
|
||||||
One person hacked up a `solution that doesn't require patching Django`_, but note that it's an
|
|
||||||
unofficial solution, and there's no guarantee it won't break at some point.
|
|
||||||
|
|
||||||
.. _solution that doesn't require patching Django: http://lukeplant.me.uk/blog.php?id=1107301634
|
|
||||||
|
|
||||||
How do I limit admin access so that objects can only be edited by the users who created them?
|
|
||||||
---------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
See the answer to the previous question.
|
|
||||||
|
|
||||||
My admin-site CSS and images showed up fine using the development server, but they're not displaying when using mod_python.
|
|
||||||
---------------------------------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
See `serving the admin files`_ in the "How to use Django with mod_python"
|
|
||||||
documentation.
|
|
||||||
|
|
||||||
.. _serving the admin files: ../modpython/#serving-the-admin-files
|
|
||||||
|
|
||||||
My "list_filter" contains a ManyToManyField, but the filter doesn't display.
|
|
||||||
----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
Django won't bother displaying the filter for a ``ManyToManyField`` if there
|
|
||||||
are fewer than two related objects.
|
|
||||||
|
|
||||||
For example, if your ``list_filter`` includes ``sites``, and there's only one
|
|
||||||
site in your database, it won't display a "Site" filter. In that case,
|
|
||||||
filtering by site would be meaningless.
|
|
||||||
|
|
||||||
How can I customize the functionality of the admin interface?
|
|
||||||
-------------------------------------------------------------
|
|
||||||
|
|
||||||
You've got several options. If you want to piggyback on top of an add/change
|
|
||||||
form that Django automatically generates, you can attach arbitrary JavaScript
|
|
||||||
modules to the page via the model's ``class Admin`` ``js`` parameter. That
|
|
||||||
parameter is a list of URLs, as strings, pointing to JavaScript modules that
|
|
||||||
will be included within the admin form via a ``<script>`` tag.
|
|
||||||
|
|
||||||
If you want more flexibility than simply tweaking the auto-generated forms,
|
|
||||||
feel free to write custom views for the admin. The admin is powered by Django
|
|
||||||
itself, and you can write custom views that hook into the authentication
|
|
||||||
system, check permissions and do whatever else they need to do.
|
|
||||||
|
|
||||||
If you want to customize the look-and-feel of the admin interface, read the
|
|
||||||
next question.
|
|
||||||
|
|
||||||
The dynamically-generated admin site is ugly! How can I change it?
|
|
||||||
------------------------------------------------------------------
|
|
||||||
|
|
||||||
We like it, but if you don't agree, you can modify the admin site's
|
|
||||||
presentation by editing the CSS stylesheet and/or associated image files. The
|
|
||||||
site is built using semantic HTML and plenty of CSS hooks, so any changes you'd
|
|
||||||
like to make should be possible by editing the stylesheet. We've got a
|
|
||||||
`guide to the CSS used in the admin`_ to get you started.
|
|
||||||
|
|
||||||
.. _`guide to the CSS used in the admin`: ../admin_css/
|
|
||||||
|
|
||||||
How do I create users without having to edit password hashes?
|
|
||||||
-------------------------------------------------------------
|
|
||||||
|
|
||||||
If you'd like to use the admin site to create users, upgrade to the Django
|
|
||||||
development version, where this problem was fixed on Aug. 4, 2006.
|
|
||||||
|
|
||||||
You can also use the Python API. See `creating users`_ for full info.
|
|
||||||
|
|
||||||
.. _creating users: ../authentication/#creating-users
|
|
||||||
|
|
||||||
Getting help
|
|
||||||
============
|
|
||||||
|
|
||||||
How do I do X? Why doesn't Y work? Where can I go to get help?
|
|
||||||
--------------------------------------------------------------
|
|
||||||
|
|
||||||
If this FAQ doesn't contain an answer to your question, you might want to
|
|
||||||
try the `django-users mailing list`_. Feel free to ask any question related
|
|
||||||
to installing, using, or debugging Django.
|
|
||||||
|
|
||||||
If you prefer IRC, the `#django IRC channel`_ on the Freenode IRC network is an
|
|
||||||
active community of helpful individuals who may be able to solve your problem.
|
|
||||||
|
|
||||||
.. _`django-users mailing list`: http://groups.google.com/group/django-users
|
|
||||||
.. _`#django IRC channel`: irc://irc.freenode.net/django
|
|
||||||
|
|
||||||
Why hasn't my message appeared on django-users?
|
|
||||||
-----------------------------------------------
|
|
||||||
|
|
||||||
django-users_ has a lot of subscribers. This is good for the community, as
|
|
||||||
it means many people are available to contribute answers to questions.
|
|
||||||
Unfortunately, it also means that django-users_ is an attractive target for
|
|
||||||
spammers.
|
|
||||||
|
|
||||||
In order to combat the spam problem, when you join the django-users_ mailing
|
|
||||||
list, we manually moderate the first message you send to the list. This means
|
|
||||||
that spammers get caught, but it also means that your first question to the
|
|
||||||
list might take a little longer to get answered. We apologize for any
|
|
||||||
inconvenience that this policy may cause.
|
|
||||||
|
|
||||||
.. _django-users: http://groups.google.com/group/django-users
|
|
||||||
|
|
||||||
Nobody on django-users answered my question! What should I do?
|
|
||||||
--------------------------------------------------------------
|
|
||||||
|
|
||||||
Try making your question more specific, or provide a better example of your
|
|
||||||
problem.
|
|
||||||
|
|
||||||
As with most open-source mailing lists, the folks on django-users_ are
|
|
||||||
volunteers. If nobody has answered your question, it may be because nobody
|
|
||||||
knows the answer, it may be because nobody can understand the question, or it
|
|
||||||
may be that everybody that can help is busy. One thing you might try is to ask
|
|
||||||
the question on IRC -- visit the `#django IRC channel`_ on the Freenode IRC
|
|
||||||
network.
|
|
||||||
|
|
||||||
You might notice we have a second mailing list, called django-developers_ --
|
|
||||||
but please don't e-mail support questions to this mailing list. This list is
|
|
||||||
for discussion of the development of Django itself. Asking a tech support
|
|
||||||
question there is considered quite impolite.
|
|
||||||
|
|
||||||
.. _django-developers: http://groups.google.com/group/django-developers
|
|
||||||
|
|
||||||
I think I've found a bug! What should I do?
|
|
||||||
-------------------------------------------
|
|
||||||
|
|
||||||
Detailed instructions on how to handle a potential bug can be found in our
|
|
||||||
`Guide to contributing to Django`_.
|
|
||||||
|
|
||||||
.. _`Guide to contributing to Django`: ../contributing/#reporting-bugs
|
|
||||||
|
|
||||||
I think I've found a security problem! What should I do?
|
|
||||||
--------------------------------------------------------
|
|
||||||
|
|
||||||
If you think you've found a security problem with Django, please send a message
|
|
||||||
to security@djangoproject.com. This is a private list only open to long-time,
|
|
||||||
highly trusted Django developers, and its archives are not publicly readable.
|
|
||||||
|
|
||||||
Due to the sensitive nature of security issues, we ask that if you think you
|
|
||||||
have found a security problem, *please* don't send a message to one of the
|
|
||||||
public mailing lists. Django has a `policy for handling security issues`_;
|
|
||||||
while a defect is outstanding, we would like to minimize any damage that
|
|
||||||
could be inflicted through public knowledge of that defect.
|
|
||||||
|
|
||||||
.. _`policy for handling security issues`: ../contributing/#reporting-security-issues
|
|
||||||
|
|
||||||
Contributing code
|
|
||||||
=================
|
|
||||||
|
|
||||||
How can I get started contributing code to Django?
|
|
||||||
--------------------------------------------------
|
|
||||||
|
|
||||||
Thanks for asking! We've written an entire document devoted to this question.
|
|
||||||
It's titled `Contributing to Django`_.
|
|
||||||
|
|
||||||
.. _`Contributing to Django`: ../contributing/
|
|
||||||
|
|
||||||
I submitted a bug fix in the ticket system several weeks ago. Why are you ignoring my patch?
|
|
||||||
--------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
Don't worry: We're not ignoring you!
|
|
||||||
|
|
||||||
It's important to understand there is a difference between "a ticket is being
|
|
||||||
ignored" and "a ticket has not been attended to yet." Django's ticket system
|
|
||||||
contains hundreds of open tickets, of various degrees of impact on end-user
|
|
||||||
functionality, and Django's developers have to review and prioritize.
|
|
||||||
|
|
||||||
On top of that: the people who work on Django are all volunteers. As a result,
|
|
||||||
the amount of time that we have to work on the framework is limited and will
|
|
||||||
vary from week to week depending on our spare time. If we're busy, we may not
|
|
||||||
be able to spend as much time on Django as we might want.
|
|
||||||
|
|
||||||
Besides, if your feature request stands no chance of inclusion in Django, we
|
|
||||||
won't ignore it -- we'll just close the ticket. So if your ticket is still
|
|
||||||
open, it doesn't mean we're ignoring you; it just means we haven't had time to
|
|
||||||
look at it yet.
|
|
|
@ -0,0 +1,103 @@
|
||||||
|
.. _faq-admin:
|
||||||
|
|
||||||
|
FAQ: The admin
|
||||||
|
==============
|
||||||
|
|
||||||
|
I can't log in. When I enter a valid username and password, it just brings up the login page again, with no error messages.
|
||||||
|
---------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
The login cookie isn't being set correctly, because the domain of the cookie
|
||||||
|
sent out by Django doesn't match the domain in your browser. Try these two
|
||||||
|
things:
|
||||||
|
|
||||||
|
* Set the ``SESSION_COOKIE_DOMAIN`` setting in your admin config file
|
||||||
|
to match your domain. For example, if you're going to
|
||||||
|
"http://www.example.com/admin/" in your browser, in
|
||||||
|
"myproject.settings" you should set ``SESSION_COOKIE_DOMAIN = 'www.example.com'``.
|
||||||
|
|
||||||
|
* Some browsers (Firefox?) don't like to accept cookies from domains that
|
||||||
|
don't have dots in them. If you're running the admin site on "localhost"
|
||||||
|
or another domain that doesn't have a dot in it, try going to
|
||||||
|
"localhost.localdomain" or "127.0.0.1". And set
|
||||||
|
``SESSION_COOKIE_DOMAIN`` accordingly.
|
||||||
|
|
||||||
|
I can't log in. When I enter a valid username and password, it brings up the login page again, with a "Please enter a correct username and password" error.
|
||||||
|
-----------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
If you're sure your username and password are correct, make sure your user
|
||||||
|
account has ``is_active`` and ``is_staff`` set to True. The admin site only
|
||||||
|
allows access to users with those two fields both set to True.
|
||||||
|
|
||||||
|
How can I prevent the cache middleware from caching the admin site?
|
||||||
|
-------------------------------------------------------------------
|
||||||
|
|
||||||
|
Set the :setting:``CACHE_MIDDLEWARE_ANONYMOUS_ONLY`` setting to ``True``. See the
|
||||||
|
:ref:`cache documentation <topics-cache>` for more information.
|
||||||
|
|
||||||
|
How do I automatically set a field's value to the user who last edited the object in the admin?
|
||||||
|
-----------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
At this point, Django doesn't have an official way to do this. But it's an oft-requested
|
||||||
|
feature, so we're discussing how it can be implemented. The problem is we don't want to couple
|
||||||
|
the model layer with the admin layer with the request layer (to get the current user). It's a
|
||||||
|
tricky problem.
|
||||||
|
|
||||||
|
One person hacked up a `solution that doesn't require patching Django`_, but note that it's an
|
||||||
|
unofficial solution, and there's no guarantee it won't break at some point.
|
||||||
|
|
||||||
|
.. _solution that doesn't require patching Django: http://lukeplant.me.uk/blog.php?id=1107301634
|
||||||
|
|
||||||
|
How do I limit admin access so that objects can only be edited by the users who created them?
|
||||||
|
---------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
See the answer to the previous question.
|
||||||
|
|
||||||
|
My admin-site CSS and images showed up fine using the development server, but they're not displaying when using mod_python.
|
||||||
|
---------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
See :ref:`serving the admin files <howto-deployment-modpython-serving-the-admin-files`
|
||||||
|
in the "How to use Django with mod_python" documentation.
|
||||||
|
|
||||||
|
My "list_filter" contains a ManyToManyField, but the filter doesn't display.
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Django won't bother displaying the filter for a ``ManyToManyField`` if there
|
||||||
|
are fewer than two related objects.
|
||||||
|
|
||||||
|
For example, if your ``list_filter`` includes ``sites``, and there's only one
|
||||||
|
site in your database, it won't display a "Site" filter. In that case,
|
||||||
|
filtering by site would be meaningless.
|
||||||
|
|
||||||
|
How can I customize the functionality of the admin interface?
|
||||||
|
-------------------------------------------------------------
|
||||||
|
|
||||||
|
You've got several options. If you want to piggyback on top of an add/change
|
||||||
|
form that Django automatically generates, you can attach arbitrary JavaScript
|
||||||
|
modules to the page via the model's ``class Admin`` ``js`` parameter. That
|
||||||
|
parameter is a list of URLs, as strings, pointing to JavaScript modules that
|
||||||
|
will be included within the admin form via a ``<script>`` tag.
|
||||||
|
|
||||||
|
If you want more flexibility than simply tweaking the auto-generated forms,
|
||||||
|
feel free to write custom views for the admin. The admin is powered by Django
|
||||||
|
itself, and you can write custom views that hook into the authentication
|
||||||
|
system, check permissions and do whatever else they need to do.
|
||||||
|
|
||||||
|
If you want to customize the look-and-feel of the admin interface, read the
|
||||||
|
next question.
|
||||||
|
|
||||||
|
The dynamically-generated admin site is ugly! How can I change it?
|
||||||
|
------------------------------------------------------------------
|
||||||
|
|
||||||
|
We like it, but if you don't agree, you can modify the admin site's
|
||||||
|
presentation by editing the CSS stylesheet and/or associated image files. The
|
||||||
|
site is built using semantic HTML and plenty of CSS hooks, so any changes you'd
|
||||||
|
like to make should be possible by editing the stylesheet. We've got a
|
||||||
|
:ref:`guide to the CSS used in the admin <obsolete-admin-css>` to get you started.
|
||||||
|
|
||||||
|
How do I create users without having to edit password hashes?
|
||||||
|
-------------------------------------------------------------
|
||||||
|
|
||||||
|
If you'd like to use the admin site to create users, upgrade to the Django
|
||||||
|
development version, where this problem was fixed on Aug. 4, 2006.
|
||||||
|
|
||||||
|
You can also use the Python API. See :ref:`creating users <topics-auth-creating-users>` for full info.
|
|
@ -0,0 +1,30 @@
|
||||||
|
.. _faq-contributing:
|
||||||
|
|
||||||
|
FAQ: Contributing code
|
||||||
|
======================
|
||||||
|
|
||||||
|
How can I get started contributing code to Django?
|
||||||
|
--------------------------------------------------
|
||||||
|
|
||||||
|
Thanks for asking! We've written an entire document devoted to this question.
|
||||||
|
It's titled :ref:`Contributing to Django <internals-contributing>`.
|
||||||
|
|
||||||
|
I submitted a bug fix in the ticket system several weeks ago. Why are you ignoring my patch?
|
||||||
|
--------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Don't worry: We're not ignoring you!
|
||||||
|
|
||||||
|
It's important to understand there is a difference between "a ticket is being
|
||||||
|
ignored" and "a ticket has not been attended to yet." Django's ticket system
|
||||||
|
contains hundreds of open tickets, of various degrees of impact on end-user
|
||||||
|
functionality, and Django's developers have to review and prioritize.
|
||||||
|
|
||||||
|
On top of that: the people who work on Django are all volunteers. As a result,
|
||||||
|
the amount of time that we have to work on the framework is limited and will
|
||||||
|
vary from week to week depending on our spare time. If we're busy, we may not
|
||||||
|
be able to spend as much time on Django as we might want.
|
||||||
|
|
||||||
|
Besides, if your feature request stands no chance of inclusion in Django, we
|
||||||
|
won't ignore it -- we'll just close the ticket. So if your ticket is still
|
||||||
|
open, it doesn't mean we're ignoring you; it just means we haven't had time to
|
||||||
|
look at it yet.
|
|
@ -0,0 +1,256 @@
|
||||||
|
.. _faq-general:
|
||||||
|
|
||||||
|
FAQ: General
|
||||||
|
============
|
||||||
|
|
||||||
|
Why does this project exist?
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
Django grew from a very practical need: World Online, a newspaper Web
|
||||||
|
operation, is responsible for building intensive Web applications on journalism
|
||||||
|
deadlines. In the fast-paced newsroom, World Online often has only a matter of
|
||||||
|
hours to take a complicated Web application from concept to public launch.
|
||||||
|
|
||||||
|
At the same time, the World Online Web developers have consistently been
|
||||||
|
perfectionists when it comes to following best practices of Web development.
|
||||||
|
|
||||||
|
In fall 2003, the World Online developers (Adrian Holovaty and Simon Willison)
|
||||||
|
ditched PHP and began using Python to develop its Web sites. As they built
|
||||||
|
intensive, richly interactive sites such as Lawrence.com, they began to extract
|
||||||
|
a generic Web development framework that let them build Web applications more
|
||||||
|
and more quickly. They tweaked this framework constantly, adding improvements
|
||||||
|
over two years.
|
||||||
|
|
||||||
|
In summer 2005, World Online decided to open-source the resulting software,
|
||||||
|
Django. Django would not be possible without a whole host of open-source
|
||||||
|
projects -- `Apache`_, `Python`_, and `PostgreSQL`_ to name a few -- and we're
|
||||||
|
thrilled to be able to give something back to the open-source community.
|
||||||
|
|
||||||
|
.. _Apache: http://httpd.apache.org/
|
||||||
|
.. _Python: http://www.python.org/
|
||||||
|
.. _PostgreSQL: http://www.postgresql.org/
|
||||||
|
|
||||||
|
What does "Django" mean, and how do you pronounce it?
|
||||||
|
-----------------------------------------------------
|
||||||
|
|
||||||
|
Django is named after `Django Reinhardt`_, a gypsy jazz guitarist from the 1930s
|
||||||
|
to early 1950s. To this day, he's considered one of the best guitarists of all time.
|
||||||
|
|
||||||
|
Listen to his music. You'll like it.
|
||||||
|
|
||||||
|
Django is pronounced **JANG**-oh. Rhymes with FANG-oh. The "D" is silent.
|
||||||
|
|
||||||
|
We've also recorded an `audio clip of the pronunciation`_.
|
||||||
|
|
||||||
|
.. _Django Reinhardt: http://en.wikipedia.org/wiki/Django_Reinhardt
|
||||||
|
.. _audio clip of the pronunciation: http://red-bean.com/~adrian/django_pronunciation.mp3
|
||||||
|
|
||||||
|
Is Django stable?
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
Yes. World Online has been using Django for more than three years. Sites built
|
||||||
|
on Django have weathered traffic spikes of over one million hits an hour and a
|
||||||
|
number of Slashdottings. Yes, it's quite stable.
|
||||||
|
|
||||||
|
Does Django scale?
|
||||||
|
------------------
|
||||||
|
|
||||||
|
Yes. Compared to development time, hardware is cheap, and so Django is
|
||||||
|
designed to take advantage of as much hardware as you can throw at it.
|
||||||
|
|
||||||
|
Django uses a "shared-nothing" architecture, which means you can add hardware
|
||||||
|
at any level -- database servers, caching servers or Web/application servers.
|
||||||
|
|
||||||
|
The framework cleanly separates components such as its database layer and
|
||||||
|
application layer. And it ships with a simple-yet-powerful
|
||||||
|
:ref:`cache framework <topics-cache>`.
|
||||||
|
|
||||||
|
Who's behind this?
|
||||||
|
------------------
|
||||||
|
|
||||||
|
Django was developed at `World Online`_, the Web department of a newspaper in
|
||||||
|
Lawrence, Kansas, USA.
|
||||||
|
|
||||||
|
`Adrian Holovaty`_
|
||||||
|
Adrian is a Web developer with a background in journalism. He was lead
|
||||||
|
developer at World Online for 2.5 years, during which time Django was
|
||||||
|
developed and implemented on World Online's sites. Now he works for
|
||||||
|
washingtonpost.com building rich, database-backed information sites, and
|
||||||
|
continues to oversee Django development. He likes playing guitar (Django
|
||||||
|
Reinhardt style) and hacking on side projects such as `chicagocrime.org`_.
|
||||||
|
He lives in Chicago.
|
||||||
|
|
||||||
|
On IRC, Adrian goes by ``adrian_h``.
|
||||||
|
|
||||||
|
`Jacob Kaplan-Moss`_
|
||||||
|
Jacob is a whipper-snapper from California who spends equal time coding and
|
||||||
|
cooking. He's lead developer at World Online and actively hacks on various
|
||||||
|
cool side projects. He's contributed to the Python-ObjC bindings and was
|
||||||
|
the first guy to figure out how to write Tivo apps in Python. Lately he's
|
||||||
|
been messing with Python on the PSP. He lives in Lawrence, Kansas.
|
||||||
|
|
||||||
|
On IRC, Jacob goes by ``jacobkm``.
|
||||||
|
|
||||||
|
`Simon Willison`_
|
||||||
|
Simon is a well-respected Web developer from England. He had a one-year
|
||||||
|
internship at World Online, during which time he and Adrian developed
|
||||||
|
Django from scratch. The most enthusiastic Brit you'll ever meet, he's
|
||||||
|
passionate about best practices in Web development and has maintained a
|
||||||
|
well-read Web-development blog for years at http://simon.incutio.com.
|
||||||
|
He works for Yahoo UK, where he managed to score the title "Hacker Liason."
|
||||||
|
He lives in London.
|
||||||
|
|
||||||
|
On IRC, Simon goes by ``SimonW``.
|
||||||
|
|
||||||
|
`Wilson Miner`_
|
||||||
|
Wilson's design-fu makes us all look like rock stars. By day, he's an
|
||||||
|
interactive designer for `Apple`_. Don't ask him what he's working on, or
|
||||||
|
he'll have to kill you. He lives in San Francisco.
|
||||||
|
|
||||||
|
On IRC, Wilson goes by ``wilsonian``.
|
||||||
|
|
||||||
|
.. _`World Online`: http://code.djangoproject.com/wiki/WorldOnline
|
||||||
|
.. _`Adrian Holovaty`: http://www.holovaty.com/
|
||||||
|
.. _`washingtonpost.com`: http://www.washingtonpost.com/
|
||||||
|
.. _`chicagocrime.org`: http://www.chicagocrime.org/
|
||||||
|
.. _`Simon Willison`: http://simon.incutio.com/
|
||||||
|
.. _`simon.incutio.com`: http://simon.incutio.com/
|
||||||
|
.. _`Jacob Kaplan-Moss`: http://www.jacobian.org/
|
||||||
|
.. _`Wilson Miner`: http://www.wilsonminer.com/
|
||||||
|
.. _`Apple`: http://www.apple.com/
|
||||||
|
|
||||||
|
Which sites use Django?
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
The Django wiki features a consistently growing `list of Django-powered sites`_.
|
||||||
|
Feel free to add your Django-powered site to the list.
|
||||||
|
|
||||||
|
.. _list of Django-powered sites: http://code.djangoproject.com/wiki/DjangoPoweredSites
|
||||||
|
|
||||||
|
.. _mtv:
|
||||||
|
|
||||||
|
Django appears to be a MVC framework, but you call the Controller the "view", and the View the "template". How come you don't use the standard names?
|
||||||
|
-----------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Well, the standard names are debatable.
|
||||||
|
|
||||||
|
In our interpretation of MVC, the "view" describes the data that gets presented
|
||||||
|
to the user. It's not necessarily *how* the data *looks*, but *which* data is
|
||||||
|
presented. The view describes *which data you see*, not *how you see it.* It's
|
||||||
|
a subtle distinction.
|
||||||
|
|
||||||
|
So, in our case, a "view" is the Python callback function for a particular URL,
|
||||||
|
because that callback function describes which data is presented.
|
||||||
|
|
||||||
|
Furthermore, it's sensible to separate content from presentation -- which is
|
||||||
|
where templates come in. In Django, a "view" describes which data is presented,
|
||||||
|
but a view normally delegates to a template, which describes *how* the data is
|
||||||
|
presented.
|
||||||
|
|
||||||
|
Where does the "controller" fit in, then? In Django's case, it's probably the
|
||||||
|
framework itself: the machinery that sends a request to the appropriate view,
|
||||||
|
according to the Django URL configuration.
|
||||||
|
|
||||||
|
If you're hungry for acronyms, you might say that Django is a "MTV" framework
|
||||||
|
-- that is, "model", "template", and "view." That breakdown makes much more
|
||||||
|
sense.
|
||||||
|
|
||||||
|
At the end of the day, of course, it comes down to getting stuff done. And,
|
||||||
|
regardless of how things are named, Django gets stuff done in a way that's most
|
||||||
|
logical to us.
|
||||||
|
|
||||||
|
<Framework X> does <feature Y> -- why doesn't Django?
|
||||||
|
-----------------------------------------------------
|
||||||
|
|
||||||
|
We're well aware that there are other awesome Web frameworks out there, and
|
||||||
|
we're not averse to borrowing ideas where appropriate. However, Django was
|
||||||
|
developed precisely because we were unhappy with the status quo, so please be
|
||||||
|
aware that "because <Framework X> does it" is not going to be sufficient reason
|
||||||
|
to add a given feature to Django.
|
||||||
|
|
||||||
|
Why did you write all of Django from scratch, instead of using other Python libraries?
|
||||||
|
--------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
When Django was originally written a couple of years ago, Adrian and Simon
|
||||||
|
spent quite a bit of time exploring the various Python Web frameworks
|
||||||
|
available.
|
||||||
|
|
||||||
|
In our opinion, none of them were completely up to snuff.
|
||||||
|
|
||||||
|
We're picky. You might even call us perfectionists. (With deadlines.)
|
||||||
|
|
||||||
|
Over time, we stumbled across open-source libraries that did things we'd
|
||||||
|
already implemented. It was reassuring to see other people solving similar
|
||||||
|
problems in similar ways, but it was too late to integrate outside code: We'd
|
||||||
|
already written, tested and implemented our own framework bits in several
|
||||||
|
production settings -- and our own code met our needs delightfully.
|
||||||
|
|
||||||
|
In most cases, however, we found that existing frameworks/tools inevitably had
|
||||||
|
some sort of fundamental, fatal flaw that made us squeamish. No tool fit our
|
||||||
|
philosophies 100%.
|
||||||
|
|
||||||
|
Like we said: We're picky.
|
||||||
|
|
||||||
|
We've documented our philosophies on the
|
||||||
|
:ref:`design philosophies page <misc-design-philosophies>`.
|
||||||
|
|
||||||
|
Do you have any of those nifty "screencast" things?
|
||||||
|
---------------------------------------------------
|
||||||
|
|
||||||
|
You can bet your bottom they're on the way. But, since we're still hammering
|
||||||
|
out a few points, we want to make sure they reflect the final state of things
|
||||||
|
at Django 1.0, not some intermediary step. In other words, we don't want to
|
||||||
|
spend a lot of energy creating screencasts yet, because Django APIs will shift.
|
||||||
|
|
||||||
|
Is Django a content-management-system (CMS)?
|
||||||
|
--------------------------------------------
|
||||||
|
|
||||||
|
No, Django is not a CMS, or any sort of "turnkey product" in and of itself.
|
||||||
|
It's a Web framework; it's a programming tool that lets you build Web sites.
|
||||||
|
|
||||||
|
For example, it doesn't make much sense to compare Django to something like
|
||||||
|
Drupal_, because Django is something you use to *create* things like Drupal.
|
||||||
|
|
||||||
|
Of course, Django's automatic admin site is fantastic and timesaving -- but
|
||||||
|
the admin site is one module of Django the framework. Furthermore, although
|
||||||
|
Django has special conveniences for building "CMS-y" apps, that doesn't mean
|
||||||
|
it's not just as appropriate for building "non-CMS-y" apps (whatever that
|
||||||
|
means!).
|
||||||
|
|
||||||
|
.. _Drupal: http://drupal.org/
|
||||||
|
|
||||||
|
When will you release Django 1.0?
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
See our `version one roadmap`_ for the detailed timeline. We're aiming for
|
||||||
|
September 2, 2008.
|
||||||
|
|
||||||
|
.. _version one roadmap: http://code.djangoproject.com/wiki/VersionOneRoadmap
|
||||||
|
|
||||||
|
How can I download the Django documentation to read it offline?
|
||||||
|
---------------------------------------------------------------
|
||||||
|
|
||||||
|
The Django docs are available in the ``docs`` directory of each Django tarball
|
||||||
|
release. These docs are in ReST (ReStructured Text) format, and each text file
|
||||||
|
corresponds to a Web page on the official Django site.
|
||||||
|
|
||||||
|
Because the documentation is `stored in revision control`_, you can browse
|
||||||
|
documentation changes just like you can browse code changes.
|
||||||
|
|
||||||
|
Technically, the docs on Django's site are generated from the latest development
|
||||||
|
versions of those ReST documents, so the docs on the Django site may offer more
|
||||||
|
information than the docs that come with the latest Django release.
|
||||||
|
|
||||||
|
.. _stored in revision control: http://code.djangoproject.com/browser/django/trunk/docs
|
||||||
|
|
||||||
|
Where can I find Django developers for hire?
|
||||||
|
--------------------------------------------
|
||||||
|
|
||||||
|
Consult our `developers for hire page`_ for a list of Django developers who
|
||||||
|
would be happy to help you.
|
||||||
|
|
||||||
|
You might also be interested in posting a job to http://djangogigs.com/ .
|
||||||
|
If you want to find Django-capable people in your local area, try
|
||||||
|
http://djangopeople.net/ .
|
||||||
|
|
||||||
|
.. _developers for hire page: http://code.djangoproject.com/wiki/DevelopersForHire
|
|
@ -0,0 +1,75 @@
|
||||||
|
.. _faq-help:
|
||||||
|
|
||||||
|
FAQ: Getting Help
|
||||||
|
=================
|
||||||
|
|
||||||
|
How do I do X? Why doesn't Y work? Where can I go to get help?
|
||||||
|
--------------------------------------------------------------
|
||||||
|
|
||||||
|
If this FAQ doesn't contain an answer to your question, you might want to
|
||||||
|
try the `django-users mailing list`_. Feel free to ask any question related
|
||||||
|
to installing, using, or debugging Django.
|
||||||
|
|
||||||
|
If you prefer IRC, the `#django IRC channel`_ on the Freenode IRC network is an
|
||||||
|
active community of helpful individuals who may be able to solve your problem.
|
||||||
|
|
||||||
|
.. _`django-users mailing list`: http://groups.google.com/group/django-users
|
||||||
|
.. _`#django IRC channel`: irc://irc.freenode.net/django
|
||||||
|
|
||||||
|
Why hasn't my message appeared on django-users?
|
||||||
|
-----------------------------------------------
|
||||||
|
|
||||||
|
django-users_ has a lot of subscribers. This is good for the community, as
|
||||||
|
it means many people are available to contribute answers to questions.
|
||||||
|
Unfortunately, it also means that django-users_ is an attractive target for
|
||||||
|
spammers.
|
||||||
|
|
||||||
|
In order to combat the spam problem, when you join the django-users_ mailing
|
||||||
|
list, we manually moderate the first message you send to the list. This means
|
||||||
|
that spammers get caught, but it also means that your first question to the
|
||||||
|
list might take a little longer to get answered. We apologize for any
|
||||||
|
inconvenience that this policy may cause.
|
||||||
|
|
||||||
|
.. _django-users: http://groups.google.com/group/django-users
|
||||||
|
|
||||||
|
Nobody on django-users answered my question! What should I do?
|
||||||
|
--------------------------------------------------------------
|
||||||
|
|
||||||
|
Try making your question more specific, or provide a better example of your
|
||||||
|
problem.
|
||||||
|
|
||||||
|
As with most open-source mailing lists, the folks on django-users_ are
|
||||||
|
volunteers. If nobody has answered your question, it may be because nobody
|
||||||
|
knows the answer, it may be because nobody can understand the question, or it
|
||||||
|
may be that everybody that can help is busy. One thing you might try is to ask
|
||||||
|
the question on IRC -- visit the `#django IRC channel`_ on the Freenode IRC
|
||||||
|
network.
|
||||||
|
|
||||||
|
You might notice we have a second mailing list, called django-developers_ --
|
||||||
|
but please don't e-mail support questions to this mailing list. This list is
|
||||||
|
for discussion of the development of Django itself. Asking a tech support
|
||||||
|
question there is considered quite impolite.
|
||||||
|
|
||||||
|
.. _django-developers: http://groups.google.com/group/django-developers
|
||||||
|
|
||||||
|
I think I've found a bug! What should I do?
|
||||||
|
-------------------------------------------
|
||||||
|
|
||||||
|
Detailed instructions on how to handle a potential bug can be found in our
|
||||||
|
:ref:`Guide to contributing to Django <reporting-bugs>`.
|
||||||
|
|
||||||
|
I think I've found a security problem! What should I do?
|
||||||
|
--------------------------------------------------------
|
||||||
|
|
||||||
|
If you think you've found a security problem with Django, please send a message
|
||||||
|
to security@djangoproject.com. This is a private list only open to long-time,
|
||||||
|
highly trusted Django developers, and its archives are not publicly readable.
|
||||||
|
|
||||||
|
Due to the sensitive nature of security issues, we ask that if you think you
|
||||||
|
have found a security problem, *please* don't send a message to one of the
|
||||||
|
public mailing lists. Django has a
|
||||||
|
:ref:`policy for handling security issues <reporting-security-issues>`;
|
||||||
|
while a defect is outstanding, we would like to minimize any damage that
|
||||||
|
could be inflicted through public knowledge of that defect.
|
||||||
|
|
||||||
|
.. _`policy for handling security issues`: ../contributing/#reporting-security-issues
|
|
@ -0,0 +1,16 @@
|
||||||
|
.. _faq-index:
|
||||||
|
|
||||||
|
==========
|
||||||
|
Django FAQ
|
||||||
|
==========
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
general
|
||||||
|
install
|
||||||
|
usage
|
||||||
|
help
|
||||||
|
models
|
||||||
|
admin
|
||||||
|
contributing
|
|
@ -0,0 +1,108 @@
|
||||||
|
.. _faq-install:
|
||||||
|
|
||||||
|
FAQ: Installation
|
||||||
|
=================
|
||||||
|
|
||||||
|
How do I get started?
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
#. `Download the code`_.
|
||||||
|
#. Install Django (read the :ref:`installation guide <intro-install>`).
|
||||||
|
#. Walk through the :ref:`tutorial <intro-tutorial01>`.
|
||||||
|
#. Check out the rest of the :ref:`documentation <index>`, and `ask questions`_ if you
|
||||||
|
run into trouble.
|
||||||
|
|
||||||
|
.. _`Download the code`: http://www.djangoproject.com/download/
|
||||||
|
.. _ask questions: http://www.djangoproject.com/community/
|
||||||
|
|
||||||
|
How do I fix the "install a later version of setuptools" error?
|
||||||
|
---------------------------------------------------------------
|
||||||
|
|
||||||
|
Just run the ``ez_setup.py`` script in the Django distribution.
|
||||||
|
|
||||||
|
What are Django's prerequisites?
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
Django requires Python_ 2.3 or later. No other Python libraries are required
|
||||||
|
for basic Django usage.
|
||||||
|
|
||||||
|
For a development environment -- if you just want to experiment with Django --
|
||||||
|
you don't need to have a separate Web server installed; Django comes with its
|
||||||
|
own lightweight development server. For a production environment, we recommend
|
||||||
|
`Apache 2`_ and mod_python_, although Django follows the WSGI_ spec, which
|
||||||
|
means it can run on a variety of server platforms.
|
||||||
|
|
||||||
|
If you want to use Django with a database, which is probably the case, you'll
|
||||||
|
also need a database engine. PostgreSQL_ is recommended, because we're
|
||||||
|
PostgreSQL fans, and MySQL_, `SQLite 3`_, and Oracle_ are also supported.
|
||||||
|
|
||||||
|
.. _Python: http://www.python.org/
|
||||||
|
.. _Apache 2: http://httpd.apache.org/
|
||||||
|
.. _mod_python: http://www.modpython.org/
|
||||||
|
.. _WSGI: http://www.python.org/peps/pep-0333.html
|
||||||
|
.. _PostgreSQL: http://www.postgresql.org/
|
||||||
|
.. _MySQL: http://www.mysql.com/
|
||||||
|
.. _`SQLite 3`: http://www.sqlite.org/
|
||||||
|
.. _Oracle: http://www.oracle.com/
|
||||||
|
|
||||||
|
Do I lose anything by using Python 2.3 versus newer Python versions, such as Python 2.5?
|
||||||
|
----------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
No. Django itself is guaranteed to work with any version of Python from 2.3
|
||||||
|
and higher.
|
||||||
|
|
||||||
|
If you use a Python version newer than 2.3, you will, of course, be able to
|
||||||
|
take advantage of newer Python features in your own code, along with the speed
|
||||||
|
improvements and other optimizations that have been made to the Python language
|
||||||
|
itself. But the Django framework itself should work equally well on 2.3 as it
|
||||||
|
does on 2.4 or 2.5.
|
||||||
|
|
||||||
|
Do I have to use mod_python?
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
Although we recommend mod_python for production use, you don't have to use it,
|
||||||
|
thanks to the fact that Django uses an arrangement called WSGI_. Django can
|
||||||
|
talk to any WSGI-enabled server. Other non-mod_python deployment setups are
|
||||||
|
FastCGI, SCGI or AJP. See
|
||||||
|
:ref:`How to use Django with FastCGI, SCGI or AJP <howto-deployment-fastcgi>`
|
||||||
|
for full information.
|
||||||
|
|
||||||
|
Also, see the `server arrangements wiki page`_ for other deployment strategies.
|
||||||
|
|
||||||
|
If you just want to play around and develop things on your local computer, use
|
||||||
|
the development Web server that comes with Django. Things should Just Work.
|
||||||
|
|
||||||
|
.. _WSGI: http://www.python.org/peps/pep-0333.html
|
||||||
|
.. _server arrangements wiki page: http://code.djangoproject.com/wiki/ServerArrangements
|
||||||
|
|
||||||
|
How do I install mod_python on Windows?
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
* For Python 2.4, grab mod_python from `win32 build of mod_python for
|
||||||
|
Python 2.4`_.
|
||||||
|
* For Python 2.4, check out this `Django on Windows howto`_.
|
||||||
|
* For Python 2.3, grab mod_python from http://www.modpython.org/ and read
|
||||||
|
`Running mod_python on Apache on Windows2000`_.
|
||||||
|
* Also, try this (not Windows-specific) `guide to getting mod_python
|
||||||
|
working`_.
|
||||||
|
|
||||||
|
.. _`win32 build of mod_python for Python 2.4`: http://www.lehuen.com/nicolas/index.php/2005/02/21/39-win32-build-of-mod_python-314-for-python-24
|
||||||
|
.. _`Django on Windows howto`: http://thinkhole.org/wp/django-on-windows/
|
||||||
|
.. _`Running mod_python on Apache on Windows2000`: http://groups-beta.google.com/group/comp.lang.python/msg/139af8c83a5a9d4f
|
||||||
|
.. _`guide to getting mod_python working`: http://www.dscpl.com.au/articles/modpython-001.html
|
||||||
|
|
||||||
|
Will Django run under shared hosting (like TextDrive or Dreamhost)?
|
||||||
|
-------------------------------------------------------------------
|
||||||
|
|
||||||
|
See our `Django-friendly Web hosts`_ page.
|
||||||
|
|
||||||
|
.. _`Django-friendly Web hosts`: http://code.djangoproject.com/wiki/DjangoFriendlyWebHosts
|
||||||
|
|
||||||
|
Should I use the official version or development version?
|
||||||
|
---------------------------------------------------------
|
||||||
|
|
||||||
|
The Django developers improve Django every day and are pretty good about not
|
||||||
|
checking in broken code. We use the development code (from the Subversion
|
||||||
|
repository) directly on our servers, so we consider it stable. With that in
|
||||||
|
mind, we recommend that you use the latest development code, because it
|
||||||
|
generally contains more features and fewer bugs than the "official" releases.
|
|
@ -0,0 +1,94 @@
|
||||||
|
.. _faq-models:
|
||||||
|
|
||||||
|
FAQ: Databases and models
|
||||||
|
=========================
|
||||||
|
|
||||||
|
How can I see the raw SQL queries Django is running?
|
||||||
|
----------------------------------------------------
|
||||||
|
|
||||||
|
Make sure your Django ``DEBUG`` setting is set to ``True``. Then, just do
|
||||||
|
this::
|
||||||
|
|
||||||
|
>>> from django.db import connection
|
||||||
|
>>> connection.queries
|
||||||
|
[{'sql': 'SELECT polls_polls.id,polls_polls.question,polls_polls.pub_date FROM polls_polls',
|
||||||
|
'time': '0.002'}]
|
||||||
|
|
||||||
|
``connection.queries`` is only available if ``DEBUG`` is ``True``. It's a list
|
||||||
|
of dictionaries in order of query execution. Each dictionary has the following::
|
||||||
|
|
||||||
|
``sql`` -- The raw SQL statement
|
||||||
|
``time`` -- How long the statement took to execute, in seconds.
|
||||||
|
|
||||||
|
``connection.queries`` includes all SQL statements -- INSERTs, UPDATES,
|
||||||
|
SELECTs, etc. Each time your app hits the database, the query will be recorded.
|
||||||
|
|
||||||
|
Can I use Django with a pre-existing database?
|
||||||
|
----------------------------------------------
|
||||||
|
|
||||||
|
Yes. See :ref:`Integrating with a legacy database <howto-legacy-databases>`.
|
||||||
|
|
||||||
|
If I make changes to a model, how do I update the database?
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
If you don't mind clearing data, your project's ``manage.py`` utility has an
|
||||||
|
option to reset the SQL for a particular application::
|
||||||
|
|
||||||
|
manage.py reset appname
|
||||||
|
|
||||||
|
This drops any tables associated with ``appname`` and recreates them.
|
||||||
|
|
||||||
|
If you do care about deleting data, you'll have to execute the ``ALTER TABLE``
|
||||||
|
statements manually in your database. That's the way we've always done it,
|
||||||
|
because dealing with data is a very sensitive operation that we've wanted to
|
||||||
|
avoid automating. That said, there's some work being done to add partially
|
||||||
|
automated database-upgrade functionality.
|
||||||
|
|
||||||
|
Do Django models support multiple-column primary keys?
|
||||||
|
------------------------------------------------------
|
||||||
|
|
||||||
|
No. Only single-column primary keys are supported.
|
||||||
|
|
||||||
|
But this isn't an issue in practice, because there's nothing stopping you from
|
||||||
|
adding other constraints (using the ``unique_together`` model option or
|
||||||
|
creating the constraint directly in your database), and enforcing the
|
||||||
|
uniqueness at that level. Single-column primary keys are needed for things such
|
||||||
|
as the admin interface to work; e.g., you need a simple way of being able to
|
||||||
|
specify an object to edit or delete.
|
||||||
|
|
||||||
|
How do I add database-specific options to my CREATE TABLE statements, such as specifying MyISAM as the table type?
|
||||||
|
------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
We try to avoid adding special cases in the Django code to accommodate all the
|
||||||
|
database-specific options such as table type, etc. If you'd like to use any of
|
||||||
|
these options, create an :ref:`SQL initial data file <initial-sql>` that
|
||||||
|
contains ``ALTER TABLE`` statements that do what you want to do. The initial
|
||||||
|
data files are executed in your database after the ``CREATE TABLE`` statements.
|
||||||
|
|
||||||
|
For example, if you're using MySQL and want your tables to use the MyISAM table
|
||||||
|
type, create an initial data file and put something like this in it::
|
||||||
|
|
||||||
|
ALTER TABLE myapp_mytable ENGINE=MyISAM;
|
||||||
|
|
||||||
|
As explained in the :ref:`SQL initial data file <initial-sql>` documentation,
|
||||||
|
this SQL file can contain arbitrary SQL, so you can make any sorts of changes
|
||||||
|
you need to make.
|
||||||
|
|
||||||
|
Why is Django leaking memory?
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
Django isn't known to leak memory. If you find your Django processes are
|
||||||
|
allocating more and more memory, with no sign of releasing it, check to make
|
||||||
|
sure your ``DEBUG`` setting is set to ``True``. If ``DEBUG`` is ``True``, then
|
||||||
|
Django saves a copy of every SQL statement it has executed.
|
||||||
|
|
||||||
|
(The queries are saved in ``django.db.connection.queries``. See
|
||||||
|
`How can I see the raw SQL queries Django is running?`_.)
|
||||||
|
|
||||||
|
To fix the problem, set ``DEBUG`` to ``False``.
|
||||||
|
|
||||||
|
If you need to clear the query list manually at any point in your functions,
|
||||||
|
just call ``reset_queries()``, like this::
|
||||||
|
|
||||||
|
from django import db
|
||||||
|
db.reset_queries()
|
|
@ -0,0 +1,65 @@
|
||||||
|
.. _faq-usage:
|
||||||
|
|
||||||
|
FAQ: Using Django
|
||||||
|
=================
|
||||||
|
|
||||||
|
Why do I get an error about importing DJANGO_SETTINGS_MODULE?
|
||||||
|
-------------------------------------------------------------
|
||||||
|
|
||||||
|
Make sure that:
|
||||||
|
|
||||||
|
* The environment variable DJANGO_SETTINGS_MODULE is set to a fully-qualified
|
||||||
|
Python module (i.e. "mysite.settings").
|
||||||
|
|
||||||
|
* Said module is on ``sys.path`` (``import mysite.settings`` should work).
|
||||||
|
|
||||||
|
* The module doesn't contain syntax errors (of course).
|
||||||
|
|
||||||
|
* If you're using mod_python but *not* using Django's request handler,
|
||||||
|
you'll need to work around a mod_python bug related to the use of
|
||||||
|
``SetEnv``; before you import anything from Django you'll need to do
|
||||||
|
the following::
|
||||||
|
|
||||||
|
os.environ.update(req.subprocess_env)
|
||||||
|
|
||||||
|
(where ``req`` is the mod_python request object).
|
||||||
|
|
||||||
|
I can't stand your template language. Do I have to use it?
|
||||||
|
----------------------------------------------------------
|
||||||
|
|
||||||
|
We happen to think our template engine is the best thing since chunky bacon,
|
||||||
|
but we recognize that choosing a template language runs close to religion.
|
||||||
|
There's nothing about Django that requires using the template language, so
|
||||||
|
if you're attached to ZPT, Cheetah, or whatever, feel free to use those.
|
||||||
|
|
||||||
|
Do I have to use your model/database layer?
|
||||||
|
-------------------------------------------
|
||||||
|
|
||||||
|
Nope. Just like the template system, the model/database layer is decoupled from
|
||||||
|
the rest of the framework.
|
||||||
|
|
||||||
|
The one exception is: If you use a different database library, you won't get to
|
||||||
|
use Django's automatically-generated admin site. That app is coupled to the
|
||||||
|
Django database layer.
|
||||||
|
|
||||||
|
How do I use image and file fields?
|
||||||
|
-----------------------------------
|
||||||
|
|
||||||
|
Using a ``FileField`` or an ``ImageField`` in a model takes a few steps:
|
||||||
|
|
||||||
|
#. In your settings file, define ``MEDIA_ROOT`` as the full path to
|
||||||
|
a directory where you'd like Django to store uploaded files. (For
|
||||||
|
performance, these files are not stored in the database.) Define
|
||||||
|
``MEDIA_URL`` as the base public URL of that directory. Make sure that
|
||||||
|
this directory is writable by the Web server's user account.
|
||||||
|
|
||||||
|
#. Add the ``FileField`` or ``ImageField`` to your model, making sure
|
||||||
|
to define the ``upload_to`` option to tell Django to which subdirectory
|
||||||
|
of ``MEDIA_ROOT`` it should upload files.
|
||||||
|
|
||||||
|
#. All that will be stored in your database is a path to the file
|
||||||
|
(relative to ``MEDIA_ROOT``). You'll most likely want to use the
|
||||||
|
convenience ``get_<fieldname>_url`` function provided by Django. For
|
||||||
|
example, if your ``ImageField`` is called ``mug_shot``, you can get the
|
||||||
|
absolute URL to your image in a template with
|
||||||
|
``{{ object.get_mug_shot_url }}``.
|
388
docs/files.txt
|
@ -1,388 +0,0 @@
|
||||||
==============
|
|
||||||
Managing files
|
|
||||||
==============
|
|
||||||
|
|
||||||
**New in Django development version**
|
|
||||||
|
|
||||||
This document describes Django's file access APIs.
|
|
||||||
|
|
||||||
By default, Django stores files locally, using the ``MEDIA_ROOT`` and
|
|
||||||
``MEDIA_URL`` settings_. The examples below assume that you're using
|
|
||||||
these defaults.
|
|
||||||
|
|
||||||
However, Django provides ways to write custom `file storage systems`_ that
|
|
||||||
allow you to completely customize where and how Django stores files. The
|
|
||||||
second half of this document describes how these storage systems work.
|
|
||||||
|
|
||||||
.. _file storage systems: `File storage`_
|
|
||||||
.. _settings: ../settings/
|
|
||||||
|
|
||||||
Using files in models
|
|
||||||
=====================
|
|
||||||
|
|
||||||
When you use a `FileField`_ or `ImageField`_, Django provides a set of APIs you can use to deal with that file.
|
|
||||||
|
|
||||||
.. _filefield: ../model-api/#filefield
|
|
||||||
.. _imagefield: ../model-api/#imagefield
|
|
||||||
|
|
||||||
Consider the following model, using a ``FileField`` to store a photo::
|
|
||||||
|
|
||||||
class Car(models.Model):
|
|
||||||
name = models.CharField(max_length=255)
|
|
||||||
price = models.DecimalField(max_digits=5, decimal_places=2)
|
|
||||||
photo = models.ImageField(upload_to='cars')
|
|
||||||
|
|
||||||
Any ``Car`` instance will have a ``photo`` attribute that you can use to get at
|
|
||||||
the details of the attached photo::
|
|
||||||
|
|
||||||
>>> car = Car.object.get(name="57 Chevy")
|
|
||||||
>>> car.photo
|
|
||||||
<ImageFieldFile: chevy.jpg>
|
|
||||||
>>> car.photo.name
|
|
||||||
u'chevy.jpg'
|
|
||||||
>>> car.photo.path
|
|
||||||
u'/media/cars/chevy.jpg'
|
|
||||||
>>> car.photo.url
|
|
||||||
u'http://media.example.com/cars/chevy.jpg'
|
|
||||||
|
|
||||||
This object -- ``car.photo`` in the example -- is a ``File`` object, which means
|
|
||||||
it has all the methods and attributes described below.
|
|
||||||
|
|
||||||
The ``File`` object
|
|
||||||
===================
|
|
||||||
|
|
||||||
Internally, Django uses a ``django.core.files.File`` any time it needs to
|
|
||||||
represent a file. This object is a thin wrapper around Python's `built-in file
|
|
||||||
object`_ with some Django-specific additions.
|
|
||||||
|
|
||||||
.. _built-in file object: http://docs.python.org/lib/bltin-file-objects.html
|
|
||||||
|
|
||||||
Creating ``File`` instances
|
|
||||||
---------------------------
|
|
||||||
|
|
||||||
Most of the time you'll simply use a ``File`` that Django's given you (i.e. a
|
|
||||||
file attached to a model as above, or perhaps an `uploaded file`_).
|
|
||||||
|
|
||||||
.. _uploaded file: ../upload_handling/
|
|
||||||
|
|
||||||
If you need to construct a ``File`` yourself, the easiest way is to create one
|
|
||||||
using a Python built-in ``file`` object::
|
|
||||||
|
|
||||||
>>> from django.core.files import File
|
|
||||||
|
|
||||||
# Create a Python file object using open()
|
|
||||||
>>> f = open('/tmp/hello.world', 'w')
|
|
||||||
>>> myfile = File(f)
|
|
||||||
|
|
||||||
Now you can use any of the ``File`` attributes and methods defined below.
|
|
||||||
|
|
||||||
``File`` attributes and methods
|
|
||||||
-------------------------------
|
|
||||||
|
|
||||||
Django's ``File`` has the following attributes and methods:
|
|
||||||
|
|
||||||
``File.path``
|
|
||||||
~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
The absolute path to the file's location on a local filesystem.
|
|
||||||
|
|
||||||
Custom `file storage systems`_ may not store files locally; files stored on
|
|
||||||
these systems will have a ``path`` of ``None``.
|
|
||||||
|
|
||||||
``File.url``
|
|
||||||
~~~~~~~~~~~~
|
|
||||||
|
|
||||||
The URL where the file can be retrieved. This is often useful in templates_; for
|
|
||||||
example, a bit of a template for displaying a ``Car`` (see above) might look
|
|
||||||
like::
|
|
||||||
|
|
||||||
<img src='{{ car.photo.url }}' alt='{{ car.name }}' />
|
|
||||||
|
|
||||||
.. _templates: ../templates/
|
|
||||||
|
|
||||||
``File.size``
|
|
||||||
~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
The size of the file in bytes.
|
|
||||||
|
|
||||||
``File.open(mode=None)``
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Open or reopen the file (which by definition also does ``File.seek(0)``). The
|
|
||||||
``mode`` argument allows the same values as Python's standard ``open()``.
|
|
||||||
|
|
||||||
When reopening a file, ``mode`` will override whatever mode the file was
|
|
||||||
originally opened with; ``None`` means to reopen with the original mode.
|
|
||||||
|
|
||||||
``File.read(num_bytes=None)``
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Read content from the file. The optional ``size`` is the number of bytes to
|
|
||||||
read; if not specified, the file will be read to the end.
|
|
||||||
|
|
||||||
``File.__iter__()``
|
|
||||||
~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Iterate over the file yielding one line at a time.
|
|
||||||
|
|
||||||
``File.chunks(chunk_size=None)``
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Iterate over the file yielding "chunks" of a given size. ``chunk_size`` defaults
|
|
||||||
to 64 KB.
|
|
||||||
|
|
||||||
This is especially useful with very large files since it allows them to be
|
|
||||||
streamed off disk and avoids storing the whole file in memory.
|
|
||||||
|
|
||||||
``File.multiple_chunks(chunk_size=None)``
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Returns ``True`` if the file is large enough to require multiple chunks to
|
|
||||||
access all of its content give some ``chunk_size``.
|
|
||||||
|
|
||||||
``File.write(content)``
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Writes the specified content string to the file. Depending on the storage system
|
|
||||||
behind the scenes, this content might not be fully committed until ``close()``
|
|
||||||
is called on the file.
|
|
||||||
|
|
||||||
``File.close()``
|
|
||||||
~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Close the file.
|
|
||||||
|
|
||||||
.. TODO: document the rest of the File methods.
|
|
||||||
|
|
||||||
Additional ``ImageField`` attributes
|
|
||||||
------------------------------------
|
|
||||||
|
|
||||||
``File.width`` and ``File.height``
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
These attributes provide the dimensions of the image.
|
|
||||||
|
|
||||||
Additional methods on files attached to objects
|
|
||||||
-----------------------------------------------
|
|
||||||
|
|
||||||
Any ``File`` that's associated with an object (as with ``Car.photo``, above)
|
|
||||||
will also have a couple of extra methods:
|
|
||||||
|
|
||||||
``File.save(name, content, save=True)``
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Saves a new file with the file name and contents provided. This will not replace
|
|
||||||
the existing file, but will create a new file and update the object to point to
|
|
||||||
it. If ``save`` is ``True``, the model's ``save()`` method will be called once
|
|
||||||
the file is saved. That is, these two lines::
|
|
||||||
|
|
||||||
>>> car.photo.save('myphoto.jpg', contents, save=False)
|
|
||||||
>>> car.save()
|
|
||||||
|
|
||||||
are the same as this one line::
|
|
||||||
|
|
||||||
>>> car.photo.save('myphoto.jpg', contents, save=True)
|
|
||||||
|
|
||||||
``File.delete(save=True)``
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Remove the file from the model instance and delete the underlying file. The
|
|
||||||
``save`` argument works as above.
|
|
||||||
|
|
||||||
File storage
|
|
||||||
============
|
|
||||||
|
|
||||||
Behind the scenes, Django delegates decisions about how and where to store files
|
|
||||||
to a file storage system. This is the object that actually understands things
|
|
||||||
like file systems, opening and reading files, etc.
|
|
||||||
|
|
||||||
Django's default file storage is given by the `DEFAULT_FILE_STORAGE setting`_;
|
|
||||||
if you don't explicitly provide a storage system, this is the one that will be
|
|
||||||
used.
|
|
||||||
|
|
||||||
.. _default_file_storage setting: ../settings/#default-file-storage
|
|
||||||
|
|
||||||
The built-in filesystem storage class
|
|
||||||
-------------------------------------
|
|
||||||
|
|
||||||
Django ships with a built-in ``FileSystemStorage`` class (defined in
|
|
||||||
``django.core.files.storage``) which implements basic local filesystem file
|
|
||||||
storage. Its initializer takes two arguments:
|
|
||||||
|
|
||||||
====================== ===================================================
|
|
||||||
Argument Description
|
|
||||||
====================== ===================================================
|
|
||||||
``location`` Optional. Absolute path to the directory that will
|
|
||||||
hold the files. If omitted, it will be set to the
|
|
||||||
value of your ``MEDIA_ROOT`` setting.
|
|
||||||
``base_url`` Optional. URL that serves the files stored at this
|
|
||||||
location. If omitted, it will default to the value
|
|
||||||
of your ``MEDIA_URL`` setting.
|
|
||||||
====================== ===================================================
|
|
||||||
|
|
||||||
For example, the following code will store uploaded files under
|
|
||||||
``/media/photos`` regardless of what your ``MEDIA_ROOT`` setting is::
|
|
||||||
|
|
||||||
from django.db import models
|
|
||||||
from django.core.files.storage import FileSystemStorage
|
|
||||||
|
|
||||||
fs = FileSystemStorage(location='/media/photos')
|
|
||||||
|
|
||||||
class Car(models.Model):
|
|
||||||
...
|
|
||||||
photo = models.ImageField(storage=fs)
|
|
||||||
|
|
||||||
`Custom storage systems`_ work the same way: you can pass them in as the
|
|
||||||
``storage`` argument to a ``FileField``.
|
|
||||||
|
|
||||||
.. _custom storage systems: `writing a custom storage system`_
|
|
||||||
|
|
||||||
Storage objects
|
|
||||||
---------------
|
|
||||||
|
|
||||||
Though most of the time you'll want to use a ``File`` object (which delegates to
|
|
||||||
the proper storage for that file), you can use file storage systems directly.
|
|
||||||
You can create an instance of some custom file storage class, or -- often more
|
|
||||||
useful -- you can use the global default storage system::
|
|
||||||
|
|
||||||
>>> from django.core.files.storage import default_storage
|
|
||||||
|
|
||||||
>>> path = default_storage.save('/path/to/file', 'new content')
|
|
||||||
>>> path
|
|
||||||
u'/path/to/file'
|
|
||||||
|
|
||||||
>>> default_storage.filesize(path)
|
|
||||||
11
|
|
||||||
>>> default_storage.open(path).read()
|
|
||||||
'new content'
|
|
||||||
|
|
||||||
>>> default_storage.delete(path)
|
|
||||||
>>> default_storage.exists(path)
|
|
||||||
False
|
|
||||||
|
|
||||||
Storage objects define the following methods:
|
|
||||||
|
|
||||||
``Storage.exists(name)``
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
``True`` if a file exists given some ``name``.
|
|
||||||
|
|
||||||
``Storage.path(name)``
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
The local filesystem path where the file can be opened using Python's standard
|
|
||||||
``open()``. For storage systems that aren't accessible from the local
|
|
||||||
filesystem, this will raise ``NotImplementedError`` instead.
|
|
||||||
|
|
||||||
``Storage.size(name)``
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Returns the total size, in bytes, of the file referenced by ``name``.
|
|
||||||
|
|
||||||
``Storage.url(name)``
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Returns the URL where the contents of the file referenced by ``name`` can be
|
|
||||||
accessed.
|
|
||||||
|
|
||||||
``Storage.open(name, mode='rb')``
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Opens the file given by ``name``. Note that although the returned file is
|
|
||||||
guaranteed to be a ``File`` object, it might actually be some subclass. In the
|
|
||||||
case of remote file storage this means that reading/writing could be quite slow,
|
|
||||||
so be warned.
|
|
||||||
|
|
||||||
``Storage.save(name, content)``
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Saves a new file using the storage system, preferably with the name specified.
|
|
||||||
If there already exists a file with this name ``name``, the storage system may
|
|
||||||
modify the filename as necessary to get a unique name. The actual name of the
|
|
||||||
stored file will be returned.
|
|
||||||
|
|
||||||
``Storage.delete(name)``
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Deletes the file referenced by ``name``. This method won't raise an exception if
|
|
||||||
the file doesn't exist.
|
|
||||||
|
|
||||||
Writing a custom storage system
|
|
||||||
===============================
|
|
||||||
|
|
||||||
If you need to provide custom file storage -- a common example is storing files
|
|
||||||
on some remote system -- you can do so by defining a custom storage class.
|
|
||||||
You'll need to follow these steps:
|
|
||||||
|
|
||||||
#. Your custom storage system must be a subclass of
|
|
||||||
``django.core.files.storage.Storage``::
|
|
||||||
|
|
||||||
from django.core.files.storage import Storage
|
|
||||||
|
|
||||||
class MyStorage(Storage):
|
|
||||||
...
|
|
||||||
|
|
||||||
#. Django must be able to instantiate your storage system without any arguments.
|
|
||||||
This means that any settings should be taken from ``django.conf.settings``::
|
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
from django.core.files.storage import Storage
|
|
||||||
|
|
||||||
class MyStorage(Storage):
|
|
||||||
def __init__(self, option=None):
|
|
||||||
if not option:
|
|
||||||
option = settings.CUSTOM_STORAGE_OPTIONS
|
|
||||||
...
|
|
||||||
|
|
||||||
#. Your storage class must implement the ``_open()`` and ``_save()`` methods,
|
|
||||||
along with any other methods appropriate to your storage class. See below for
|
|
||||||
more on these methods.
|
|
||||||
|
|
||||||
In addition, if your class provides local file storage, it must override
|
|
||||||
the ``path()`` method.
|
|
||||||
|
|
||||||
Custom storage system methods
|
|
||||||
-----------------------------
|
|
||||||
|
|
||||||
Your custom storage system may override any of the storage methods explained
|
|
||||||
above in `storage objects`_. However, it's usually better to use the hooks
|
|
||||||
specifically designed for custom storage objects. These are:
|
|
||||||
|
|
||||||
``_open(name, mode='rb')``
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
**Required**.
|
|
||||||
|
|
||||||
Called by ``Storage.open()``, this is the actual mechanism the storage class
|
|
||||||
uses to open the file. This must return a ``File`` object, though in most cases,
|
|
||||||
you'll want to return some subclass here that implements logic specific to the
|
|
||||||
backend storage system.
|
|
||||||
|
|
||||||
``_save(name, content)``
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Called by ``Storage.save()``. The ``name`` will already have gone through
|
|
||||||
``get_valid_name()`` and ``get_available_name()``, and the ``content`` will be a
|
|
||||||
``File`` object itself. No return value is expected.
|
|
||||||
|
|
||||||
``get_valid_name(name)``
|
|
||||||
------------------------
|
|
||||||
|
|
||||||
Returns a filename suitable for use with the underlying storage system. The
|
|
||||||
``name`` argument passed to this method is the original filename sent to the
|
|
||||||
server, after having any path information removed. Override this to customize
|
|
||||||
how non-standard characters are converted to safe filenames.
|
|
||||||
|
|
||||||
The code provided on ``Storage`` retains only alpha-numeric characters, periods
|
|
||||||
and underscores from the original filename, removing everything else.
|
|
||||||
|
|
||||||
``get_available_name(name)``
|
|
||||||
----------------------------
|
|
||||||
|
|
||||||
Returns a filename that is available in the storage mechanism, possibly taking
|
|
||||||
the provided filename into account. The ``name`` argument passed to this method
|
|
||||||
will have already cleaned to a filename valid for the storage system, according
|
|
||||||
to the ``get_valid_name()`` method described above.
|
|
||||||
|
|
||||||
The code provided on ``Storage`` simply appends underscores to the filename
|
|
||||||
until it finds one that's available in the destination directory.
|
|
|
@ -1,95 +0,0 @@
|
||||||
============
|
|
||||||
Form preview
|
|
||||||
============
|
|
||||||
|
|
||||||
Django comes with an optional "form preview" application that helps automate
|
|
||||||
the following workflow:
|
|
||||||
|
|
||||||
"Display an HTML form, force a preview, then do something with the submission."
|
|
||||||
|
|
||||||
To force a preview of a form submission, all you have to do is write a short
|
|
||||||
Python class.
|
|
||||||
|
|
||||||
Overview
|
|
||||||
=========
|
|
||||||
|
|
||||||
Given a ``django.forms.Form`` subclass that you define, this application
|
|
||||||
takes care of the following workflow:
|
|
||||||
|
|
||||||
1. Displays the form as HTML on a Web page.
|
|
||||||
2. Validates the form data when it's submitted via POST.
|
|
||||||
a. If it's valid, displays a preview page.
|
|
||||||
b. If it's not valid, redisplays the form with error messages.
|
|
||||||
3. When the "confirmation" form is submitted from the preview page, calls
|
|
||||||
a hook that you define -- a ``done()`` method that gets passed the valid
|
|
||||||
data.
|
|
||||||
|
|
||||||
The framework enforces the required preview by passing a shared-secret hash to
|
|
||||||
the preview page via hidden form fields. If somebody tweaks the form parameters
|
|
||||||
on the preview page, the form submission will fail the hash-comparison test.
|
|
||||||
|
|
||||||
How to use ``FormPreview``
|
|
||||||
==========================
|
|
||||||
|
|
||||||
1. Point Django at the default FormPreview templates. There are two ways to
|
|
||||||
do this:
|
|
||||||
|
|
||||||
* Add ``'django.contrib.formtools'`` to your ``INSTALLED_APPS``
|
|
||||||
setting. This will work if your ``TEMPLATE_LOADERS`` setting includes
|
|
||||||
the ``app_directories`` template loader (which is the case by
|
|
||||||
default). See the `template loader docs`_ for more.
|
|
||||||
|
|
||||||
* Otherwise, determine the full filesystem path to the
|
|
||||||
``django/contrib/formtools/templates`` directory, and add that
|
|
||||||
directory to your ``TEMPLATE_DIRS`` setting.
|
|
||||||
|
|
||||||
2. Create a ``FormPreview`` subclass that overrides the ``done()`` method::
|
|
||||||
|
|
||||||
from django.contrib.formtools.preview import FormPreview
|
|
||||||
from myapp.models import SomeModel
|
|
||||||
|
|
||||||
class SomeModelFormPreview(FormPreview):
|
|
||||||
|
|
||||||
def done(self, request, cleaned_data):
|
|
||||||
# Do something with the cleaned_data, then redirect
|
|
||||||
# to a "success" page.
|
|
||||||
return HttpResponseRedirect('/form/success')
|
|
||||||
|
|
||||||
This method takes an ``HttpRequest`` object and a dictionary of the form
|
|
||||||
data after it has been validated and cleaned. It should return an
|
|
||||||
``HttpResponseRedirect`` that is the end result of the form being
|
|
||||||
submitted.
|
|
||||||
|
|
||||||
3. Change your URLconf to point to an instance of your ``FormPreview``
|
|
||||||
subclass::
|
|
||||||
|
|
||||||
from myapp.preview import SomeModelFormPreview
|
|
||||||
from myapp.models import SomeModel
|
|
||||||
from django import forms
|
|
||||||
|
|
||||||
...and add the following line to the appropriate model in your URLconf::
|
|
||||||
|
|
||||||
(r'^post/$', SomeModelFormPreview(SomeModelForm)),
|
|
||||||
|
|
||||||
where ``SomeModelForm`` is a Form or ModelForm class for the model.
|
|
||||||
|
|
||||||
4. Run the Django server and visit ``/post/`` in your browser.
|
|
||||||
|
|
||||||
.. _template loader docs: ../templates_python/#loader-types
|
|
||||||
|
|
||||||
``FormPreview`` classes
|
|
||||||
=======================
|
|
||||||
|
|
||||||
A ``FormPreview`` class is a simple Python class that represents the preview
|
|
||||||
workflow. ``FormPreview`` classes must subclass
|
|
||||||
``django.contrib.formtools.preview.FormPreview`` and override the ``done()``
|
|
||||||
method. They can live anywhere in your codebase.
|
|
||||||
|
|
||||||
``FormPreview`` templates
|
|
||||||
=========================
|
|
||||||
|
|
||||||
By default, the form is rendered via the template ``formtools/form.html``, and
|
|
||||||
the preview page is rendered via the template ``formtools.preview.html``.
|
|
||||||
These values can be overridden for a particular form preview by setting
|
|
||||||
``preview_template`` and ``form_template`` attributes on the FormPreview
|
|
||||||
subclass. See ``django/contrib/formtools/templates`` for the default templates.
|
|
|
@ -1,304 +0,0 @@
|
||||||
===========
|
|
||||||
Form wizard
|
|
||||||
===========
|
|
||||||
|
|
||||||
**New in Django development version.**
|
|
||||||
|
|
||||||
Django comes with an optional "form wizard" application that splits forms_
|
|
||||||
across multiple Web pages. It maintains state in hashed HTML
|
|
||||||
``<input type="hidden">`` fields, and the data isn't processed server-side
|
|
||||||
until the final form is submitted.
|
|
||||||
|
|
||||||
You might want to use this if you have a lengthy form that would be too
|
|
||||||
unwieldy for display on a single page. The first page might ask the user for
|
|
||||||
core information, the second page might ask for less important information,
|
|
||||||
etc.
|
|
||||||
|
|
||||||
The term "wizard," in this context, is `explained on Wikipedia`_.
|
|
||||||
|
|
||||||
.. _explained on Wikipedia: http://en.wikipedia.org/wiki/Wizard_%28software%29
|
|
||||||
.. _forms: ../forms/
|
|
||||||
|
|
||||||
How it works
|
|
||||||
============
|
|
||||||
|
|
||||||
Here's the basic workflow for how a user would use a wizard:
|
|
||||||
|
|
||||||
1. The user visits the first page of the wizard, fills in the form and
|
|
||||||
submits it.
|
|
||||||
2. The server validates the data. If it's invalid, the form is displayed
|
|
||||||
again, with error messages. If it's valid, the server calculates a
|
|
||||||
secure hash of the data and presents the user with the next form,
|
|
||||||
saving the validated data and hash in ``<input type="hidden">`` fields.
|
|
||||||
3. Step 1 and 2 repeat, for every subsequent form in the wizard.
|
|
||||||
4. Once the user has submitted all the forms and all the data has been
|
|
||||||
validated, the wizard processes the data -- saving it to the database,
|
|
||||||
sending an e-mail, or whatever the application needs to do.
|
|
||||||
|
|
||||||
Usage
|
|
||||||
=====
|
|
||||||
|
|
||||||
This application handles as much machinery for you as possible. Generally, you
|
|
||||||
just have to do these things:
|
|
||||||
|
|
||||||
1. Define a number of ``django.forms`` ``Form`` classes -- one per wizard
|
|
||||||
page.
|
|
||||||
2. Create a ``FormWizard`` class that specifies what to do once all of your
|
|
||||||
forms have been submitted and validated. This also lets you override some
|
|
||||||
of the wizard's behavior.
|
|
||||||
3. Create some templates that render the forms. You can define a single,
|
|
||||||
generic template to handle every one of the forms, or you can define a
|
|
||||||
specific template for each form.
|
|
||||||
4. Point your URLconf at your ``FormWizard`` class.
|
|
||||||
|
|
||||||
Defining ``Form`` classes
|
|
||||||
=========================
|
|
||||||
|
|
||||||
The first step in creating a form wizard is to create the ``Form`` classes.
|
|
||||||
These should be standard ``django.forms`` ``Form`` classes, covered in the
|
|
||||||
`forms documentation`_.
|
|
||||||
|
|
||||||
These classes can live anywhere in your codebase, but convention is to put them
|
|
||||||
in a file called ``forms.py`` in your application.
|
|
||||||
|
|
||||||
For example, let's write a "contact form" wizard, where the first page's form
|
|
||||||
collects the sender's e-mail address and subject, and the second page collects
|
|
||||||
the message itself. Here's what the ``forms.py`` might look like::
|
|
||||||
|
|
||||||
from django import forms
|
|
||||||
|
|
||||||
class ContactForm1(forms.Form):
|
|
||||||
subject = forms.CharField(max_length=100)
|
|
||||||
sender = forms.EmailField()
|
|
||||||
|
|
||||||
class ContactForm2(forms.Form):
|
|
||||||
message = forms.CharField(widget=forms.Textarea)
|
|
||||||
|
|
||||||
**Important limitation:** Because the wizard uses HTML hidden fields to store
|
|
||||||
data between pages, you may not include a ``FileField`` in any form except the
|
|
||||||
last one.
|
|
||||||
|
|
||||||
.. _forms documentation: ../forms/
|
|
||||||
|
|
||||||
Creating a ``FormWizard`` class
|
|
||||||
===============================
|
|
||||||
|
|
||||||
The next step is to create a ``FormWizard`` class, which should be a subclass
|
|
||||||
of ``django.contrib.formtools.wizard.FormWizard``.
|
|
||||||
|
|
||||||
As your ``Form`` classes, this ``FormWizard`` class can live anywhere in your
|
|
||||||
codebase, but convention is to put it in ``forms.py``.
|
|
||||||
|
|
||||||
The only requirement on this subclass is that it implement a ``done()`` method,
|
|
||||||
which specifies what should happen when the data for *every* form is submitted
|
|
||||||
and validated. This method is passed two arguments:
|
|
||||||
|
|
||||||
* ``request`` -- an HttpRequest_ object
|
|
||||||
* ``form_list`` -- a list of ``django.forms`` ``Form`` classes
|
|
||||||
|
|
||||||
In this simplistic example, rather than perform any database operation, the
|
|
||||||
method simply renders a template of the validated data::
|
|
||||||
|
|
||||||
from django.shortcuts import render_to_response
|
|
||||||
from django.contrib.formtools.wizard import FormWizard
|
|
||||||
|
|
||||||
class ContactWizard(FormWizard):
|
|
||||||
def done(self, request, form_list):
|
|
||||||
return render_to_response('done.html', {
|
|
||||||
'form_data': [form.cleaned_data for form in form_list],
|
|
||||||
})
|
|
||||||
|
|
||||||
Note that this method will be called via ``POST``, so it really ought to be a
|
|
||||||
good Web citizen and redirect after processing the data. Here's another
|
|
||||||
example::
|
|
||||||
|
|
||||||
from django.http import HttpResponseRedirect
|
|
||||||
from django.contrib.formtools.wizard import FormWizard
|
|
||||||
|
|
||||||
class ContactWizard(FormWizard):
|
|
||||||
def done(self, request, form_list):
|
|
||||||
do_something_with_the_form_data(form_list)
|
|
||||||
return HttpResponseRedirect('/page-to-redirect-to-when-done/')
|
|
||||||
|
|
||||||
See the section "Advanced ``FormWizard`` methods" below to learn about more
|
|
||||||
``FormWizard`` hooks.
|
|
||||||
|
|
||||||
.. _HttpRequest: request_response/#httprequest-objects
|
|
||||||
|
|
||||||
Creating templates for the forms
|
|
||||||
================================
|
|
||||||
|
|
||||||
Next, you'll need to create a template that renders the wizard's forms. By
|
|
||||||
default, every form uses a template called ``forms/wizard.html``. (You can
|
|
||||||
change this template name by overriding ``FormWizard.get_template()``, which is
|
|
||||||
documented below. This hook also allows you to use a different template for
|
|
||||||
each form.)
|
|
||||||
|
|
||||||
This template expects the following context:
|
|
||||||
|
|
||||||
* ``step_field`` -- The name of the hidden field containing the step.
|
|
||||||
* ``step0`` -- The current step (zero-based).
|
|
||||||
* ``step`` -- The current step (one-based).
|
|
||||||
* ``step_count`` -- The total number of steps.
|
|
||||||
* ``form`` -- The ``Form`` instance for the current step (either empty or
|
|
||||||
with errors).
|
|
||||||
* ``previous_fields`` -- A string representing every previous data field,
|
|
||||||
plus hashes for completed forms, all in the form of hidden fields. Note
|
|
||||||
that you'll need to run this through the ``safe`` template filter, to
|
|
||||||
prevent auto-escaping, because it's raw HTML.
|
|
||||||
|
|
||||||
It will also be passed any objects in ``extra_context``, which is a dictionary
|
|
||||||
you can specify that contains extra values to add to the context. You can
|
|
||||||
specify it in two ways:
|
|
||||||
|
|
||||||
* Set the ``extra_context`` attribute on your ``FormWizard`` subclass to a
|
|
||||||
dictionary.
|
|
||||||
|
|
||||||
* Pass ``extra_context`` as extra parameters in the URLconf.
|
|
||||||
|
|
||||||
Here's a full example template::
|
|
||||||
|
|
||||||
{% extends "base.html" %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<p>Step {{ step }} of {{ step_count }}</p>
|
|
||||||
<form action="." method="post">
|
|
||||||
<table>
|
|
||||||
{{ form }}
|
|
||||||
</table>
|
|
||||||
<input type="hidden" name="{{ step_field }}" value="{{ step0 }}" />
|
|
||||||
{{ previous_fields|safe }}
|
|
||||||
<input type="submit">
|
|
||||||
</form>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
Note that ``previous_fields``, ``step_field`` and ``step0`` are all required
|
|
||||||
for the wizard to work properly.
|
|
||||||
|
|
||||||
Hooking the wizard into a URLconf
|
|
||||||
=================================
|
|
||||||
|
|
||||||
Finally, give your new ``FormWizard`` object a URL in ``urls.py``. The wizard
|
|
||||||
takes a list of your form objects as arguments::
|
|
||||||
|
|
||||||
from django.conf.urls.defaults import *
|
|
||||||
from mysite.testapp.forms import ContactForm1, ContactForm2, ContactWizard
|
|
||||||
|
|
||||||
urlpatterns = patterns('',
|
|
||||||
(r'^contact/$', ContactWizard([ContactForm1, ContactForm2])),
|
|
||||||
)
|
|
||||||
|
|
||||||
Advanced ``FormWizard`` methods
|
|
||||||
===============================
|
|
||||||
|
|
||||||
Aside from the ``done()`` method, ``FormWizard`` offers a few advanced method
|
|
||||||
hooks that let you customize how your wizard works.
|
|
||||||
|
|
||||||
Some of these methods take an argument ``step``, which is a zero-based counter
|
|
||||||
representing the current step of the wizard. (E.g., the first form is ``0`` and
|
|
||||||
the second form is ``1``.)
|
|
||||||
|
|
||||||
``prefix_for_step``
|
|
||||||
~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Given the step, returns a ``Form`` prefix to use. By default, this simply uses
|
|
||||||
the step itself. For more, see the `form prefix documentation`_.
|
|
||||||
|
|
||||||
Default implementation::
|
|
||||||
|
|
||||||
def prefix_for_step(self, step):
|
|
||||||
return str(step)
|
|
||||||
|
|
||||||
.. _form prefix documentation: ../forms/#prefixes-for-forms
|
|
||||||
|
|
||||||
``render_hash_failure``
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Renders a template if the hash check fails. It's rare that you'd need to
|
|
||||||
override this.
|
|
||||||
|
|
||||||
Default implementation::
|
|
||||||
|
|
||||||
def render_hash_failure(self, request, step):
|
|
||||||
return self.render(self.get_form(step), request, step,
|
|
||||||
context={'wizard_error': 'We apologize, but your form has expired. Please continue filling out the form from this page.'})
|
|
||||||
|
|
||||||
``security_hash``
|
|
||||||
~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Calculates the security hash for the given request object and ``Form`` instance.
|
|
||||||
|
|
||||||
By default, this uses an MD5 hash of the form data and your
|
|
||||||
`SECRET_KEY setting`_. It's rare that somebody would need to override this.
|
|
||||||
|
|
||||||
Example::
|
|
||||||
|
|
||||||
def security_hash(self, request, form):
|
|
||||||
return my_hash_function(request, form)
|
|
||||||
|
|
||||||
.. _SECRET_KEY setting: ../settings/#secret-key
|
|
||||||
|
|
||||||
``parse_params``
|
|
||||||
~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
A hook for saving state from the request object and ``args`` / ``kwargs`` that
|
|
||||||
were captured from the URL by your URLconf.
|
|
||||||
|
|
||||||
By default, this does nothing.
|
|
||||||
|
|
||||||
Example::
|
|
||||||
|
|
||||||
def parse_params(self, request, *args, **kwargs):
|
|
||||||
self.my_state = args[0]
|
|
||||||
|
|
||||||
``get_template``
|
|
||||||
~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Returns the name of the template that should be used for the given step.
|
|
||||||
|
|
||||||
By default, this returns ``'forms/wizard.html'``, regardless of step.
|
|
||||||
|
|
||||||
Example::
|
|
||||||
|
|
||||||
def get_template(self, step):
|
|
||||||
return 'myapp/wizard_%s.html' % step
|
|
||||||
|
|
||||||
If ``get_template`` returns a list of strings, then the wizard will use the
|
|
||||||
template system's ``select_template()`` function, `explained in the template docs`_.
|
|
||||||
This means the system will use the first template that exists on the filesystem.
|
|
||||||
For example::
|
|
||||||
|
|
||||||
def get_template(self, step):
|
|
||||||
return ['myapp/wizard_%s.html' % step, 'myapp/wizard.html']
|
|
||||||
|
|
||||||
.. _explained in the template docs: ../templates_python/#the-python-api
|
|
||||||
|
|
||||||
``render_template``
|
|
||||||
~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Renders the template for the given step, returning an ``HttpResponse`` object.
|
|
||||||
|
|
||||||
Override this method if you want to add a custom context, return a different
|
|
||||||
MIME type, etc. If you only need to override the template name, use
|
|
||||||
``get_template()`` instead.
|
|
||||||
|
|
||||||
The template will be rendered with the context documented in the
|
|
||||||
"Creating templates for the forms" section above.
|
|
||||||
|
|
||||||
``process_step``
|
|
||||||
~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Hook for modifying the wizard's internal state, given a fully validated ``Form``
|
|
||||||
object. The Form is guaranteed to have clean, valid data.
|
|
||||||
|
|
||||||
This method should *not* modify any of that data. Rather, it might want to set
|
|
||||||
``self.extra_context`` or dynamically alter ``self.form_list``, based on
|
|
||||||
previously submitted forms.
|
|
||||||
|
|
||||||
Note that this method is called every time a page is rendered for *all*
|
|
||||||
submitted steps.
|
|
||||||
|
|
||||||
The function signature::
|
|
||||||
|
|
||||||
def process_step(self, request, form, step):
|
|
||||||
# ...
|
|
2468
docs/forms.txt
|
@ -0,0 +1,80 @@
|
||||||
|
.. _glossary:
|
||||||
|
|
||||||
|
========
|
||||||
|
Glossary
|
||||||
|
========
|
||||||
|
|
||||||
|
.. glossary::
|
||||||
|
|
||||||
|
field
|
||||||
|
An attribute on a :term:`model`; a given field usually maps directly to
|
||||||
|
a single database column.
|
||||||
|
|
||||||
|
See :ref:`topics-db-models`.
|
||||||
|
|
||||||
|
generic view
|
||||||
|
A higher-order :term:`view` function that abstracts common idioms and patterns
|
||||||
|
found in view development and abstracts them.
|
||||||
|
|
||||||
|
See :ref:`ref-generic-views`.
|
||||||
|
|
||||||
|
model
|
||||||
|
Models store your application's data.
|
||||||
|
|
||||||
|
See :ref:`topics-db-models`.
|
||||||
|
|
||||||
|
MTV
|
||||||
|
See :ref:`mtv`.
|
||||||
|
|
||||||
|
MVC
|
||||||
|
`Model-view-controller`__; a software pattern. Django :ref:`follows MVC
|
||||||
|
to some extent <mtv>`.
|
||||||
|
|
||||||
|
__ http://en.wikipedia.org/wiki/Model-view-controller
|
||||||
|
|
||||||
|
project
|
||||||
|
A Python package -- i.e. a directory of code -- that contains all the
|
||||||
|
settings for an instance of Django. This would include database
|
||||||
|
configuration, Django-specific options and application-specific
|
||||||
|
settings.
|
||||||
|
|
||||||
|
property
|
||||||
|
Also known as "managed attributes", and a feature of Python since
|
||||||
|
version 2.2. From `the property documentation`__:
|
||||||
|
|
||||||
|
Properties are a neat way to implement attributes whose usage
|
||||||
|
resembles attribute access, but whose implementation uses method
|
||||||
|
calls. [...] You
|
||||||
|
could only do this by overriding ``__getattr__`` and
|
||||||
|
``__setattr__``; but overriding ``__setattr__`` slows down all
|
||||||
|
attribute assignments considerably, and overriding ``__getattr__``
|
||||||
|
is always a bit tricky to get right. Properties let you do this
|
||||||
|
painlessly, without having to override ``__getattr__`` or
|
||||||
|
``__setattr__``.
|
||||||
|
|
||||||
|
__ http://www.python.org/download/releases/2.2/descrintro/#property
|
||||||
|
|
||||||
|
queryset
|
||||||
|
An object representing some set of rows to be fetched from the database.
|
||||||
|
|
||||||
|
See :ref:`topics-db-queries`.
|
||||||
|
|
||||||
|
slug
|
||||||
|
A short label for something, containing only letters, numbers,
|
||||||
|
underscores or hyphens. They're generally used in URLs. For
|
||||||
|
example, in a typical blog entry URL:
|
||||||
|
|
||||||
|
.. parsed-literal::
|
||||||
|
|
||||||
|
http://www.djangoproject.com/weblog/2008/apr/12/**spring**/
|
||||||
|
|
||||||
|
the last bit (``spring``) is the slug.
|
||||||
|
|
||||||
|
template
|
||||||
|
A chunk of text that separates the presentation of a document from its
|
||||||
|
data.
|
||||||
|
|
||||||
|
See :ref:`topics-templates`.
|
||||||
|
|
||||||
|
view
|
||||||
|
A function responsible for rending a page.
|
|
@ -1,10 +1,13 @@
|
||||||
|
.. _howto-apache-auth:
|
||||||
|
|
||||||
=========================================================
|
=========================================================
|
||||||
Authenticating against Django's user database from Apache
|
Authenticating against Django's user database from Apache
|
||||||
=========================================================
|
=========================================================
|
||||||
|
|
||||||
Since keeping multiple authentication databases in sync is a common problem when
|
Since keeping multiple authentication databases in sync is a common problem when
|
||||||
dealing with Apache, you can configuring Apache to authenticate against Django's
|
dealing with Apache, you can configuring Apache to authenticate against Django's
|
||||||
`authentication system`_ directly. For example, you could:
|
:ref:`authentication system <topics-auth>` directly. For example, you
|
||||||
|
could:
|
||||||
|
|
||||||
* Serve static/media files directly from Apache only to authenticated users.
|
* Serve static/media files directly from Apache only to authenticated users.
|
||||||
|
|
||||||
|
@ -13,12 +16,17 @@ dealing with Apache, you can configuring Apache to authenticate against Django's
|
||||||
|
|
||||||
* Allow certain users to connect to a WebDAV share created with mod_dav_.
|
* Allow certain users to connect to a WebDAV share created with mod_dav_.
|
||||||
|
|
||||||
|
.. _Subversion: http://subversion.tigris.org/
|
||||||
|
.. _mod_dav: http://httpd.apache.org/docs/2.0/mod/mod_dav.html
|
||||||
|
|
||||||
Configuring Apache
|
Configuring Apache
|
||||||
==================
|
==================
|
||||||
|
|
||||||
To check against Django's authorization database from a Apache configuration
|
To check against Django's authorization database from a Apache configuration
|
||||||
file, you'll need to use mod_python's ``PythonAuthenHandler`` directive along
|
file, you'll need to use mod_python's ``PythonAuthenHandler`` directive along
|
||||||
with the standard ``Auth*`` and ``Require`` directives::
|
with the standard ``Auth*`` and ``Require`` directives:
|
||||||
|
|
||||||
|
.. code-block:: apache
|
||||||
|
|
||||||
<Location /example/>
|
<Location /example/>
|
||||||
AuthType Basic
|
AuthType Basic
|
||||||
|
@ -44,6 +52,8 @@ with the standard ``Auth*`` and ``Require`` directives::
|
||||||
on which other authentication modules you have loaded, you might need one
|
on which other authentication modules you have loaded, you might need one
|
||||||
or more of the following directives::
|
or more of the following directives::
|
||||||
|
|
||||||
|
.. code-block:: apache
|
||||||
|
|
||||||
AuthBasicAuthoritative Off
|
AuthBasicAuthoritative Off
|
||||||
AuthDefaultAuthoritative Off
|
AuthDefaultAuthoritative Off
|
||||||
AuthzLDAPAuthoritative Off
|
AuthzLDAPAuthoritative Off
|
||||||
|
@ -94,8 +104,9 @@ location to users marked as staff members. You can use a set of
|
||||||
Defaults to ``off``.
|
Defaults to ``off``.
|
||||||
|
|
||||||
``DjangoPermissionName`` The name of a permission to require for
|
``DjangoPermissionName`` The name of a permission to require for
|
||||||
access. See `custom permissions`_ for
|
access. See :ref:`custom permissions
|
||||||
more information.
|
<custom-permissions>` for more
|
||||||
|
information.
|
||||||
|
|
||||||
By default no specific permission will be
|
By default no specific permission will be
|
||||||
required.
|
required.
|
||||||
|
@ -109,8 +120,3 @@ are equivalent::
|
||||||
|
|
||||||
SetEnv DJANGO_SETTINGS_MODULE mysite.settings
|
SetEnv DJANGO_SETTINGS_MODULE mysite.settings
|
||||||
PythonOption DJANGO_SETTINGS_MODULE mysite.settings
|
PythonOption DJANGO_SETTINGS_MODULE mysite.settings
|
||||||
|
|
||||||
.. _authentication system: ../authentication/
|
|
||||||
.. _Subversion: http://subversion.tigris.org/
|
|
||||||
.. _mod_dav: http://httpd.apache.org/docs/2.0/mod/mod_dav.html
|
|
||||||
.. _custom permissions: ../authentication/#custom-permissions
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
.. _howto-custom-file-storage:
|
||||||
|
|
||||||
|
Writing a custom storage system
|
||||||
|
===============================
|
||||||
|
|
||||||
|
If you need to provide custom file storage -- a common example is storing files
|
||||||
|
on some remote system -- you can do so by defining a custom storage class.
|
||||||
|
You'll need to follow these steps:
|
||||||
|
|
||||||
|
#. Your custom storage system must be a subclass of
|
||||||
|
``django.core.files.storage.Storage``::
|
||||||
|
|
||||||
|
from django.core.files.storage import Storage
|
||||||
|
|
||||||
|
class MyStorage(Storage):
|
||||||
|
...
|
||||||
|
|
||||||
|
#. Django must be able to instantiate your storage system without any arguments.
|
||||||
|
This means that any settings should be taken from ``django.conf.settings``::
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.core.files.storage import Storage
|
||||||
|
|
||||||
|
class MyStorage(Storage):
|
||||||
|
def __init__(self, option=None):
|
||||||
|
if not option:
|
||||||
|
option = settings.CUSTOM_STORAGE_OPTIONS
|
||||||
|
...
|
||||||
|
|
||||||
|
#. Your storage class must implement the ``_open()`` and ``_save()`` methods,
|
||||||
|
along with any other methods appropriate to your storage class. See below for
|
||||||
|
more on these methods.
|
||||||
|
|
||||||
|
In addition, if your class provides local file storage, it must override
|
||||||
|
the ``path()`` method.
|
||||||
|
|
||||||
|
Your custom storage system may override any of the storage methods explained in
|
||||||
|
:ref:`ref-files-storage`. However, it's usually better to use the hooks
|
||||||
|
specifically designed for custom storage objects. These are:
|
||||||
|
|
||||||
|
``_open(name, mode='rb')``
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
**Required**.
|
||||||
|
|
||||||
|
Called by ``Storage.open()``, this is the actual mechanism the storage class
|
||||||
|
uses to open the file. This must return a ``File`` object, though in most cases,
|
||||||
|
you'll want to return some subclass here that implements logic specific to the
|
||||||
|
backend storage system.
|
||||||
|
|
||||||
|
``_save(name, content)``
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Called by ``Storage.save()``. The ``name`` will already have gone through
|
||||||
|
``get_valid_name()`` and ``get_available_name()``, and the ``content`` will be a
|
||||||
|
``File`` object itself. No return value is expected.
|
||||||
|
|
||||||
|
``get_valid_name(name)``
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
Returns a filename suitable for use with the underlying storage system. The
|
||||||
|
``name`` argument passed to this method is the original filename sent to the
|
||||||
|
server, after having any path information removed. Override this to customize
|
||||||
|
how non-standard characters are converted to safe filenames.
|
||||||
|
|
||||||
|
The code provided on ``Storage`` retains only alpha-numeric characters, periods
|
||||||
|
and underscores from the original filename, removing everything else.
|
||||||
|
|
||||||
|
``get_available_name(name)``
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
Returns a filename that is available in the storage mechanism, possibly taking
|
||||||
|
the provided filename into account. The ``name`` argument passed to this method
|
||||||
|
will have already cleaned to a filename valid for the storage system, according
|
||||||
|
to the ``get_valid_name()`` method described above.
|
||||||
|
|
||||||
|
The code provided on ``Storage`` simply appends underscores to the filename
|
||||||
|
until it finds one that's available in the destination directory.
|
|
@ -0,0 +1,33 @@
|
||||||
|
.. _howto-custom-management-commands:
|
||||||
|
|
||||||
|
Writing custom django-admin commands
|
||||||
|
====================================
|
||||||
|
|
||||||
|
**New in Django development version**
|
||||||
|
|
||||||
|
Applications can register their own actions with ``manage.py``. For example,
|
||||||
|
you might want to add a ``manage.py`` action for a Django app that you're
|
||||||
|
distributing.
|
||||||
|
|
||||||
|
To do this, just add a ``management/commands`` directory to your application.
|
||||||
|
Each Python module in that directory will be auto-discovered and registered as
|
||||||
|
a command that can be executed as an action when you run ``manage.py``::
|
||||||
|
|
||||||
|
blog/
|
||||||
|
__init__.py
|
||||||
|
models.py
|
||||||
|
management/
|
||||||
|
__init__.py
|
||||||
|
commands/
|
||||||
|
__init__.py
|
||||||
|
explode.py
|
||||||
|
views.py
|
||||||
|
|
||||||
|
In this example, the ``explode`` command will be made available to any project
|
||||||
|
that includes the ``blog`` application in ``settings.INSTALLED_APPS``.
|
||||||
|
|
||||||
|
The ``explode.py`` module has only one requirement -- it must define a class
|
||||||
|
called ``Command`` that extends ``django.core.management.base.BaseCommand``.
|
||||||
|
|
||||||
|
For more details on how to define your own commands, look at the code for the
|
||||||
|
existing ``django-admin.py`` commands, in ``/django/core/management/commands``.
|
|
@ -1,23 +1,28 @@
|
||||||
===================
|
.. _howto-custom-model-fields:
|
||||||
Custom model fields
|
|
||||||
===================
|
===========================
|
||||||
|
Writing custom model fields
|
||||||
|
===========================
|
||||||
|
|
||||||
**New in Django development version**
|
**New in Django development version**
|
||||||
|
|
||||||
Introduction
|
Introduction
|
||||||
============
|
============
|
||||||
|
|
||||||
The `model reference`_ documentation explains how to use Django's standard
|
The :ref:`model reference <topics-db-models>` documentation explains how to use
|
||||||
field classes -- ``CharField``, ``DateField``, etc. For many purposes, those
|
Django's standard field classes -- :class:`~django.db.models.CharField`,
|
||||||
classes are all you'll need. Sometimes, though, the Django version won't meet
|
:class:`~django.db.models.DateField`, etc. For many purposes, those classes are
|
||||||
your precise requirements, or you'll want to use a field that is entirely
|
all you'll need. Sometimes, though, the Django version won't meet your precise
|
||||||
different from those shipped with Django.
|
requirements, or you'll want to use a field that is entirely different from
|
||||||
|
those shipped with Django.
|
||||||
|
|
||||||
Django's built-in field types don't cover every possible database column type --
|
Django's built-in field types don't cover every possible database column type --
|
||||||
only the common types, such as ``VARCHAR`` and ``INTEGER``. For more obscure
|
only the common types, such as ``VARCHAR`` and ``INTEGER``. For more obscure
|
||||||
column types, such as geographic polygons or even user-created types such as
|
column types, such as geographic polygons or even user-created types such as
|
||||||
`PostgreSQL custom types`_, you can define your own Django ``Field`` subclasses.
|
`PostgreSQL custom types`_, you can define your own Django ``Field`` subclasses.
|
||||||
|
|
||||||
|
.. _PostgreSQL custom types: http://www.postgresql.org/docs/8.2/interactive/sql-createtype.html
|
||||||
|
|
||||||
Alternatively, you may have a complex Python object that can somehow be
|
Alternatively, you may have a complex Python object that can somehow be
|
||||||
serialized to fit into a standard database column type. This is another case
|
serialized to fit into a standard database column type. This is another case
|
||||||
where a ``Field`` subclass will help you use your object with your models.
|
where a ``Field`` subclass will help you use your object with your models.
|
||||||
|
@ -43,6 +48,8 @@ Our class looks something like this::
|
||||||
|
|
||||||
# ... (other possibly useful methods omitted) ...
|
# ... (other possibly useful methods omitted) ...
|
||||||
|
|
||||||
|
.. _Bridge: http://en.wikipedia.org/wiki/Contract_bridge
|
||||||
|
|
||||||
This is just an ordinary Python class, with nothing Django-specific about it.
|
This is just an ordinary Python class, with nothing Django-specific about it.
|
||||||
We'd like to be able to do things like this in our models (we assume the
|
We'd like to be able to do things like this in our models (we assume the
|
||||||
``hand`` attribute on the model is an instance of ``Hand``)::
|
``hand`` attribute on the model is an instance of ``Hand``)::
|
||||||
|
@ -68,10 +75,6 @@ model support for existing classes where you cannot change the source code.
|
||||||
strings, or floats, for example. This case is similar to our ``Hand``
|
strings, or floats, for example. This case is similar to our ``Hand``
|
||||||
example and we'll note any differences as we go along.
|
example and we'll note any differences as we go along.
|
||||||
|
|
||||||
.. _model reference: ../model_api/
|
|
||||||
.. _PostgreSQL custom types: http://www.postgresql.org/docs/8.2/interactive/sql-createtype.html
|
|
||||||
.. _Bridge: http://en.wikipedia.org/wiki/Contract_bridge
|
|
||||||
|
|
||||||
Background theory
|
Background theory
|
||||||
=================
|
=================
|
||||||
|
|
||||||
|
@ -103,15 +106,13 @@ What does a field class do?
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
||||||
All of Django's fields (and when we say *fields* in this document, we always
|
All of Django's fields (and when we say *fields* in this document, we always
|
||||||
mean model fields and not `form fields`_) are subclasses of
|
mean model fields and not :ref:`form fields <ref-forms-fields>`) are subclasses
|
||||||
``django.db.models.Field``. Most of the information that Django records about a
|
of :class:`django.db.models.Field`. Most of the information that Django records
|
||||||
field is common to all fields -- name, help text, validator lists, uniqueness
|
about a field is common to all fields -- name, help text, validator lists,
|
||||||
and so forth. Storing all that information is handled by ``Field``. We'll get
|
uniqueness and so forth. Storing all that information is handled by ``Field``.
|
||||||
into the precise details of what ``Field`` can do later on; for now, suffice it
|
We'll get into the precise details of what ``Field`` can do later on; for now,
|
||||||
to say that everything descends from ``Field`` and then customizes key pieces
|
suffice it to say that everything descends from ``Field`` and then customizes
|
||||||
of the class behavior.
|
key pieces of the class behavior.
|
||||||
|
|
||||||
.. _form fields: ../forms/#fields
|
|
||||||
|
|
||||||
It's important to realize that a Django field class is not what is stored in
|
It's important to realize that a Django field class is not what is stored in
|
||||||
your model attributes. The model attributes contain normal Python objects. The
|
your model attributes. The model attributes contain normal Python objects. The
|
||||||
|
@ -120,7 +121,7 @@ when the model class is created (the precise details of how this is done are
|
||||||
unimportant here). This is because the field classes aren't necessary when
|
unimportant here). This is because the field classes aren't necessary when
|
||||||
you're just creating and modifying attributes. Instead, they provide the
|
you're just creating and modifying attributes. Instead, they provide the
|
||||||
machinery for converting between the attribute value and what is stored in the
|
machinery for converting between the attribute value and what is stored in the
|
||||||
database or sent to the serializer.
|
database or sent to the :ref:`serializer <topics-serialization>`.
|
||||||
|
|
||||||
Keep this in mind when creating your own custom fields. The Django ``Field``
|
Keep this in mind when creating your own custom fields. The Django ``Field``
|
||||||
subclass you write provides the machinery for converting between your Python
|
subclass you write provides the machinery for converting between your Python
|
||||||
|
@ -139,22 +140,25 @@ classes when you want a custom field:
|
||||||
how to convert your first class back and forth between its permanent
|
how to convert your first class back and forth between its permanent
|
||||||
storage form and the Python form.
|
storage form and the Python form.
|
||||||
|
|
||||||
Writing a ``Field`` subclass
|
Writing a field subclass
|
||||||
=============================
|
========================
|
||||||
|
|
||||||
When planning your ``Field`` subclass, first give some thought to which
|
When planning your :class:`~django.db.models.Field` subclass, first give some
|
||||||
existing ``Field`` class your new field is most similar to. Can you subclass an
|
thought to which existing :class:`~django.db.models.Field` class your new field
|
||||||
existing Django field and save yourself some work? If not, you should subclass
|
is most similar to. Can you subclass an existing Django field and save yourself
|
||||||
the ``Field`` class, from which everything is descended.
|
some work? If not, you should subclass the :class:`~django.db.models.Field`
|
||||||
|
class, from which everything is descended.
|
||||||
|
|
||||||
Initializing your new field is a matter of separating out any arguments that
|
Initializing your new field is a matter of separating out any arguments that are
|
||||||
are specific to your case from the common arguments and passing the latter to
|
specific to your case from the common arguments and passing the latter to the
|
||||||
the ``__init__()`` method of ``Field`` (or your parent class).
|
:meth:`~django.db.models.Field.__init__` method of
|
||||||
|
:class:`~django.db.models.Field` (or your parent class).
|
||||||
|
|
||||||
In our example, we'll call our field ``HandField``. (It's a good idea to call
|
In our example, we'll call our field ``HandField``. (It's a good idea to call
|
||||||
your ``Field`` subclass ``(Something)Field``, so it's easily identifiable as a
|
your :class:`~django.db.models.Field` subclass ``<Something>Field``, so it's
|
||||||
``Field`` subclass.) It doesn't behave like any existing field, so we'll
|
easily identifiable as a :class:`~django.db.models.Field` subclass.) It doesn't
|
||||||
subclass directly from ``Field``::
|
behave like any existing field, so we'll subclass directly from
|
||||||
|
:class:`~django.db.models.Field`::
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
|
@ -169,10 +173,13 @@ card values plus their suits; 104 characters in total.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
Many of Django's model fields accept options that they don't do anything
|
Many of Django's model fields accept options that they don't do anything
|
||||||
with. For example, you can pass both ``editable`` and ``auto_now`` to a
|
with. For example, you can pass both
|
||||||
``DateField`` and it will simply ignore the ``editable`` parameter
|
:attr:`~django.db.models.Field.editable` and
|
||||||
(``auto_now`` being set implies ``editable=False``). No error is raised in
|
:attr:`~django.db.models.Field.auto_now` to a
|
||||||
this case.
|
:class:`django.db.models.DateField` and it will simply ignore the
|
||||||
|
:attr:`~django.db.models.Field.editable` parameter
|
||||||
|
(:attr:`~django.db.models.Field.auto_now` being set implies
|
||||||
|
``editable=False``). No error is raised in this case.
|
||||||
|
|
||||||
This behavior simplifies the field classes, because they don't need to
|
This behavior simplifies the field classes, because they don't need to
|
||||||
check for options that aren't necessary. They just pass all the options to
|
check for options that aren't necessary. They just pass all the options to
|
||||||
|
@ -180,41 +187,42 @@ card values plus their suits; 104 characters in total.
|
||||||
you want your fields to be more strict about the options they select, or
|
you want your fields to be more strict about the options they select, or
|
||||||
to use the simpler, more permissive behavior of the current fields.
|
to use the simpler, more permissive behavior of the current fields.
|
||||||
|
|
||||||
The ``Field.__init__()`` method takes the following parameters, in this
|
The :meth:`~django.db.models.Field.__init__` method takes the following
|
||||||
order:
|
parameters:
|
||||||
|
|
||||||
* ``verbose_name``
|
* :attr:`~django.db.models.Field.verbose_name`
|
||||||
* ``name``
|
* :attr:`~django.db.models.Field.name`
|
||||||
* ``primary_key``
|
* :attr:`~django.db.models.Field.primary_key`
|
||||||
* ``max_length``
|
* :attr:`~django.db.models.Field.max_length`
|
||||||
* ``unique``
|
* :attr:`~django.db.models.Field.unique`
|
||||||
* ``blank``
|
* :attr:`~django.db.models.Field.blank`
|
||||||
* ``null``
|
* :attr:`~django.db.models.Field.null`
|
||||||
* ``db_index``
|
* :attr:`~django.db.models.Field.db_index`
|
||||||
* ``core``
|
* :attr:`~django.db.models.Field.core`
|
||||||
* ``rel``: Used for related fields (like ``ForeignKey``). For advanced use
|
* :attr:`~django.db.models.Field.rel`: Used for related fields (like
|
||||||
only.
|
:attr:`~django.db.models.Field.ForeignKey`). For advanced use only.
|
||||||
* ``default``
|
* :attr:`~django.db.models.Field.default`
|
||||||
* ``editable``
|
* :attr:`~django.db.models.Field.editable`
|
||||||
* ``serialize``: If ``False``, the field will not be serialized when the
|
* :attr:`~django.db.models.Field.serialize`: If
|
||||||
model is passed to Django's serializers_. Defaults to ``True``.
|
:attr:`~django.db.models.Field.False`, the field will not be serialized
|
||||||
* ``prepopulate_from``
|
when the model is passed to Django's :ref:`serializers
|
||||||
* ``unique_for_date``
|
<topics-serialization>`. Defaults to
|
||||||
* ``unique_for_month``
|
:attr:`~django.db.models.Field.True`.
|
||||||
* ``unique_for_year``
|
* :attr:`~django.db.models.Field.prepopulate_from`
|
||||||
* ``validator_list``
|
* :attr:`~django.db.models.Field.unique_for_date`
|
||||||
* ``choices``
|
* :attr:`~django.db.models.Field.unique_for_month`
|
||||||
* ``help_text``
|
* :attr:`~django.db.models.Field.unique_for_year`
|
||||||
* ``db_column``
|
* :attr:`~django.db.models.Field.validator_list`
|
||||||
* ``db_tablespace``: Currently only used with the Oracle backend and only
|
* :attr:`~django.db.models.Field.choices`
|
||||||
for index creation. You can usually ignore this option.
|
* :attr:`~django.db.models.Field.help_text`
|
||||||
|
* :attr:`~django.db.models.Field.db_column`
|
||||||
|
* :attr:`~django.db.models.Field.db_tablespace`: Currently only used with
|
||||||
|
the Oracle backend and only for index creation. You can usually ignore
|
||||||
|
this option.
|
||||||
|
|
||||||
All of the options without an explanation in the above list have the same
|
All of the options without an explanation in the above list have the same
|
||||||
meaning they do for normal Django fields. See the `model documentation`_ for
|
meaning they do for normal Django fields. See the :ref:`field documentation
|
||||||
examples and details.
|
<ref-models-fields>` for examples and details.
|
||||||
|
|
||||||
.. _serializers: ../serialization/
|
|
||||||
.. _model documentation: ../model-api/
|
|
||||||
|
|
||||||
The ``SubfieldBase`` metaclass
|
The ``SubfieldBase`` metaclass
|
||||||
------------------------------
|
------------------------------
|
||||||
|
@ -226,13 +234,16 @@ possible. If you're only working with custom database column types and your
|
||||||
model fields appear in Python as standard Python types direct from the
|
model fields appear in Python as standard Python types direct from the
|
||||||
database backend, you don't need to worry about this section.
|
database backend, you don't need to worry about this section.
|
||||||
|
|
||||||
If you're handling custom Python types, such as our ``Hand`` class, we need
|
If you're handling custom Python types, such as our ``Hand`` class, we need to
|
||||||
to make sure that when Django initializes an instance of our model and assigns
|
make sure that when Django initializes an instance of our model and assigns a
|
||||||
a database value to our custom field attribute, we convert that value into the
|
database value to our custom field attribute, we convert that value into the
|
||||||
appropriate Python object. The details of how this happens internally are a
|
appropriate Python object. The details of how this happens internally are a
|
||||||
little complex, but the code you need to write in your ``Field`` class is
|
little complex, but the code you need to write in your ``Field`` class is
|
||||||
simple: make sure your field subclass uses ``django.db.models.SubfieldBase`` as
|
simple: make sure your field subclass uses a special metaclass:
|
||||||
its metaclass::
|
|
||||||
|
.. class:: django.db.models.SubfieldBase
|
||||||
|
|
||||||
|
For example::
|
||||||
|
|
||||||
class HandField(models.Field):
|
class HandField(models.Field):
|
||||||
__metaclass__ = models.SubfieldBase
|
__metaclass__ = models.SubfieldBase
|
||||||
|
@ -240,27 +251,27 @@ its metaclass::
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
# ...
|
# ...
|
||||||
|
|
||||||
This ensures that the ``to_python()`` method, documented below_, will always be
|
This ensures that the :meth:`to_python` method, documented below, will always be
|
||||||
called when the attribute is initialized.
|
called when the attribute is initialized.
|
||||||
|
|
||||||
.. _below: #to-python-self-value
|
|
||||||
|
|
||||||
Useful methods
|
Useful methods
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
Once you've created your ``Field`` subclass and set up up the
|
Once you've created your :class:`~django.db.models.Field` subclass and set up up
|
||||||
``__metaclass__``, you might consider overriding a few standard methods,
|
the ``__metaclass__``, you might consider overriding a few standard methods,
|
||||||
depending on your field's behavior. The list of methods below is in
|
depending on your field's behavior. The list of methods below is in
|
||||||
approximately decreasing order of importance, so start from the top.
|
approximately decreasing order of importance, so start from the top.
|
||||||
|
|
||||||
``db_type(self)``
|
Custom database types
|
||||||
~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
Returns the database column data type for the ``Field``, taking into account
|
.. method:: db_type(self)
|
||||||
the current ``DATABASE_ENGINE`` setting.
|
|
||||||
|
Returns the database column data type for the :class:`~django.db.models.Field`,
|
||||||
|
taking into account the current :setting:`DATABASE_ENGINE` setting.
|
||||||
|
|
||||||
Say you've created a PostgreSQL custom type called ``mytype``. You can use this
|
Say you've created a PostgreSQL custom type called ``mytype``. You can use this
|
||||||
field with Django by subclassing ``Field`` and implementing the ``db_type()``
|
field with Django by subclassing ``Field`` and implementing the :meth:`db_type`
|
||||||
method, like so::
|
method, like so::
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
@ -281,7 +292,7 @@ If you aim to build a database-agnostic application, you should account for
|
||||||
differences in database column types. For example, the date/time column type
|
differences in database column types. For example, the date/time column type
|
||||||
in PostgreSQL is called ``timestamp``, while the same column in MySQL is called
|
in PostgreSQL is called ``timestamp``, while the same column in MySQL is called
|
||||||
``datetime``. The simplest way to handle this in a ``db_type()`` method is to
|
``datetime``. The simplest way to handle this in a ``db_type()`` method is to
|
||||||
import the Django settings module and check the ``DATABASE_ENGINE`` setting.
|
import the Django settings module and check the :setting:`DATABASE_ENGINE` setting.
|
||||||
For example::
|
For example::
|
||||||
|
|
||||||
class MyDateField(models.Field):
|
class MyDateField(models.Field):
|
||||||
|
@ -292,11 +303,11 @@ For example::
|
||||||
else:
|
else:
|
||||||
return 'timestamp'
|
return 'timestamp'
|
||||||
|
|
||||||
The ``db_type()`` method is only called by Django when the framework constructs
|
The :meth:`db_type` method is only called by Django when the framework
|
||||||
the ``CREATE TABLE`` statements for your application -- that is, when you first
|
constructs the ``CREATE TABLE`` statements for your application -- that is, when
|
||||||
create your tables. It's not called at any other time, so it can afford to
|
you first create your tables. It's not called at any other time, so it can
|
||||||
execute slightly complex code, such as the ``DATABASE_ENGINE`` check in the
|
afford to execute slightly complex code, such as the :setting:`DATABASE_ENGINE`
|
||||||
above example.
|
check in the above example.
|
||||||
|
|
||||||
Some database column types accept parameters, such as ``CHAR(25)``, where the
|
Some database column types accept parameters, such as ``CHAR(25)``, where the
|
||||||
parameter ``25`` represents the maximum column length. In cases like these,
|
parameter ``25`` represents the maximum column length. In cases like these,
|
||||||
|
@ -316,7 +327,7 @@ sense to have a ``CharMaxlength25Field``, shown here::
|
||||||
|
|
||||||
The better way of doing this would be to make the parameter specifiable at run
|
The better way of doing this would be to make the parameter specifiable at run
|
||||||
time -- i.e., when the class is instantiated. To do that, just implement
|
time -- i.e., when the class is instantiated. To do that, just implement
|
||||||
``__init__()``, like so::
|
:meth:`django.db.models.Field.__init__`, like so::
|
||||||
|
|
||||||
# This is a much more flexible example.
|
# This is a much more flexible example.
|
||||||
class BetterCharField(models.Field):
|
class BetterCharField(models.Field):
|
||||||
|
@ -333,13 +344,15 @@ time -- i.e., when the class is instantiated. To do that, just implement
|
||||||
my_field = BetterCharField(25)
|
my_field = BetterCharField(25)
|
||||||
|
|
||||||
Finally, if your column requires truly complex SQL setup, return ``None`` from
|
Finally, if your column requires truly complex SQL setup, return ``None`` from
|
||||||
``db_type()``. This will cause Django's SQL creation code to skip over this
|
:meth:`db_type`. This will cause Django's SQL creation code to skip over this
|
||||||
field. You are then responsible for creating the column in the right table in
|
field. You are then responsible for creating the column in the right table in
|
||||||
some other way, of course, but this gives you a way to tell Django to get out
|
some other way, of course, but this gives you a way to tell Django to get out of
|
||||||
of the way.
|
the way.
|
||||||
|
|
||||||
``to_python(self, value)``
|
Converting database values to Python objects
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. method:: to_python(self, value)
|
||||||
|
|
||||||
Converts a value as returned by your database (or a serializer) to a Python
|
Converts a value as returned by your database (or a serializer) to a Python
|
||||||
object.
|
object.
|
||||||
|
@ -348,10 +361,10 @@ The default implementation simply returns ``value``, for the common case in
|
||||||
which the database backend already returns data in the correct format (as a
|
which the database backend already returns data in the correct format (as a
|
||||||
Python string, for example).
|
Python string, for example).
|
||||||
|
|
||||||
If your custom ``Field`` class deals with data structures that are more complex
|
If your custom :class:`~django.db.models.Field` class deals with data structures
|
||||||
than strings, dates, integers or floats, then you'll need to override this
|
that are more complex than strings, dates, integers or floats, then you'll need
|
||||||
method. As a general rule, the method should deal gracefully with any of the
|
to override this method. As a general rule, the method should deal gracefully
|
||||||
following arguments:
|
with any of the following arguments:
|
||||||
|
|
||||||
* An instance of the correct type (e.g., ``Hand`` in our ongoing example).
|
* An instance of the correct type (e.g., ``Hand`` in our ongoing example).
|
||||||
|
|
||||||
|
@ -361,7 +374,7 @@ following arguments:
|
||||||
|
|
||||||
In our ``HandField`` class, we're storing the data as a VARCHAR field in the
|
In our ``HandField`` class, we're storing the data as a VARCHAR field in the
|
||||||
database, so we need to be able to process strings and ``Hand`` instances in
|
database, so we need to be able to process strings and ``Hand`` instances in
|
||||||
``to_python()``::
|
:meth:`to_python`::
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
@ -381,18 +394,20 @@ database, so we need to be able to process strings and ``Hand`` instances in
|
||||||
Notice that we always return a ``Hand`` instance from this method. That's the
|
Notice that we always return a ``Hand`` instance from this method. That's the
|
||||||
Python object type we want to store in the model's attribute.
|
Python object type we want to store in the model's attribute.
|
||||||
|
|
||||||
**Remember:** If your custom field needs the ``to_python()`` method to be
|
**Remember:** If your custom field needs the :meth:`to_python` method to be
|
||||||
called when it is created, you should be using `The SubfieldBase metaclass`_
|
called when it is created, you should be using `The SubfieldBase metaclass`_
|
||||||
mentioned earlier. Otherwise ``to_python()`` won't be called automatically.
|
mentioned earlier. Otherwise :meth:`to_python` won't be called automatically.
|
||||||
|
|
||||||
``get_db_prep_value(self, value)``
|
Converting Python objects to database values
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
This is the reverse of ``to_python()`` when working with the database backends
|
.. method:: get_db_prep_value(self, value)
|
||||||
|
|
||||||
|
This is the reverse of :meth:`to_python` when working with the database backends
|
||||||
(as opposed to serialization). The ``value`` parameter is the current value of
|
(as opposed to serialization). The ``value`` parameter is the current value of
|
||||||
the model's attribute (a field has no reference to its containing model, so it
|
the model's attribute (a field has no reference to its containing model, so it
|
||||||
cannot retrieve the value itself), and the method should return data in a
|
cannot retrieve the value itself), and the method should return data in a format
|
||||||
format that can be used as a parameter in a query for the database backend.
|
that can be used as a parameter in a query for the database backend.
|
||||||
|
|
||||||
For example::
|
For example::
|
||||||
|
|
||||||
|
@ -403,8 +418,7 @@ For example::
|
||||||
return ''.join([''.join(l) for l in (value.north,
|
return ''.join([''.join(l) for l in (value.north,
|
||||||
value.east, value.south, value.west)])
|
value.east, value.south, value.west)])
|
||||||
|
|
||||||
``get_db_prep_save(self, value)``
|
.. method:: get_db_prep_save(self, value)
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Same as the above, but called when the Field value must be *saved* to the
|
Same as the above, but called when the Field value must be *saved* to the
|
||||||
database. As the default implementation just calls ``get_db_prep_value``, you
|
database. As the default implementation just calls ``get_db_prep_value``, you
|
||||||
|
@ -412,28 +426,33 @@ shouldn't need to implement this method unless your custom field need a special
|
||||||
conversion when being saved that is not the same as the used for normal query
|
conversion when being saved that is not the same as the used for normal query
|
||||||
parameters (which is implemented by ``get_db_prep_value``).
|
parameters (which is implemented by ``get_db_prep_value``).
|
||||||
|
|
||||||
|
Preprocessing values before saving
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
``pre_save(self, model_instance, add)``
|
.. method:: pre_save(self, model_instance, add)
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
This method is called just prior to ``get_db_prep_save()`` and should return
|
This method is called just prior to :meth:`get_db_prep_save` and should return
|
||||||
the value of the appropriate attribute from ``model_instance`` for this field.
|
the value of the appropriate attribute from ``model_instance`` for this field.
|
||||||
The attribute name is in ``self.attname`` (this is set up by ``Field``). If
|
The attribute name is in ``self.attname`` (this is set up by
|
||||||
the model is being saved to the database for the first time, the ``add``
|
:class:`~django.db.models.Field`). If the model is being saved to the database
|
||||||
parameter will be ``True``, otherwise it will be ``False``.
|
for the first time, the ``add`` parameter will be ``True``, otherwise it will be
|
||||||
|
``False``.
|
||||||
|
|
||||||
You only need to override this method if you want to preprocess the value
|
You only need to override this method if you want to preprocess the value
|
||||||
somehow, just before saving. For example, Django's ``DateTimeField`` uses this
|
somehow, just before saving. For example, Django's
|
||||||
method to set the attribute correctly in the case of ``auto_now`` or
|
`:class:`~django.db.models.DateTimeField` uses this method to set the attribute
|
||||||
``auto_now_add``.
|
correctly in the case of :attr:`~django.db.models.Field.auto_now` or
|
||||||
|
:attr:`~django.db.models.Field.auto_now_add`.
|
||||||
|
|
||||||
If you do override this method, you must return the value of the attribute at
|
If you do override this method, you must return the value of the attribute at
|
||||||
the end. You should also update the model's attribute if you make any changes
|
the end. You should also update the model's attribute if you make any changes
|
||||||
to the value so that code holding references to the model will always see the
|
to the value so that code holding references to the model will always see the
|
||||||
correct value.
|
correct value.
|
||||||
|
|
||||||
``get_db_prep_lookup(self, lookup_type, value)``
|
Preparing values for use in database lookups
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. method:: get_db_prep_lookup(self, lookup_type, value)
|
||||||
|
|
||||||
Prepares the ``value`` for passing to the database when used in a lookup (a
|
Prepares the ``value`` for passing to the database when used in a lookup (a
|
||||||
``WHERE`` constraint in SQL). The ``lookup_type`` will be one of the valid
|
``WHERE`` constraint in SQL). The ``lookup_type`` will be one of the valid
|
||||||
|
@ -447,7 +466,7 @@ should raise either a ``ValueError`` if the ``value`` is of the wrong sort (a
|
||||||
list when you were expecting an object, for example) or a ``TypeError`` if
|
list when you were expecting an object, for example) or a ``TypeError`` if
|
||||||
your field does not support that type of lookup. For many fields, you can get
|
your field does not support that type of lookup. For many fields, you can get
|
||||||
by with handling the lookup types that need special handling for your field
|
by with handling the lookup types that need special handling for your field
|
||||||
and pass the rest of the ``get_db_prep_lookup()`` method of the parent class.
|
and pass the rest of the :meth:`get_db_prep_lookup` method of the parent class.
|
||||||
|
|
||||||
If you needed to implement ``get_db_prep_save()``, you will usually need to
|
If you needed to implement ``get_db_prep_save()``, you will usually need to
|
||||||
implement ``get_db_prep_lookup()``. If you don't, ``get_db_prep_value`` will be
|
implement ``get_db_prep_lookup()``. If you don't, ``get_db_prep_value`` will be
|
||||||
|
@ -478,22 +497,23 @@ accepted lookup types to ``exact`` and ``in``::
|
||||||
else:
|
else:
|
||||||
raise TypeError('Lookup type %r not supported.' % lookup_type)
|
raise TypeError('Lookup type %r not supported.' % lookup_type)
|
||||||
|
|
||||||
|
Specifying the form field for a model field
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
``formfield(self, form_class=forms.CharField, **kwargs)``
|
.. method:: formfield(self, form_class=forms.CharField, **kwargs)
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Returns the default form field to use when this field is displayed
|
Returns the default form field to use when this field is displayed in a model.
|
||||||
in a model.
|
This method is called by the :class:`~django.forms.ModelForm` helper.
|
||||||
|
|
||||||
All of the ``kwargs`` dictionary is passed directly to the form field's
|
All of the ``kwargs`` dictionary is passed directly to the form field's
|
||||||
``__init__()`` method. Normally, all you need to do is set up a good default
|
:meth:`~django.forms.Field__init__` method. Normally, all you need to do is
|
||||||
for the ``form_class`` argument and then delegate further handling to the
|
set up a good default for the ``form_class`` argument and then delegate further
|
||||||
parent class. This might require you to write a custom form field (and even a
|
handling to the parent class. This might require you to write a custom form
|
||||||
form widget). See the `forms documentation`_ for information about this, and
|
field (and even a form widget). See the :ref:`forms documentation
|
||||||
take a look at the code in ``django.contrib.localflavor`` for some examples of
|
<topics-forms-index>` for information about this, and take a look at the code in
|
||||||
custom widgets.
|
:mod:`django.contrib.localflavor` for some examples of custom widgets.
|
||||||
|
|
||||||
Continuing our ongoing example, we can write the ``formfield()`` method as::
|
Continuing our ongoing example, we can write the :meth:`formfield` method as::
|
||||||
|
|
||||||
class HandField(models.Field):
|
class HandField(models.Field):
|
||||||
# ...
|
# ...
|
||||||
|
@ -512,15 +532,17 @@ fields.
|
||||||
.. _helper functions: ../forms/#generating-forms-for-models
|
.. _helper functions: ../forms/#generating-forms-for-models
|
||||||
.. _forms documentation: ../forms/
|
.. _forms documentation: ../forms/
|
||||||
|
|
||||||
``get_internal_type(self)``
|
Emulating built-in field types
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
Returns a string giving the name of the ``Field`` subclass we are emulating at
|
.. method:: get_internal_type(self)
|
||||||
the database level. This is used to determine the type of database column for
|
|
||||||
simple cases.
|
|
||||||
|
|
||||||
If you have created a ``db_type()`` method, you don't need to worry about
|
Returns a string giving the name of the :class:`~django.db.models.Field`
|
||||||
``get_internal_type()`` -- it won't be used much. Sometimes, though, your
|
subclass we are emulating at the database level. This is used to determine the
|
||||||
|
type of database column for simple cases.
|
||||||
|
|
||||||
|
If you have created a :meth:`db_type` method, you don't need to worry about
|
||||||
|
:meth:`get_internal_type` -- it won't be used much. Sometimes, though, your
|
||||||
database storage is similar in type to some other field, so you can use that
|
database storage is similar in type to some other field, so you can use that
|
||||||
other field's logic to create the right column.
|
other field's logic to create the right column.
|
||||||
|
|
||||||
|
@ -535,35 +557,35 @@ For example::
|
||||||
No matter which database backend we are using, this will mean that ``syncdb``
|
No matter which database backend we are using, this will mean that ``syncdb``
|
||||||
and other SQL commands create the right column type for storing a string.
|
and other SQL commands create the right column type for storing a string.
|
||||||
|
|
||||||
If ``get_internal_type()`` returns a string that is not known to Django for
|
If :meth:`get_internal_type` returns a string that is not known to Django for
|
||||||
the database backend you are using -- that is, it doesn't appear in
|
the database backend you are using -- that is, it doesn't appear in
|
||||||
``django.db.backends.<db_name>.creation.DATA_TYPES`` -- the string will still
|
``django.db.backends.<db_name>.creation.DATA_TYPES`` -- the string will still be
|
||||||
be used by the serializer, but the default ``db_type()`` method will return
|
used by the serializer, but the default :meth:`db_type` method will return
|
||||||
``None``. See the documentation of ``db_type()`` above_ for reasons why this
|
``None``. See the documentation of :meth:`db_type` for reasons why this might be
|
||||||
might be useful. Putting a descriptive string in as the type of the field for
|
useful. Putting a descriptive string in as the type of the field for the
|
||||||
the serializer is a useful idea if you're ever going to be using the
|
serializer is a useful idea if you're ever going to be using the serializer
|
||||||
serializer output in some other place, outside of Django.
|
output in some other place, outside of Django.
|
||||||
|
|
||||||
.. _above: #db-type-self
|
Converting field data for serialization
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
``flatten_data(self, follow, obj=None)``
|
.. method:: flatten_data(self, follow, obj=None)
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
.. admonition:: Subject to change
|
.. admonition:: Subject to change
|
||||||
|
|
||||||
Although implementing this method is necessary to allow field
|
Although implementing this method is necessary to allow field
|
||||||
serialization, the API might change in the future.
|
serialization, the API might change in the future.
|
||||||
|
|
||||||
Returns a dictionary, mapping the field's attribute name to a
|
Returns a dictionary, mapping the field's attribute name to a flattened string
|
||||||
flattened string version of the data. This method has some internal
|
version of the data. This method has some internal uses that aren't of interest
|
||||||
uses that aren't of interest to use here (mostly having to do with
|
to use here (mostly having to do with forms). For our purposes, it's sufficient
|
||||||
forms). For our purposes, it's sufficient to return a one item
|
to return a one item dictionary that maps the attribute name to a string.
|
||||||
dictionary that maps the attribute name to a string.
|
|
||||||
|
|
||||||
This method is used by the serializers to convert the field into a string for
|
This method is used by the serializers to convert the field into a string for
|
||||||
output. You can ignore the input parameters for serialization purposes,
|
output. You can ignore the input parameters for serialization purposes, although
|
||||||
although calling ``Field._get_val_from_obj(obj)`` is the best way to get the
|
calling :meth:`Field._get_val_from_obj(obj)
|
||||||
value to serialize.
|
<django.db.models.Field._get_val_from_obj>` is the best way to get the value to
|
||||||
|
serialize.
|
||||||
|
|
||||||
For example, since our ``HandField`` uses strings for its data storage anyway,
|
For example, since our ``HandField`` uses strings for its data storage anyway,
|
||||||
we can reuse some existing conversion code::
|
we can reuse some existing conversion code::
|
||||||
|
@ -584,17 +606,19 @@ serialization formats. Here are a couple of tips to make things go more
|
||||||
smoothly:
|
smoothly:
|
||||||
|
|
||||||
1. Look at the existing Django fields (in
|
1. Look at the existing Django fields (in
|
||||||
``django/db/models/fields/__init__.py``) for inspiration. Try to find a
|
:file:`django/db/models/fields/__init__.py`) for inspiration. Try to find
|
||||||
field that's similar to what you want and extend it a little bit,
|
a field that's similar to what you want and extend it a little bit,
|
||||||
instead of creating an entirely new field from scratch.
|
instead of creating an entirely new field from scratch.
|
||||||
|
|
||||||
2. Put a ``__str__()`` or ``__unicode__()`` method on the class you're
|
2. Put a :meth:`__str__` or :meth:`__unicode__` method on the class you're
|
||||||
wrapping up as a field. There are a lot of places where the default
|
wrapping up as a field. There are a lot of places where the default
|
||||||
behavior of the field code is to call ``force_unicode()`` on the value.
|
behavior of the field code is to call
|
||||||
(In our examples in this document, ``value`` would be a ``Hand``
|
:func:`~django.utils.encoding.force_unicode` on the value. (In our
|
||||||
instance, not a ``HandField``). So if your ``__unicode__()`` method
|
examples in this document, ``value`` would be a ``Hand`` instance, not a
|
||||||
automatically converts to the string form of your Python object, you can
|
``HandField``). So if your :meth:`__unicode__` method automatically
|
||||||
save yourself a lot of work.
|
converts to the string form of your Python object, you can save yourself
|
||||||
|
a lot of work.
|
||||||
|
|
||||||
|
|
||||||
Writing a ``FileField`` subclass
|
Writing a ``FileField`` subclass
|
||||||
=================================
|
=================================
|
||||||
|
@ -606,17 +630,15 @@ retrieval, can remain unchanged, leaving subclasses to deal with the challenge
|
||||||
of supporting a particular type of file.
|
of supporting a particular type of file.
|
||||||
|
|
||||||
Django provides a ``File`` class, which is used as a proxy to the file's
|
Django provides a ``File`` class, which is used as a proxy to the file's
|
||||||
contents and operations. This can be subclassed to customzie hwo the file is
|
contents and operations. This can be subclassed to customize how the file is
|
||||||
accessed, and what methods are available. It lives at
|
accessed, and what methods are available. It lives at
|
||||||
``django.db.models.fields.files``, and its default behavior is explained in the
|
``django.db.models.fields.files``, and its default behavior is explained in the
|
||||||
`file documentation`_.
|
:ref:`file documentation <ref-files-file>`.
|
||||||
|
|
||||||
Once a subclass of ``File`` is created, the new ``FileField`` subclass must be
|
Once a subclass of ``File`` is created, the new ``FileField`` subclass must be
|
||||||
told to use it. To do so, simply assign the new ``File`` subclass to the special
|
told to use it. To do so, simply assign the new ``File`` subclass to the special
|
||||||
``attr_class`` attribute of the ``FileField`` subclass.
|
``attr_class`` attribute of the ``FileField`` subclass.
|
||||||
|
|
||||||
.. _file documentation: ../files/
|
|
||||||
|
|
||||||
A few suggestions
|
A few suggestions
|
||||||
------------------
|
------------------
|
||||||
|
|
|
@ -1,634 +1,61 @@
|
||||||
====================================================
|
.. _howto-custom-template-tags:
|
||||||
The Django template language: For Python programmers
|
|
||||||
====================================================
|
|
||||||
|
|
||||||
This document explains the Django template system from a technical
|
================================
|
||||||
perspective -- how it works and how to extend it. If you're just looking for
|
Custom template tags and filters
|
||||||
reference on the language syntax, see
|
================================
|
||||||
`The Django template language: For template authors`_.
|
|
||||||
|
|
||||||
If you're looking to use the Django template system as part of another
|
Introduction
|
||||||
application -- i.e., without the rest of the framework -- make sure to read
|
============
|
||||||
the `configuration`_ section later in this document.
|
|
||||||
|
|
||||||
.. _`The Django template language: For template authors`: ../templates/
|
Django's template system comes a wide variety of :ref:`built-in tags and filters
|
||||||
|
<ref-templates-builtins>` designed to address the presentation logic needs of
|
||||||
|
your application. Nevertheless, you may find yourself needing functionality that
|
||||||
|
is not covered by the core set of template primitives. You can extend the
|
||||||
|
template engine by defining custom tags and filters using Python, and then make
|
||||||
|
them available to your templates using the ``{% load %}`` tag.
|
||||||
|
|
||||||
Basics
|
Code layout
|
||||||
======
|
-----------
|
||||||
|
|
||||||
A **template** is a text document, or a normal Python string, that is marked-up
|
Custom template tags and filters must live inside a Django app. If they relate
|
||||||
using the Django template language. A template can contain **block tags** or
|
to an existing app it makes sense to bundle them there; otherwise, you should
|
||||||
**variables**.
|
create a new app to hold them.
|
||||||
|
|
||||||
A **block tag** is a symbol within a template that does something.
|
The app should contain a ``templatetags`` directory, at the same level as
|
||||||
|
``models.py``, ``views.py``, etc. If this doesn't already exist, create it -
|
||||||
|
don't forget the ``__init__.py`` file to ensure the directory is treated as a
|
||||||
|
Python package.
|
||||||
|
|
||||||
This definition is deliberately vague. For example, a block tag can output
|
Your custom tags and filters will live in a module inside the ``templatetags``
|
||||||
content, serve as a control structure (an "if" statement or "for" loop), grab
|
directory. The name of the module file is the name you'll use to load the tags
|
||||||
content from a database or enable access to other template tags.
|
later, so be careful to pick a name that won't clash with custom tags and
|
||||||
|
filters in another app.
|
||||||
|
|
||||||
Block tags are surrounded by ``"{%"`` and ``"%}"``.
|
For example, if your custom tags/filters are in a file called
|
||||||
|
``poll_extras.py``, your app layout might look like this::
|
||||||
Example template with block tags::
|
|
||||||
|
|
||||||
{% if is_logged_in %}Thanks for logging in!{% else %}Please log in.{% endif %}
|
|
||||||
|
|
||||||
A **variable** is a symbol within a template that outputs a value.
|
|
||||||
|
|
||||||
Variable tags are surrounded by ``"{{"`` and ``"}}"``.
|
|
||||||
|
|
||||||
Example template with variables::
|
|
||||||
|
|
||||||
My first name is {{ first_name }}. My last name is {{ last_name }}.
|
|
||||||
|
|
||||||
A **context** is a "variable name" -> "variable value" mapping that is passed
|
|
||||||
to a template.
|
|
||||||
|
|
||||||
A template **renders** a context by replacing the variable "holes" with values
|
|
||||||
from the context and executing all block tags.
|
|
||||||
|
|
||||||
Using the template system
|
|
||||||
=========================
|
|
||||||
|
|
||||||
Using the template system in Python is a two-step process:
|
|
||||||
|
|
||||||
* First, you compile the raw template code into a ``Template`` object.
|
|
||||||
* Then, you call the ``render()`` method of the ``Template`` object with a
|
|
||||||
given context.
|
|
||||||
|
|
||||||
Compiling a string
|
|
||||||
------------------
|
|
||||||
|
|
||||||
The easiest way to create a ``Template`` object is by instantiating it
|
|
||||||
directly. The class lives at ``django.template.Template``. The constructor
|
|
||||||
takes one argument -- the raw template code::
|
|
||||||
|
|
||||||
>>> from django.template import Template
|
|
||||||
>>> t = Template("My name is {{ my_name }}.")
|
|
||||||
>>> print t
|
|
||||||
<django.template.Template instance>
|
|
||||||
|
|
||||||
.. admonition:: Behind the scenes
|
|
||||||
|
|
||||||
The system only parses your raw template code once -- when you create the
|
|
||||||
``Template`` object. From then on, it's stored internally as a "node"
|
|
||||||
structure for performance.
|
|
||||||
|
|
||||||
Even the parsing itself is quite fast. Most of the parsing happens via a
|
|
||||||
single call to a single, short, regular expression.
|
|
||||||
|
|
||||||
Rendering a context
|
|
||||||
-------------------
|
|
||||||
|
|
||||||
Once you have a compiled ``Template`` object, you can render a context -- or
|
|
||||||
multiple contexts -- with it. The ``Context`` class lives at
|
|
||||||
``django.template.Context``, and the constructor takes one (optional)
|
|
||||||
argument: a dictionary mapping variable names to variable values. Call the
|
|
||||||
``Template`` object's ``render()`` method with the context to "fill" the
|
|
||||||
template::
|
|
||||||
|
|
||||||
>>> from django.template import Context, Template
|
|
||||||
>>> t = Template("My name is {{ my_name }}.")
|
|
||||||
|
|
||||||
>>> c = Context({"my_name": "Adrian"})
|
|
||||||
>>> t.render(c)
|
|
||||||
"My name is Adrian."
|
|
||||||
|
|
||||||
>>> c = Context({"my_name": "Dolores"})
|
|
||||||
>>> t.render(c)
|
|
||||||
"My name is Dolores."
|
|
||||||
|
|
||||||
Variable names must consist of any letter (A-Z), any digit (0-9), an underscore
|
|
||||||
or a dot.
|
|
||||||
|
|
||||||
Dots have a special meaning in template rendering. A dot in a variable name
|
|
||||||
signifies **lookup**. Specifically, when the template system encounters a dot
|
|
||||||
in a variable name, it tries the following lookups, in this order:
|
|
||||||
|
|
||||||
* Dictionary lookup. Example: ``foo["bar"]``
|
|
||||||
* Attribute lookup. Example: ``foo.bar``
|
|
||||||
* Method call. Example: ``foo.bar()``
|
|
||||||
* List-index lookup. Example: ``foo[bar]``
|
|
||||||
|
|
||||||
The template system uses the first lookup type that works. It's short-circuit
|
|
||||||
logic.
|
|
||||||
|
|
||||||
Here are a few examples::
|
|
||||||
|
|
||||||
>>> from django.template import Context, Template
|
|
||||||
>>> t = Template("My name is {{ person.first_name }}.")
|
|
||||||
>>> d = {"person": {"first_name": "Joe", "last_name": "Johnson"}}
|
|
||||||
>>> t.render(Context(d))
|
|
||||||
"My name is Joe."
|
|
||||||
|
|
||||||
>>> class PersonClass: pass
|
|
||||||
>>> p = PersonClass()
|
|
||||||
>>> p.first_name = "Ron"
|
|
||||||
>>> p.last_name = "Nasty"
|
|
||||||
>>> t.render(Context({"person": p}))
|
|
||||||
"My name is Ron."
|
|
||||||
|
|
||||||
>>> class PersonClass2:
|
|
||||||
... def first_name(self):
|
|
||||||
... return "Samantha"
|
|
||||||
>>> p = PersonClass2()
|
|
||||||
>>> t.render(Context({"person": p}))
|
|
||||||
"My name is Samantha."
|
|
||||||
|
|
||||||
>>> t = Template("The first stooge in the list is {{ stooges.0 }}.")
|
|
||||||
>>> c = Context({"stooges": ["Larry", "Curly", "Moe"]})
|
|
||||||
>>> t.render(c)
|
|
||||||
"The first stooge in the list is Larry."
|
|
||||||
|
|
||||||
Method lookups are slightly more complex than the other lookup types. Here are
|
|
||||||
some things to keep in mind:
|
|
||||||
|
|
||||||
* If, during the method lookup, a method raises an exception, the exception
|
|
||||||
will be propagated, unless the exception has an attribute
|
|
||||||
``silent_variable_failure`` whose value is ``True``. If the exception
|
|
||||||
*does* have a ``silent_variable_failure`` attribute, the variable will
|
|
||||||
render as an empty string. Example::
|
|
||||||
|
|
||||||
>>> t = Template("My name is {{ person.first_name }}.")
|
|
||||||
>>> class PersonClass3:
|
|
||||||
... def first_name(self):
|
|
||||||
... raise AssertionError, "foo"
|
|
||||||
>>> p = PersonClass3()
|
|
||||||
>>> t.render(Context({"person": p}))
|
|
||||||
Traceback (most recent call last):
|
|
||||||
...
|
|
||||||
AssertionError: foo
|
|
||||||
|
|
||||||
>>> class SilentAssertionError(Exception):
|
|
||||||
... silent_variable_failure = True
|
|
||||||
>>> class PersonClass4:
|
|
||||||
... def first_name(self):
|
|
||||||
... raise SilentAssertionError
|
|
||||||
>>> p = PersonClass4()
|
|
||||||
>>> t.render(Context({"person": p}))
|
|
||||||
"My name is ."
|
|
||||||
|
|
||||||
Note that ``django.core.exceptions.ObjectDoesNotExist``, which is the
|
|
||||||
base class for all Django database API ``DoesNotExist`` exceptions, has
|
|
||||||
``silent_variable_failure = True``. So if you're using Django templates
|
|
||||||
with Django model objects, any ``DoesNotExist`` exception will fail
|
|
||||||
silently.
|
|
||||||
|
|
||||||
* A method call will only work if the method has no required arguments.
|
|
||||||
Otherwise, the system will move to the next lookup type (list-index
|
|
||||||
lookup).
|
|
||||||
|
|
||||||
* Obviously, some methods have side effects, and it'd be either foolish or
|
|
||||||
a security hole to allow the template system to access them.
|
|
||||||
|
|
||||||
A good example is the ``delete()`` method on each Django model object.
|
|
||||||
The template system shouldn't be allowed to do something like this::
|
|
||||||
|
|
||||||
I will now delete this valuable data. {{ data.delete }}
|
|
||||||
|
|
||||||
To prevent this, set a function attribute ``alters_data`` on the method.
|
|
||||||
The template system won't execute a method if the method has
|
|
||||||
``alters_data=True`` set. The dynamically-generated ``delete()`` and
|
|
||||||
``save()`` methods on Django model objects get ``alters_data=True``
|
|
||||||
automatically. Example::
|
|
||||||
|
|
||||||
def sensitive_function(self):
|
|
||||||
self.database_record.delete()
|
|
||||||
sensitive_function.alters_data = True
|
|
||||||
|
|
||||||
How invalid variables are handled
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Generally, if a variable doesn't exist, the template system inserts the
|
|
||||||
value of the ``TEMPLATE_STRING_IF_INVALID`` setting, which is set to ``''``
|
|
||||||
(the empty string) by default.
|
|
||||||
|
|
||||||
Filters that are applied to an invalid variable will only be applied if
|
|
||||||
``TEMPLATE_STRING_IF_INVALID`` is set to ``''`` (the empty string). If
|
|
||||||
``TEMPLATE_STRING_IF_INVALID`` is set to any other value, variable
|
|
||||||
filters will be ignored.
|
|
||||||
|
|
||||||
This behavior is slightly different for the ``if``, ``for`` and ``regroup``
|
|
||||||
template tags. If an invalid variable is provided to one of these template
|
|
||||||
tags, the variable will be interpreted as ``None``. Filters are always
|
|
||||||
applied to invalid variables within these template tags.
|
|
||||||
|
|
||||||
If ``TEMPLATE_STRING_IF_INVALID`` contains a ``'%s'``, the format marker will
|
|
||||||
be replaced with the name of the invalid variable.
|
|
||||||
|
|
||||||
.. admonition:: For debug purposes only!
|
|
||||||
|
|
||||||
While ``TEMPLATE_STRING_IF_INVALID`` can be a useful debugging tool,
|
|
||||||
it is a bad idea to turn it on as a 'development default'.
|
|
||||||
|
|
||||||
Many templates, including those in the Admin site, rely upon the
|
|
||||||
silence of the template system when a non-existent variable is
|
|
||||||
encountered. If you assign a value other than ``''`` to
|
|
||||||
``TEMPLATE_STRING_IF_INVALID``, you will experience rendering
|
|
||||||
problems with these templates and sites.
|
|
||||||
|
|
||||||
Generally, ``TEMPLATE_STRING_IF_INVALID`` should only be enabled
|
|
||||||
in order to debug a specific template problem, then cleared
|
|
||||||
once debugging is complete.
|
|
||||||
|
|
||||||
Playing with Context objects
|
|
||||||
----------------------------
|
|
||||||
|
|
||||||
Most of the time, you'll instantiate ``Context`` objects by passing in a
|
|
||||||
fully-populated dictionary to ``Context()``. But you can add and delete items
|
|
||||||
from a ``Context`` object once it's been instantiated, too, using standard
|
|
||||||
dictionary syntax::
|
|
||||||
|
|
||||||
>>> c = Context({"foo": "bar"})
|
|
||||||
>>> c['foo']
|
|
||||||
'bar'
|
|
||||||
>>> del c['foo']
|
|
||||||
>>> c['foo']
|
|
||||||
''
|
|
||||||
>>> c['newvariable'] = 'hello'
|
|
||||||
>>> c['newvariable']
|
|
||||||
'hello'
|
|
||||||
|
|
||||||
A ``Context`` object is a stack. That is, you can ``push()`` and ``pop()`` it.
|
|
||||||
If you ``pop()`` too much, it'll raise
|
|
||||||
``django.template.ContextPopException``::
|
|
||||||
|
|
||||||
>>> c = Context()
|
|
||||||
>>> c['foo'] = 'first level'
|
|
||||||
>>> c.push()
|
|
||||||
>>> c['foo'] = 'second level'
|
|
||||||
>>> c['foo']
|
|
||||||
'second level'
|
|
||||||
>>> c.pop()
|
|
||||||
>>> c['foo']
|
|
||||||
'first level'
|
|
||||||
>>> c['foo'] = 'overwritten'
|
|
||||||
>>> c['foo']
|
|
||||||
'overwritten'
|
|
||||||
>>> c.pop()
|
|
||||||
Traceback (most recent call last):
|
|
||||||
...
|
|
||||||
django.template.ContextPopException
|
|
||||||
|
|
||||||
Using a ``Context`` as a stack comes in handy in some custom template tags, as
|
|
||||||
you'll see below.
|
|
||||||
|
|
||||||
Subclassing Context: RequestContext
|
|
||||||
-----------------------------------
|
|
||||||
|
|
||||||
Django comes with a special ``Context`` class,
|
|
||||||
``django.template.RequestContext``, that acts slightly differently than
|
|
||||||
the normal ``django.template.Context``. The first difference is that it takes
|
|
||||||
an `HttpRequest object`_ as its first argument. For example::
|
|
||||||
|
|
||||||
c = RequestContext(request, {
|
|
||||||
'foo': 'bar',
|
|
||||||
}
|
|
||||||
|
|
||||||
The second difference is that it automatically populates the context with a few
|
|
||||||
variables, according to your `TEMPLATE_CONTEXT_PROCESSORS setting`_.
|
|
||||||
|
|
||||||
The ``TEMPLATE_CONTEXT_PROCESSORS`` setting is a tuple of callables -- called
|
|
||||||
**context processors** -- that take a request object as their argument and
|
|
||||||
return a dictionary of items to be merged into the context. By default,
|
|
||||||
``TEMPLATE_CONTEXT_PROCESSORS`` is set to::
|
|
||||||
|
|
||||||
("django.core.context_processors.auth",
|
|
||||||
"django.core.context_processors.debug",
|
|
||||||
"django.core.context_processors.i18n",
|
|
||||||
"django.core.context_processors.media")
|
|
||||||
|
|
||||||
Each processor is applied in order. That means, if one processor adds a
|
|
||||||
variable to the context and a second processor adds a variable with the same
|
|
||||||
name, the second will override the first. The default processors are explained
|
|
||||||
below.
|
|
||||||
|
|
||||||
Also, you can give ``RequestContext`` a list of additional processors, using the
|
|
||||||
optional, third positional argument, ``processors``. In this example, the
|
|
||||||
``RequestContext`` instance gets a ``ip_address`` variable::
|
|
||||||
|
|
||||||
def ip_address_processor(request):
|
|
||||||
return {'ip_address': request.META['REMOTE_ADDR']}
|
|
||||||
|
|
||||||
def some_view(request):
|
|
||||||
# ...
|
|
||||||
c = RequestContext(request, {
|
|
||||||
'foo': 'bar',
|
|
||||||
}, [ip_address_processor])
|
|
||||||
return t.render(c)
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
If you're using Django's ``render_to_response()`` shortcut to populate a
|
|
||||||
template with the contents of a dictionary, your template will be passed a
|
|
||||||
``Context`` instance by default (not a ``RequestContext``). To use a
|
|
||||||
``RequestContext`` in your template rendering, pass an optional third
|
|
||||||
argument to ``render_to_response()``: a ``RequestContext``
|
|
||||||
instance. Your code might look like this::
|
|
||||||
|
|
||||||
def some_view(request):
|
|
||||||
# ...
|
|
||||||
return render_to_response('my_template.html',
|
|
||||||
my_data_dictionary,
|
|
||||||
context_instance=RequestContext(request))
|
|
||||||
|
|
||||||
Here's what each of the default processors does:
|
|
||||||
|
|
||||||
.. _HttpRequest object: ../request_response/#httprequest-objects
|
|
||||||
.. _TEMPLATE_CONTEXT_PROCESSORS setting: ../settings/#template-context-processors
|
|
||||||
|
|
||||||
django.core.context_processors.auth
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
If ``TEMPLATE_CONTEXT_PROCESSORS`` contains this processor, every
|
|
||||||
``RequestContext`` will contain these three variables:
|
|
||||||
|
|
||||||
* ``user`` -- An ``auth.User`` instance representing the currently
|
|
||||||
logged-in user (or an ``AnonymousUser`` instance, if the client isn't
|
|
||||||
logged in). See the `user authentication docs`_.
|
|
||||||
|
|
||||||
* ``messages`` -- A list of messages (as strings) for the currently
|
|
||||||
logged-in user. Behind the scenes, this calls
|
|
||||||
``request.user.get_and_delete_messages()`` for every request. That method
|
|
||||||
collects the user's messages and deletes them from the database.
|
|
||||||
|
|
||||||
Note that messages are set with ``user.message_set.create``. See the
|
|
||||||
`message docs`_ for more.
|
|
||||||
|
|
||||||
* ``perms`` -- An instance of
|
|
||||||
``django.core.context_processors.PermWrapper``, representing the
|
|
||||||
permissions that the currently logged-in user has. See the `permissions
|
|
||||||
docs`_.
|
|
||||||
|
|
||||||
.. _user authentication docs: ../authentication/#users
|
|
||||||
.. _message docs: ../authentication/#messages
|
|
||||||
.. _permissions docs: ../authentication/#permissions
|
|
||||||
|
|
||||||
django.core.context_processors.debug
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
If ``TEMPLATE_CONTEXT_PROCESSORS`` contains this processor, every
|
|
||||||
``RequestContext`` will contain these two variables -- but only if your
|
|
||||||
``DEBUG`` setting is set to ``True`` and the request's IP address
|
|
||||||
(``request.META['REMOTE_ADDR']``) is in the ``INTERNAL_IPS`` setting:
|
|
||||||
|
|
||||||
* ``debug`` -- ``True``. You can use this in templates to test whether
|
|
||||||
you're in ``DEBUG`` mode.
|
|
||||||
* ``sql_queries`` -- A list of ``{'sql': ..., 'time': ...}`` dictionaries,
|
|
||||||
representing every SQL query that has happened so far during the request
|
|
||||||
and how long it took. The list is in order by query.
|
|
||||||
|
|
||||||
django.core.context_processors.i18n
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
If ``TEMPLATE_CONTEXT_PROCESSORS`` contains this processor, every
|
|
||||||
``RequestContext`` will contain these two variables:
|
|
||||||
|
|
||||||
* ``LANGUAGES`` -- The value of the `LANGUAGES setting`_.
|
|
||||||
* ``LANGUAGE_CODE`` -- ``request.LANGUAGE_CODE``, if it exists. Otherwise,
|
|
||||||
the value of the `LANGUAGE_CODE setting`_.
|
|
||||||
|
|
||||||
See the `internationalization docs`_ for more.
|
|
||||||
|
|
||||||
.. _LANGUAGES setting: ../settings/#languages
|
|
||||||
.. _LANGUAGE_CODE setting: ../settings/#language-code
|
|
||||||
.. _internationalization docs: ../i18n/
|
|
||||||
|
|
||||||
django.core.context_processors.media
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
**New in Django development version**
|
|
||||||
|
|
||||||
If ``TEMPLATE_CONTEXT_PROCESSORS`` contains this processor, every
|
|
||||||
``RequestContext`` will contain a variable ``MEDIA_URL``, providing the
|
|
||||||
value of the `MEDIA_URL setting`_.
|
|
||||||
|
|
||||||
.. _MEDIA_URL setting: ../settings/#media-url
|
|
||||||
|
|
||||||
django.core.context_processors.request
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
If ``TEMPLATE_CONTEXT_PROCESSORS`` contains this processor, every
|
|
||||||
``RequestContext`` will contain a variable ``request``, which is the current
|
|
||||||
`HttpRequest object`_. Note that this processor is not enabled by default;
|
|
||||||
you'll have to activate it.
|
|
||||||
|
|
||||||
Writing your own context processors
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
A context processor has a very simple interface: It's just a Python function
|
|
||||||
that takes one argument, an ``HttpRequest`` object, and returns a dictionary
|
|
||||||
that gets added to the template context. Each context processor *must* return
|
|
||||||
a dictionary.
|
|
||||||
|
|
||||||
Custom context processors can live anywhere in your code base. All Django cares
|
|
||||||
about is that your custom context processors are pointed-to by your
|
|
||||||
``TEMPLATE_CONTEXT_PROCESSORS`` setting.
|
|
||||||
|
|
||||||
Loading templates
|
|
||||||
-----------------
|
|
||||||
|
|
||||||
Generally, you'll store templates in files on your filesystem rather than using
|
|
||||||
the low-level ``Template`` API yourself. Save templates in a directory
|
|
||||||
specified as a **template directory**.
|
|
||||||
|
|
||||||
Django searches for template directories in a number of places, depending on
|
|
||||||
your template-loader settings (see "Loader types" below), but the most basic
|
|
||||||
way of specifying template directories is by using the ``TEMPLATE_DIRS``
|
|
||||||
setting.
|
|
||||||
|
|
||||||
The TEMPLATE_DIRS setting
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Tell Django what your template directories are by using the ``TEMPLATE_DIRS``
|
|
||||||
setting in your settings file. This should be set to a list or tuple of strings
|
|
||||||
that contain full paths to your template directory(ies). Example::
|
|
||||||
|
|
||||||
TEMPLATE_DIRS = (
|
|
||||||
"/home/html/templates/lawrence.com",
|
|
||||||
"/home/html/templates/default",
|
|
||||||
)
|
|
||||||
|
|
||||||
Your templates can go anywhere you want, as long as the directories and
|
|
||||||
templates are readable by the Web server. They can have any extension you want,
|
|
||||||
such as ``.html`` or ``.txt``, or they can have no extension at all.
|
|
||||||
|
|
||||||
Note that these paths should use Unix-style forward slashes, even on Windows.
|
|
||||||
|
|
||||||
The Python API
|
|
||||||
~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Django has two ways to load templates from files:
|
|
||||||
|
|
||||||
``django.template.loader.get_template(template_name)``
|
|
||||||
``get_template`` returns the compiled template (a ``Template`` object) for
|
|
||||||
the template with the given name. If the template doesn't exist, it raises
|
|
||||||
``django.template.TemplateDoesNotExist``.
|
|
||||||
|
|
||||||
``django.template.loader.select_template(template_name_list)``
|
|
||||||
``select_template`` is just like ``get_template``, except it takes a list
|
|
||||||
of template names. Of the list, it returns the first template that exists.
|
|
||||||
|
|
||||||
For example, if you call ``get_template('story_detail.html')`` and have the
|
|
||||||
above ``TEMPLATE_DIRS`` setting, here are the files Django will look for, in
|
|
||||||
order:
|
|
||||||
|
|
||||||
* ``/home/html/templates/lawrence.com/story_detail.html``
|
|
||||||
* ``/home/html/templates/default/story_detail.html``
|
|
||||||
|
|
||||||
If you call ``select_template(['story_253_detail.html', 'story_detail.html'])``,
|
|
||||||
here's what Django will look for:
|
|
||||||
|
|
||||||
* ``/home/html/templates/lawrence.com/story_253_detail.html``
|
|
||||||
* ``/home/html/templates/default/story_253_detail.html``
|
|
||||||
* ``/home/html/templates/lawrence.com/story_detail.html``
|
|
||||||
* ``/home/html/templates/default/story_detail.html``
|
|
||||||
|
|
||||||
When Django finds a template that exists, it stops looking.
|
|
||||||
|
|
||||||
.. admonition:: Tip
|
|
||||||
|
|
||||||
You can use ``select_template()`` for super-flexible "templatability." For
|
|
||||||
example, if you've written a news story and want some stories to have
|
|
||||||
custom templates, use something like
|
|
||||||
``select_template(['story_%s_detail.html' % story.id, 'story_detail.html'])``.
|
|
||||||
That'll allow you to use a custom template for an individual story, with a
|
|
||||||
fallback template for stories that don't have custom templates.
|
|
||||||
|
|
||||||
Using subdirectories
|
|
||||||
~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
It's possible -- and preferable -- to organize templates in subdirectories of
|
|
||||||
the template directory. The convention is to make a subdirectory for each
|
|
||||||
Django app, with subdirectories within those subdirectories as needed.
|
|
||||||
|
|
||||||
Do this for your own sanity. Storing all templates in the root level of a
|
|
||||||
single directory gets messy.
|
|
||||||
|
|
||||||
To load a template that's within a subdirectory, just use a slash, like so::
|
|
||||||
|
|
||||||
get_template('news/story_detail.html')
|
|
||||||
|
|
||||||
Using the same ``TEMPLATE_DIRS`` setting from above, this example
|
|
||||||
``get_template()`` call will attempt to load the following templates:
|
|
||||||
|
|
||||||
* ``/home/html/templates/lawrence.com/news/story_detail.html``
|
|
||||||
* ``/home/html/templates/default/news/story_detail.html``
|
|
||||||
|
|
||||||
Loader types
|
|
||||||
~~~~~~~~~~~~
|
|
||||||
|
|
||||||
By default, Django uses a filesystem-based template loader, but Django comes
|
|
||||||
with a few other template loaders, which know how to load templates from other
|
|
||||||
sources.
|
|
||||||
|
|
||||||
These other loaders are disabled by default, but you can activate them by
|
|
||||||
editing your ``TEMPLATE_LOADERS`` setting. ``TEMPLATE_LOADERS`` should be a
|
|
||||||
tuple of strings, where each string represents a template loader. Here are the
|
|
||||||
template loaders that come with Django:
|
|
||||||
|
|
||||||
``django.template.loaders.filesystem.load_template_source``
|
|
||||||
Loads templates from the filesystem, according to ``TEMPLATE_DIRS``.
|
|
||||||
|
|
||||||
``django.template.loaders.app_directories.load_template_source``
|
|
||||||
Loads templates from Django apps on the filesystem. For each app in
|
|
||||||
``INSTALLED_APPS``, the loader looks for a ``templates`` subdirectory. If
|
|
||||||
the directory exists, Django looks for templates in there.
|
|
||||||
|
|
||||||
This means you can store templates with your individual apps. This also
|
|
||||||
makes it easy to distribute Django apps with default templates.
|
|
||||||
|
|
||||||
For example, for this setting::
|
|
||||||
|
|
||||||
INSTALLED_APPS = ('myproject.polls', 'myproject.music')
|
|
||||||
|
|
||||||
...then ``get_template('foo.html')`` will look for templates in these
|
|
||||||
directories, in this order:
|
|
||||||
|
|
||||||
* ``/path/to/myproject/polls/templates/foo.html``
|
|
||||||
* ``/path/to/myproject/music/templates/foo.html``
|
|
||||||
|
|
||||||
Note that the loader performs an optimization when it is first imported:
|
|
||||||
It caches a list of which ``INSTALLED_APPS`` packages have a ``templates``
|
|
||||||
subdirectory.
|
|
||||||
|
|
||||||
``django.template.loaders.eggs.load_template_source``
|
|
||||||
Just like ``app_directories`` above, but it loads templates from Python
|
|
||||||
eggs rather than from the filesystem.
|
|
||||||
|
|
||||||
Django uses the template loaders in order according to the ``TEMPLATE_LOADERS``
|
|
||||||
setting. It uses each loader until a loader finds a match.
|
|
||||||
|
|
||||||
The ``render_to_string()`` shortcut
|
|
||||||
===================================
|
|
||||||
|
|
||||||
To cut down on the repetitive nature of loading and rendering
|
|
||||||
templates, Django provides a shortcut function which largely
|
|
||||||
automates the process: ``render_to_string()`` in
|
|
||||||
``django.template.loader``, which loads a template, renders it and
|
|
||||||
returns the resulting string::
|
|
||||||
|
|
||||||
from django.template.loader import render_to_string
|
|
||||||
rendered = render_to_string('my_template.html', { 'foo': 'bar' })
|
|
||||||
|
|
||||||
The ``render_to_string`` shortcut takes one required argument --
|
|
||||||
``template_name``, which should be the name of the template to load
|
|
||||||
and render -- and two optional arguments::
|
|
||||||
|
|
||||||
dictionary
|
|
||||||
A dictionary to be used as variables and values for the
|
|
||||||
template's context. This can also be passed as the second
|
|
||||||
positional argument.
|
|
||||||
|
|
||||||
context_instance
|
|
||||||
An instance of ``Context`` or a subclass (e.g., an instance of
|
|
||||||
``RequestContext``) to use as the template's context. This can
|
|
||||||
also be passed as the third positional argument.
|
|
||||||
|
|
||||||
See also the `render_to_response()`_ shortcut, which calls
|
|
||||||
``render_to_string`` and feeds the result into an ``HttpResponse``
|
|
||||||
suitable for returning directly from a view.
|
|
||||||
|
|
||||||
.. _render_to_response(): ../shortcuts/#render-to-response
|
|
||||||
|
|
||||||
Extending the template system
|
|
||||||
=============================
|
|
||||||
|
|
||||||
Although the Django template language comes with several default tags and
|
|
||||||
filters, you might want to write your own. It's easy to do.
|
|
||||||
|
|
||||||
First, create a ``templatetags`` package in the appropriate Django app's
|
|
||||||
package. It should be on the same level as ``models.py``, ``views.py``, etc. For
|
|
||||||
example::
|
|
||||||
|
|
||||||
polls/
|
polls/
|
||||||
models.py
|
models.py
|
||||||
templatetags/
|
templatetags/
|
||||||
|
__init__.py
|
||||||
|
poll_extras.py
|
||||||
views.py
|
views.py
|
||||||
|
|
||||||
Add two files to the ``templatetags`` package: an ``__init__.py`` file and a
|
And in your template you would use the following:
|
||||||
file that will contain your custom tag/filter definitions. The name of the
|
|
||||||
latter file is the name you'll use to load the tags later. For example, if your
|
.. code-block:: html+django
|
||||||
custom tags/filters are in a file called ``poll_extras.py``, you'd do the
|
|
||||||
following in a template::
|
|
||||||
|
|
||||||
{% load poll_extras %}
|
{% load poll_extras %}
|
||||||
|
|
||||||
The ``{% load %}`` tag looks at your ``INSTALLED_APPS`` setting and only allows
|
The app that contains the custom tags must be in :setting:`INSTALLED_APPS` in
|
||||||
the loading of template libraries within installed Django apps. This is a
|
order for the ``{% load %}`` tag to work. This is a security feature: It allows
|
||||||
security feature: It allows you to host Python code for many template libraries
|
you to host Python code for many template libraries on a single host machine
|
||||||
on a single computer without enabling access to all of them for every Django
|
without enabling access to all of them for every Django installation.
|
||||||
installation.
|
|
||||||
|
|
||||||
If you write a template library that isn't tied to any particular models/views,
|
|
||||||
it's perfectly OK to have a Django app package that only contains a
|
|
||||||
``templatetags`` package.
|
|
||||||
|
|
||||||
There's no limit on how many modules you put in the ``templatetags`` package.
|
There's no limit on how many modules you put in the ``templatetags`` package.
|
||||||
Just keep in mind that a ``{% load %}`` statement will load tags/filters for
|
Just keep in mind that a ``{% load %}`` statement will load tags/filters for
|
||||||
the given Python module name, not the name of the app.
|
the given Python module name, not the name of the app.
|
||||||
|
|
||||||
Once you've created that Python module, you'll just have to write a bit of
|
|
||||||
Python code, depending on whether you're writing filters or tags.
|
|
||||||
|
|
||||||
To be a valid tag library, the module must contain a module-level variable
|
To be a valid tag library, the module must contain a module-level variable
|
||||||
named ``register`` that is a ``template.Library`` instance, in which all the
|
named ``register`` that is a ``template.Library`` instance, in which all the
|
||||||
tags and filters are registered. So, near the top of your module, put the
|
tags and filters are registered. So, near the top of your module, put the
|
||||||
|
@ -666,7 +93,9 @@ Here's an example filter definition::
|
||||||
"Removes all values of arg from the given string"
|
"Removes all values of arg from the given string"
|
||||||
return value.replace(arg, '')
|
return value.replace(arg, '')
|
||||||
|
|
||||||
And here's an example of how that filter would be used::
|
And here's an example of how that filter would be used:
|
||||||
|
|
||||||
|
.. code-block:: html+django
|
||||||
|
|
||||||
{{ somevariable|cut:"0" }}
|
{{ somevariable|cut:"0" }}
|
||||||
|
|
||||||
|
@ -818,7 +247,8 @@ Template filter code falls into one of two situations:
|
||||||
escaping so that your HTML markup isn't escaped further, so you'll need
|
escaping so that your HTML markup isn't escaped further, so you'll need
|
||||||
to handle the input yourself.
|
to handle the input yourself.
|
||||||
|
|
||||||
To mark the output as a safe string, use ``django.utils.safestring.mark_safe()``.
|
To mark the output as a safe string, use
|
||||||
|
:func:`django.utils.safestring.mark_safe`.
|
||||||
|
|
||||||
Be careful, though. You need to do more than just mark the output as
|
Be careful, though. You need to do more than just mark the output as
|
||||||
safe. You need to ensure it really *is* safe, and what you do depends on
|
safe. You need to ensure it really *is* safe, and what you do depends on
|
||||||
|
@ -852,9 +282,9 @@ Template filter code falls into one of two situations:
|
||||||
The ``needs_autoescape`` attribute on the filter function and the
|
The ``needs_autoescape`` attribute on the filter function and the
|
||||||
``autoescape`` keyword argument mean that our function will know whether
|
``autoescape`` keyword argument mean that our function will know whether
|
||||||
automatic escaping is in effect when the filter is called. We use
|
automatic escaping is in effect when the filter is called. We use
|
||||||
``autoescape`` to decide whether the input data needs to be passed through
|
``autoescape`` to decide whether the input data needs to be passed
|
||||||
``django.utils.html.conditional_escape`` or not. (In the latter case, we
|
through ``django.utils.html.conditional_escape`` or not. (In the latter
|
||||||
just use the identity function as the "escape" function.) The
|
case, we just use the identity function as the "escape" function.) The
|
||||||
``conditional_escape()`` function is like ``escape()`` except it only
|
``conditional_escape()`` function is like ``escape()`` except it only
|
||||||
escapes input that is **not** a ``SafeData`` instance. If a ``SafeData``
|
escapes input that is **not** a ``SafeData`` instance. If a ``SafeData``
|
||||||
instance is passed to ``conditional_escape()``, the data is returned
|
instance is passed to ``conditional_escape()``, the data is returned
|
||||||
|
@ -902,7 +332,9 @@ responsible for returning a ``Node`` instance based on the contents of the tag.
|
||||||
For example, let's write a template tag, ``{% current_time %}``, that displays
|
For example, let's write a template tag, ``{% current_time %}``, that displays
|
||||||
the current date/time, formatted according to a parameter given in the tag, in
|
the current date/time, formatted according to a parameter given in the tag, in
|
||||||
`strftime syntax`_. It's a good idea to decide the tag syntax before anything
|
`strftime syntax`_. It's a good idea to decide the tag syntax before anything
|
||||||
else. In our case, let's say the tag should be used like this::
|
else. In our case, let's say the tag should be used like this:
|
||||||
|
|
||||||
|
.. code-block:: html+django
|
||||||
|
|
||||||
<p>The time is {% current_time "%Y-%m-%d %I:%M %p" %}.</p>
|
<p>The time is {% current_time "%Y-%m-%d %I:%M %p" %}.</p>
|
||||||
|
|
||||||
|
@ -1064,7 +496,9 @@ content (a template variable) to a template tag as an argument.
|
||||||
|
|
||||||
While the previous examples have formatted the current time into a string and
|
While the previous examples have formatted the current time into a string and
|
||||||
returned the string, suppose you wanted to pass in a ``DateTimeField`` from an
|
returned the string, suppose you wanted to pass in a ``DateTimeField`` from an
|
||||||
object and have the template tag format that date-time::
|
object and have the template tag format that date-time:
|
||||||
|
|
||||||
|
.. code-block:: html+django
|
||||||
|
|
||||||
<p>This post was last updated at {% format_time blog_entry.date_updated "%Y-%m-%d %I:%M %p" %}.</p>
|
<p>This post was last updated at {% format_time blog_entry.date_updated "%Y-%m-%d %I:%M %p" %}.</p>
|
||||||
|
|
||||||
|
@ -1174,7 +608,7 @@ In Python 2.4, the decorator syntax also works::
|
||||||
|
|
||||||
A couple of things to note about the ``simple_tag`` helper function:
|
A couple of things to note about the ``simple_tag`` helper function:
|
||||||
|
|
||||||
* Checking for the required number of arguments, etc, has already been
|
* Checking for the required number of arguments, etc., has already been
|
||||||
done by the time our function is called, so we don't need to do that.
|
done by the time our function is called, so we don't need to do that.
|
||||||
* The quotes around the argument (if any) have already been stripped away,
|
* The quotes around the argument (if any) have already been stripped away,
|
||||||
so we just receive a plain string.
|
so we just receive a plain string.
|
||||||
|
@ -1200,11 +634,15 @@ These sorts of tags are called "inclusion tags".
|
||||||
|
|
||||||
Writing inclusion tags is probably best demonstrated by example. Let's write a
|
Writing inclusion tags is probably best demonstrated by example. Let's write a
|
||||||
tag that outputs a list of choices for a given ``Poll`` object, such as was
|
tag that outputs a list of choices for a given ``Poll`` object, such as was
|
||||||
created in the tutorials_. We'll use the tag like this::
|
created in the :ref:`tutorials <creating-models>`. We'll use the tag like this:
|
||||||
|
|
||||||
|
.. code-block:: html+django
|
||||||
|
|
||||||
{% show_results poll %}
|
{% show_results poll %}
|
||||||
|
|
||||||
...and the output will be something like this::
|
...and the output will be something like this:
|
||||||
|
|
||||||
|
.. code-block:: html
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<li>First choice</li>
|
<li>First choice</li>
|
||||||
|
@ -1223,7 +661,9 @@ for the template fragment. Example::
|
||||||
|
|
||||||
Next, create the template used to render the tag's output. This template is a
|
Next, create the template used to render the tag's output. This template is a
|
||||||
fixed feature of the tag: the tag writer specifies it, not the template
|
fixed feature of the tag: the tag writer specifies it, not the template
|
||||||
designer. Following our example, the template is very simple::
|
designer. Following our example, the template is very simple:
|
||||||
|
|
||||||
|
.. code-block:: html+django
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
{% for choice in choices %}
|
{% for choice in choices %}
|
||||||
|
@ -1272,13 +712,17 @@ back to the main page. Here's what the Python function would look like::
|
||||||
|
|
||||||
In that ``register.inclusion_tag()`` line, we specified ``takes_context=True``
|
In that ``register.inclusion_tag()`` line, we specified ``takes_context=True``
|
||||||
and the name of the template. Here's what the template ``link.html`` might look
|
and the name of the template. Here's what the template ``link.html`` might look
|
||||||
like::
|
like:
|
||||||
|
|
||||||
|
.. code-block:: html+django
|
||||||
|
|
||||||
Jump directly to <a href="{{ link }}">{{ title }}</a>.
|
Jump directly to <a href="{{ link }}">{{ title }}</a>.
|
||||||
|
|
||||||
Then, any time you want to use that custom tag, load its library and call it
|
Then, any time you want to use that custom tag, load its library and call it
|
||||||
without any arguments, like so::
|
without any arguments, like so::
|
||||||
|
|
||||||
|
.. code-block:: html+django
|
||||||
|
|
||||||
{% jump_link %}
|
{% jump_link %}
|
||||||
|
|
||||||
Note that when you're using ``takes_context=True``, there's no need to pass
|
Note that when you're using ``takes_context=True``, there's no need to pass
|
||||||
|
@ -1288,8 +732,6 @@ The ``takes_context`` parameter defaults to ``False``. When it's set to *True*,
|
||||||
the tag is passed the context object, as in this example. That's the only
|
the tag is passed the context object, as in this example. That's the only
|
||||||
difference between this case and the previous ``inclusion_tag`` example.
|
difference between this case and the previous ``inclusion_tag`` example.
|
||||||
|
|
||||||
.. _tutorials: ../tutorial01/#creating-models
|
|
||||||
|
|
||||||
Setting a variable in the context
|
Setting a variable in the context
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
@ -1313,7 +755,9 @@ Note that ``render()`` returns the empty string. ``render()`` should always
|
||||||
return string output. If all the template tag does is set a variable,
|
return string output. If all the template tag does is set a variable,
|
||||||
``render()`` should return the empty string.
|
``render()`` should return the empty string.
|
||||||
|
|
||||||
Here's how you'd use this new version of the tag::
|
Here's how you'd use this new version of the tag:
|
||||||
|
|
||||||
|
.. code-block:: html+django
|
||||||
|
|
||||||
{% current_time "%Y-%M-%d %I:%M %p" %}<p>The time is {{ current_time }}.</p>
|
{% current_time "%Y-%M-%d %I:%M %p" %}<p>The time is {{ current_time }}.</p>
|
||||||
|
|
||||||
|
@ -1322,7 +766,9 @@ But, there's a problem with ``CurrentTimeNode2``: The variable name
|
||||||
template doesn't use ``{{ current_time }}`` anywhere else, because the
|
template doesn't use ``{{ current_time }}`` anywhere else, because the
|
||||||
``{% current_time %}`` will blindly overwrite that variable's value. A cleaner
|
``{% current_time %}`` will blindly overwrite that variable's value. A cleaner
|
||||||
solution is to make the template tag specify the name of the output variable,
|
solution is to make the template tag specify the name of the output variable,
|
||||||
like so::
|
like so:
|
||||||
|
|
||||||
|
.. code-block:: html+django
|
||||||
|
|
||||||
{% get_current_time "%Y-%M-%d %I:%M %p" as my_current_time %}
|
{% get_current_time "%Y-%M-%d %I:%M %p" as my_current_time %}
|
||||||
<p>The current time is {{ my_current_time }}.</p>
|
<p>The current time is {{ my_current_time }}.</p>
|
||||||
|
@ -1402,7 +848,9 @@ possible to do something with the code between block tags.
|
||||||
For example, here's a custom template tag, ``{% upper %}``, that capitalizes
|
For example, here's a custom template tag, ``{% upper %}``, that capitalizes
|
||||||
everything between itself and ``{% endupper %}``.
|
everything between itself and ``{% endupper %}``.
|
||||||
|
|
||||||
Usage::
|
Usage:
|
||||||
|
|
||||||
|
.. code-block:: html+django
|
||||||
|
|
||||||
{% upper %}This will appear in uppercase, {{ your_name }}.{% endupper %}
|
{% upper %}This will appear in uppercase, {{ your_name }}.{% endupper %}
|
||||||
|
|
||||||
|
@ -1427,37 +875,3 @@ The only new concept here is the ``self.nodelist.render(context)`` in
|
||||||
For more examples of complex rendering, see the source code for ``{% if %}``,
|
For more examples of complex rendering, see the source code for ``{% if %}``,
|
||||||
``{% for %}``, ``{% ifequal %}`` and ``{% ifchanged %}``. They live in
|
``{% for %}``, ``{% ifequal %}`` and ``{% ifchanged %}``. They live in
|
||||||
``django/template/defaulttags.py``.
|
``django/template/defaulttags.py``.
|
||||||
|
|
||||||
.. _configuration:
|
|
||||||
|
|
||||||
Configuring the template system in standalone mode
|
|
||||||
==================================================
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
This section is only of interest to people trying to use the template
|
|
||||||
system as an output component in another application. If you're using the
|
|
||||||
template system as part of a Django application, nothing here applies to
|
|
||||||
you.
|
|
||||||
|
|
||||||
Normally, Django will load all the configuration information it needs from its
|
|
||||||
own default configuration file, combined with the settings in the module given
|
|
||||||
in the ``DJANGO_SETTINGS_MODULE`` environment variable. But if you're using the
|
|
||||||
template system independently of the rest of Django, the environment variable
|
|
||||||
approach isn't very convenient, because you probably want to configure the
|
|
||||||
template system in line with the rest of your application rather than dealing
|
|
||||||
with settings files and pointing to them via environment variables.
|
|
||||||
|
|
||||||
To solve this problem, you need to use the manual configuration option
|
|
||||||
described in the `settings file`_ documentation. Simply import the appropriate
|
|
||||||
pieces of the templating system and then, *before* you call any of the
|
|
||||||
templating functions, call ``django.conf.settings.configure()`` with any
|
|
||||||
settings you wish to specify. You might want to consider setting at least
|
|
||||||
``TEMPLATE_DIRS`` (if you're going to use template loaders),
|
|
||||||
``DEFAULT_CHARSET`` (although the default of ``utf-8`` is probably fine) and
|
|
||||||
``TEMPLATE_DEBUG``. All available settings are described in the
|
|
||||||
`settings documentation`_, and any setting starting with *TEMPLATE_*
|
|
||||||
is of obvious interest.
|
|
||||||
|
|
||||||
.. _settings file: ../settings/#using-settings-without-the-django-settings-module-environment-variable
|
|
||||||
.. _settings documentation: ../settings/
|
|
|
@ -1,17 +1,22 @@
|
||||||
|
.. _howto-deployment-fastcgi:
|
||||||
|
|
||||||
===========================================
|
===========================================
|
||||||
How to use Django with FastCGI, SCGI or AJP
|
How to use Django with FastCGI, SCGI or AJP
|
||||||
===========================================
|
===========================================
|
||||||
|
|
||||||
Although the `current preferred setup`_ for running Django is Apache_ with
|
.. highlight:: bash
|
||||||
`mod_python`_, many people use shared hosting, on which protocols such as
|
|
||||||
FastCGI, SCGI or AJP are the only viable options. In some setups, these protocols
|
Although the current preferred setup for running Django is :ref:`Apache with
|
||||||
also allow better security -- and, possibly, better performance -- than mod_python.
|
mod_python <howto-deployment-modpython>`, many people use shared hosting, on
|
||||||
|
which protocols such as FastCGI, SCGI or AJP are the only viable options. In
|
||||||
|
some setups, these protocols also allow better security -- and, possibly, better
|
||||||
|
performance -- than mod_python_.
|
||||||
|
|
||||||
.. admonition:: Note
|
.. admonition:: Note
|
||||||
|
|
||||||
This document primarily focuses on FastCGI. Other protocols, such as SCGI
|
This document primarily focuses on FastCGI. Other protocols, such as SCGI
|
||||||
and AJP, are also supported, through the ``flup`` Python package. See the
|
and AJP, are also supported, through the ``flup`` Python package. See the
|
||||||
"Protocols" section below for specifics about SCGI and AJP.
|
Protocols_ section below for specifics about SCGI and AJP.
|
||||||
|
|
||||||
Essentially, FastCGI is an efficient way of letting an external application
|
Essentially, FastCGI is an efficient way of letting an external application
|
||||||
serve pages to a Web server. The Web server delegates the incoming Web requests
|
serve pages to a Web server. The Web server delegates the incoming Web requests
|
||||||
|
@ -19,12 +24,10 @@ serve pages to a Web server. The Web server delegates the incoming Web requests
|
||||||
to the Web server, which, in turn, passes it back to the client's Web browser.
|
to the Web server, which, in turn, passes it back to the client's Web browser.
|
||||||
|
|
||||||
Like mod_python, FastCGI allows code to stay in memory, allowing requests to be
|
Like mod_python, FastCGI allows code to stay in memory, allowing requests to be
|
||||||
served with no startup time. Unlike mod_python (or `mod_perl`_), a FastCGI
|
served with no startup time. Unlike mod_python_ (or `mod_perl`_), a FastCGI
|
||||||
process doesn't run inside the Web server process, but in a separate,
|
process doesn't run inside the Web server process, but in a separate,
|
||||||
persistent process.
|
persistent process.
|
||||||
|
|
||||||
.. _current preferred setup: ../modpython/
|
|
||||||
.. _Apache: http://httpd.apache.org/
|
|
||||||
.. _mod_python: http://www.modpython.org/
|
.. _mod_python: http://www.modpython.org/
|
||||||
.. _mod_perl: http://perl.apache.org/
|
.. _mod_perl: http://perl.apache.org/
|
||||||
|
|
||||||
|
@ -45,9 +48,8 @@ persistent process.
|
||||||
Prerequisite: flup
|
Prerequisite: flup
|
||||||
==================
|
==================
|
||||||
|
|
||||||
Before you can start using FastCGI with Django, you'll need to install flup_,
|
Before you can start using FastCGI with Django, you'll need to install flup_, a
|
||||||
which is a Python library for dealing with FastCGI. Version 0.5 or newer should
|
Python library for dealing with FastCGI. Version 0.5 or newer should work fine.
|
||||||
work fine.
|
|
||||||
|
|
||||||
.. _flup: http://www.saddi.com/software/flup/
|
.. _flup: http://www.saddi.com/software/flup/
|
||||||
|
|
||||||
|
@ -72,25 +74,27 @@ TCP socket. What you choose is a manner of preference; a TCP socket is usually
|
||||||
easier due to permissions issues.
|
easier due to permissions issues.
|
||||||
|
|
||||||
To start your server, first change into the directory of your project (wherever
|
To start your server, first change into the directory of your project (wherever
|
||||||
your ``manage.py`` is), and then run ``manage.py`` with the ``runfcgi`` option::
|
your :ref:`manage.py <ref-django-admin>` is), and then run the
|
||||||
|
:djadmin:`runfcgi` command::
|
||||||
|
|
||||||
./manage.py runfcgi [options]
|
./manage.py runfcgi [options]
|
||||||
|
|
||||||
If you specify ``help`` as the only option after ``runfcgi``, it'll display a
|
If you specify ``help`` as the only option after :djadmin:`runfcgi`, it'll
|
||||||
list of all the available options.
|
display a list of all the available options.
|
||||||
|
|
||||||
You'll need to specify either a ``socket``, ``protocol`` or both ``host`` and
|
You'll need to specify either a ``socket``, a ``protocol`` or both ``host`` and
|
||||||
``port``. Then, when you set up your Web server, you'll just need to point it
|
``port``. Then, when you set up your Web server, you'll just need to point it at
|
||||||
at the host/port or socket you specified when starting the FastCGI server.
|
the host/port or socket you specified when starting the FastCGI server. See the
|
||||||
|
examples_, below.
|
||||||
|
|
||||||
Protocols
|
Protocols
|
||||||
---------
|
---------
|
||||||
|
|
||||||
Django supports all the protocols that flup_ does, namely fastcgi_, `SCGI`_ and
|
Django supports all the protocols that flup_ does, namely fastcgi_, `SCGI`_ and
|
||||||
`AJP1.3`_ (the Apache JServ Protocol, version 1.3). Select your preferred
|
`AJP1.3`_ (the Apache JServ Protocol, version 1.3). Select your preferred
|
||||||
protocol by using the ``protocol=<protocol_name>`` option with
|
protocol by using the ``protocol=<protocol_name>`` option with ``./manage.py
|
||||||
``./manage.py runfcgi`` -- where ``<protocol_name>`` may be one of: ``fcgi``
|
runfcgi`` -- where ``<protocol_name>`` may be one of: ``fcgi`` (the default),
|
||||||
(the default), ``scgi`` or ``ajp``. For example::
|
``scgi`` or ``ajp``. For example::
|
||||||
|
|
||||||
./manage.py runfcgi protocol=scgi
|
./manage.py runfcgi protocol=scgi
|
||||||
|
|
||||||
|
@ -122,8 +126,8 @@ Simply hitting ``Ctrl-C`` will stop and quit the FastCGI server. However, when
|
||||||
you're dealing with background processes, you'll need to resort to the Unix
|
you're dealing with background processes, you'll need to resort to the Unix
|
||||||
``kill`` command.
|
``kill`` command.
|
||||||
|
|
||||||
If you specify the ``pidfile`` option to your ``manage.py runfcgi``, you can
|
If you specify the ``pidfile`` option to :djadmin:`runfcgi`, you can kill the
|
||||||
kill the running FastCGI daemon like this::
|
running FastCGI daemon like this::
|
||||||
|
|
||||||
kill `cat $PIDFILE`
|
kill `cat $PIDFILE`
|
||||||
|
|
||||||
|
@ -170,7 +174,9 @@ Specifying the location of the FastCGI server
|
||||||
|
|
||||||
The ``FastCGIExternalServer`` directive tells Apache how to find your FastCGI
|
The ``FastCGIExternalServer`` directive tells Apache how to find your FastCGI
|
||||||
server. As the `FastCGIExternalServer docs`_ explain, you can specify either a
|
server. As the `FastCGIExternalServer docs`_ explain, you can specify either a
|
||||||
``socket`` or a ``host``. Here are examples of both::
|
``socket`` or a ``host``. Here are examples of both:
|
||||||
|
|
||||||
|
.. code-block:: apache
|
||||||
|
|
||||||
# Connect to FastCGI via a socket / named pipe.
|
# Connect to FastCGI via a socket / named pipe.
|
||||||
FastCGIExternalServer /home/user/public_html/mysite.fcgi -socket /home/user/mysite.sock
|
FastCGIExternalServer /home/user/public_html/mysite.fcgi -socket /home/user/mysite.sock
|
||||||
|
@ -195,7 +201,9 @@ directive, as explained in the previous section).
|
||||||
|
|
||||||
In this example, we tell Apache to use FastCGI to handle any request that
|
In this example, we tell Apache to use FastCGI to handle any request that
|
||||||
doesn't represent a file on the filesystem and doesn't start with ``/media/``.
|
doesn't represent a file on the filesystem and doesn't start with ``/media/``.
|
||||||
This is probably the most common case, if you're using Django's admin site::
|
This is probably the most common case, if you're using Django's admin site:
|
||||||
|
|
||||||
|
.. code-block:: apache
|
||||||
|
|
||||||
<VirtualHost 12.34.56.78>
|
<VirtualHost 12.34.56.78>
|
||||||
ServerName example.com
|
ServerName example.com
|
||||||
|
@ -215,15 +223,19 @@ constructing URLs with the ``{% url %}`` template tag (and similar methods).
|
||||||
lighttpd setup
|
lighttpd setup
|
||||||
==============
|
==============
|
||||||
|
|
||||||
lighttpd is a lightweight Web server commonly used for serving static files. It
|
lighttpd_ is a lightweight Web server commonly used for serving static files. It
|
||||||
supports FastCGI natively and, thus, is a good choice for serving both static
|
supports FastCGI natively and, thus, is a good choice for serving both static
|
||||||
and dynamic pages, if your site doesn't have any Apache-specific needs.
|
and dynamic pages, if your site doesn't have any Apache-specific needs.
|
||||||
|
|
||||||
|
.. _lighttpd: http://www.lighttpd.net/
|
||||||
|
|
||||||
Make sure ``mod_fastcgi`` is in your modules list, somewhere after
|
Make sure ``mod_fastcgi`` is in your modules list, somewhere after
|
||||||
``mod_rewrite`` and ``mod_access``, but not after ``mod_accesslog``. You'll
|
``mod_rewrite`` and ``mod_access``, but not after ``mod_accesslog``. You'll
|
||||||
probably want ``mod_alias`` as well, for serving admin media.
|
probably want ``mod_alias`` as well, for serving admin media.
|
||||||
|
|
||||||
Add the following to your lighttpd config file::
|
Add the following to your lighttpd config file:
|
||||||
|
|
||||||
|
.. code-block:: lua
|
||||||
|
|
||||||
server.document-root = "/home/user/public_html"
|
server.document-root = "/home/user/public_html"
|
||||||
fastcgi.server = (
|
fastcgi.server = (
|
||||||
|
@ -289,7 +301,9 @@ using Web server-spawned processes.
|
||||||
there's no need for you to start the FastCGI server on your own. Apache
|
there's no need for you to start the FastCGI server on your own. Apache
|
||||||
will spawn a number of processes, scaling as it needs to.
|
will spawn a number of processes, scaling as it needs to.
|
||||||
|
|
||||||
In your Web root directory, add this to a file named ``.htaccess`` ::
|
In your Web root directory, add this to a file named ``.htaccess``:
|
||||||
|
|
||||||
|
.. code-block:: apache
|
||||||
|
|
||||||
AddHandler fastcgi-script .fcgi
|
AddHandler fastcgi-script .fcgi
|
||||||
RewriteEngine On
|
RewriteEngine On
|
||||||
|
@ -298,7 +312,9 @@ In your Web root directory, add this to a file named ``.htaccess`` ::
|
||||||
|
|
||||||
Then, create a small script that tells Apache how to spawn your FastCGI
|
Then, create a small script that tells Apache how to spawn your FastCGI
|
||||||
program. Create a file ``mysite.fcgi`` and place it in your Web directory, and
|
program. Create a file ``mysite.fcgi`` and place it in your Web directory, and
|
||||||
be sure to make it executable::
|
be sure to make it executable:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
#!/usr/bin/python
|
#!/usr/bin/python
|
||||||
import sys, os
|
import sys, os
|
||||||
|
@ -332,12 +348,10 @@ easily by using the ``touch`` command::
|
||||||
Serving admin media files
|
Serving admin media files
|
||||||
=========================
|
=========================
|
||||||
|
|
||||||
Regardless of the server and configuration you eventually decide to use, you will
|
Regardless of the server and configuration you eventually decide to use, you
|
||||||
also need to give some thought to how to serve the admin media files. The
|
will also need to give some thought to how to serve the admin media files. The
|
||||||
advice given in the modpython_ documentation is also applicable in the setups
|
advice given in the :ref:`modpython <serving-the-admin-files>` documentation
|
||||||
detailed above.
|
is also applicable in the setups detailed above.
|
||||||
|
|
||||||
.. _modpython: ../modpython/#serving-the-admin-files
|
|
||||||
|
|
||||||
Forcing the URL prefix to a particular value
|
Forcing the URL prefix to a particular value
|
||||||
============================================
|
============================================
|
||||||
|
@ -366,3 +380,4 @@ As an example of how to use it, if your Django configuration is serving all of
|
||||||
the URLs under ``'/'`` and you wanted to use this setting, you would set
|
the URLs under ``'/'`` and you wanted to use this setting, you would set
|
||||||
``FORCE_SCRIPT_NAME = ''`` in your settings file.
|
``FORCE_SCRIPT_NAME = ''`` in your settings file.
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
.. _howto-deployment-index:
|
||||||
|
|
||||||
|
Deploying Django
|
||||||
|
================
|
||||||
|
|
||||||
|
Django's chock-full of shortcuts to make web developer's lives easier, but all
|
||||||
|
those tools are of no use if you can't easily deploy your sites. Since Django's
|
||||||
|
inception, ease of deployment has been a major goal. There's a number of good
|
||||||
|
ways to easily deploy Django:
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
|
||||||
|
modpython
|
||||||
|
fastcgi
|
||||||
|
|
||||||
|
:ref:`Deploying under mod_python <howto-deployment-modpython>` is the
|
||||||
|
recommended deployment method; start there if you're not sure which path you'd
|
||||||
|
like to go down.
|
||||||
|
|
||||||
|
.. seealso::
|
||||||
|
|
||||||
|
* `Chapter 20 of The Django Book`_ discusses deployment and especially
|
||||||
|
scaling in more detail.
|
||||||
|
|
||||||
|
* `mod_wsgi`_ is a newcomer to the Python deployment world, but it's rapidly
|
||||||
|
gaining traction. Currently there's a few hoops you have to jump through to
|
||||||
|
`use mod_wsgi with Django`_, but mod_wsgi tends to get rave reviews from
|
||||||
|
those who use it.
|
||||||
|
|
||||||
|
.. _chapter 20 of the django book: http://djangobook.com/en/1.0/chapter20/
|
||||||
|
.. _mod_wsgi: http://code.google.com/p/modwsgi/
|
||||||
|
.. _use mod_wsgi with Django: http://code.google.com/p/modwsgi/wiki/IntegrationWithDjango
|
|
@ -1,27 +1,30 @@
|
||||||
=================================
|
.. _howto-deployment-modpython:
|
||||||
How to use Django with mod_python
|
|
||||||
=================================
|
============================================
|
||||||
|
How to use Django with Apache and mod_python
|
||||||
|
============================================
|
||||||
|
|
||||||
|
.. highlight:: apache
|
||||||
|
|
||||||
Apache_ with `mod_python`_ currently is the preferred setup for using Django
|
Apache_ with `mod_python`_ currently is the preferred setup for using Django
|
||||||
on a production server.
|
on a production server.
|
||||||
|
|
||||||
mod_python is similar to `mod_perl`_ : It embeds Python within Apache and loads
|
mod_python is similar to (and inspired by) `mod_perl`_ : It embeds Python within
|
||||||
Python code into memory when the server starts. Code stays in memory throughout
|
Apache and loads Python code into memory when the server starts. Code stays in
|
||||||
the life of an Apache process, which leads to significant performance gains over
|
memory throughout the life of an Apache process, which leads to significant
|
||||||
other server arrangements.
|
performance gains over other server arrangements.
|
||||||
|
|
||||||
Django requires Apache 2.x and mod_python 3.x, and you should use Apache's
|
Django requires Apache 2.x and mod_python 3.x, and you should use Apache's
|
||||||
`prefork MPM`_, as opposed to the `worker MPM`_.
|
`prefork MPM`_, as opposed to the `worker MPM`_.
|
||||||
|
|
||||||
You may also be interested in `How to use Django with FastCGI, SCGI or AJP`_
|
You may also be interested in :ref:`How to use Django with FastCGI, SCGI or AJP
|
||||||
(which also covers SCGI and AJP).
|
<howto-deployment-fastcgi>` (which also covers SCGI and AJP).
|
||||||
|
|
||||||
.. _Apache: http://httpd.apache.org/
|
.. _Apache: http://httpd.apache.org/
|
||||||
.. _mod_python: http://www.modpython.org/
|
.. _mod_python: http://www.modpython.org/
|
||||||
.. _mod_perl: http://perl.apache.org/
|
.. _mod_perl: http://perl.apache.org/
|
||||||
.. _prefork MPM: http://httpd.apache.org/docs/2.2/mod/prefork.html
|
.. _prefork MPM: http://httpd.apache.org/docs/2.2/mod/prefork.html
|
||||||
.. _worker MPM: http://httpd.apache.org/docs/2.2/mod/worker.html
|
.. _worker MPM: http://httpd.apache.org/docs/2.2/mod/worker.html
|
||||||
.. _How to use Django with FastCGI, SCGI or AJP: ../fastcgi/
|
|
||||||
|
|
||||||
Basic configuration
|
Basic configuration
|
||||||
===================
|
===================
|
||||||
|
@ -43,8 +46,8 @@ Then edit your ``httpd.conf`` file and add the following::
|
||||||
project's settings file.
|
project's settings file.
|
||||||
|
|
||||||
This tells Apache: "Use mod_python for any URL at or under '/mysite/', using the
|
This tells Apache: "Use mod_python for any URL at or under '/mysite/', using the
|
||||||
Django mod_python handler." It passes the value of ``DJANGO_SETTINGS_MODULE``
|
Django mod_python handler." It passes the value of :ref:`DJANGO_SETTINGS_MODULE
|
||||||
so mod_python knows which settings to use.
|
<django-settings-module>` so mod_python knows which settings to use.
|
||||||
|
|
||||||
**New in Django development version:** Because mod_python does not know we are
|
**New in Django development version:** Because mod_python does not know we are
|
||||||
serving this site from underneath the ``/mysite/`` prefix, this value needs to
|
serving this site from underneath the ``/mysite/`` prefix, this value needs to
|
||||||
|
@ -85,18 +88,18 @@ computer, you'll have to tell mod_python where your project can be found:
|
||||||
|
|
||||||
The value you use for ``PythonPath`` should include the parent directories of
|
The value you use for ``PythonPath`` should include the parent directories of
|
||||||
all the modules you are going to import in your application. It should also
|
all the modules you are going to import in your application. It should also
|
||||||
include the parent directory of the ``DJANGO_SETTINGS_MODULE`` location. This
|
include the parent directory of the :ref:`DJANGO_SETTINGS_MODULE
|
||||||
is exactly the same situation as setting the Python path for interactive
|
<django-settings-module>` location. This is exactly the same situation as
|
||||||
usage. Whenever you try to import something, Python will run through all the
|
setting the Python path for interactive usage. Whenever you try to import
|
||||||
directories in ``sys.path`` in turn, from first to last, and try to import
|
something, Python will run through all the directories in ``sys.path`` in turn,
|
||||||
from each directory until one succeeds.
|
from first to last, and try to import from each directory until one succeeds.
|
||||||
|
|
||||||
An example might make this clearer. Suppose
|
An example might make this clearer. Suppose you have some applications under
|
||||||
you have some applications under ``/usr/local/django-apps/`` (for example,
|
``/usr/local/django-apps/`` (for example, ``/usr/local/django-apps/weblog/`` and
|
||||||
``/usr/local/django-apps/weblog/`` and so forth), your settings file is at
|
so forth), your settings file is at ``/var/www/mysite/settings.py`` and you have
|
||||||
``/var/www/mysite/settings.py`` and you have specified
|
specified :ref:`DJANGO_SETTINGS_MODULE <django-settings-module>` as in the above
|
||||||
``DJANGO_SETTINGS_MODULE`` as in the above example. In this case, you would
|
example. In this case, you would need to write your ``PythonPath`` directive
|
||||||
need to write your ``PythonPath`` directive as::
|
as::
|
||||||
|
|
||||||
PythonPath "['/usr/local/django-apps/', '/var/www'] + sys.path"
|
PythonPath "['/usr/local/django-apps/', '/var/www'] + sys.path"
|
||||||
|
|
||||||
|
@ -127,9 +130,9 @@ Note that you should set ``PythonDebug Off`` on a production server. If you
|
||||||
leave ``PythonDebug On``, your users would see ugly (and revealing) Python
|
leave ``PythonDebug On``, your users would see ugly (and revealing) Python
|
||||||
tracebacks if something goes wrong within mod_python.
|
tracebacks if something goes wrong within mod_python.
|
||||||
|
|
||||||
Restart Apache, and any request to /mysite/ or below will be served by Django.
|
Restart Apache, and any request to ``/mysite/`` or below will be served by
|
||||||
Note that Django's URLconfs won't trim the "/mysite/" -- they get passed the
|
Django. Note that Django's URLconfs won't trim the "/mysite/" -- they get passed
|
||||||
full URL.
|
the full URL.
|
||||||
|
|
||||||
When deploying Django sites on mod_python, you'll need to restart Apache each
|
When deploying Django sites on mod_python, you'll need to restart Apache each
|
||||||
time you make changes to your Python code.
|
time you make changes to your Python code.
|
||||||
|
@ -196,6 +199,8 @@ Or add the debugging information to the template of your page.
|
||||||
|
|
||||||
.. _mod_python documentation: http://modpython.org/live/current/doc-html/directives.html
|
.. _mod_python documentation: http://modpython.org/live/current/doc-html/directives.html
|
||||||
|
|
||||||
|
.. _serving-media-files:
|
||||||
|
|
||||||
Serving media files
|
Serving media files
|
||||||
===================
|
===================
|
||||||
|
|
||||||
|
@ -205,9 +210,9 @@ server you choose.
|
||||||
We recommend using a separate Web server -- i.e., one that's not also running
|
We recommend using a separate Web server -- i.e., one that's not also running
|
||||||
Django -- for serving media. Here are some good choices:
|
Django -- for serving media. Here are some good choices:
|
||||||
|
|
||||||
* lighttpd_
|
* lighttpd_
|
||||||
* TUX_
|
* TUX_
|
||||||
* A stripped-down version of Apache_
|
* A stripped-down version of Apache_
|
||||||
|
|
||||||
If, however, you have no option but to serve media files on the same Apache
|
If, however, you have no option but to serve media files on the same Apache
|
||||||
``VirtualHost`` as Django, here's how you can turn off mod_python for a
|
``VirtualHost`` as Django, here's how you can turn off mod_python for a
|
||||||
|
@ -243,6 +248,10 @@ the ``media`` subdirectory and any URL that ends with ``.jpg``, ``.gif`` or
|
||||||
.. _TUX: http://en.wikipedia.org/wiki/TUX_web_server
|
.. _TUX: http://en.wikipedia.org/wiki/TUX_web_server
|
||||||
.. _Apache: http://httpd.apache.org/
|
.. _Apache: http://httpd.apache.org/
|
||||||
|
|
||||||
|
.. _howto-deployment-modpython-serving-the-admin-files:
|
||||||
|
|
||||||
|
.. _serving-the-admin-files:
|
||||||
|
|
||||||
Serving the admin files
|
Serving the admin files
|
||||||
=======================
|
=======================
|
||||||
|
|
||||||
|
@ -251,25 +260,27 @@ but this is not the case when you use any other server arrangement. You're
|
||||||
responsible for setting up Apache, or whichever media server you're using, to
|
responsible for setting up Apache, or whichever media server you're using, to
|
||||||
serve the admin files.
|
serve the admin files.
|
||||||
|
|
||||||
The admin files live in (``django/contrib/admin/media``) of the Django
|
The admin files live in (:file:`django/contrib/admin/media`) of the Django
|
||||||
distribution.
|
distribution.
|
||||||
|
|
||||||
Here are two recommended approaches:
|
Here are two recommended approaches:
|
||||||
|
|
||||||
1. Create a symbolic link to the admin media files from within your
|
1. Create a symbolic link to the admin media files from within your
|
||||||
document root. This way, all of your Django-related files -- code
|
document root. This way, all of your Django-related files -- code **and**
|
||||||
**and** templates -- stay in one place, and you'll still be able to
|
templates -- stay in one place, and you'll still be able to ``svn
|
||||||
``svn update`` your code to get the latest admin templates, if they
|
update`` your code to get the latest admin templates, if they change.
|
||||||
change.
|
|
||||||
2. Or, copy the admin media files so that they live within your Apache
|
2. Or, copy the admin media files so that they live within your Apache
|
||||||
document root.
|
document root.
|
||||||
|
|
||||||
Using eggs with mod_python
|
Using "eggs" with mod_python
|
||||||
==========================
|
============================
|
||||||
|
|
||||||
If you installed Django from a Python egg_ or are using eggs in your Django
|
If you installed Django from a Python egg_ or are using eggs in your Django
|
||||||
project, some extra configuration is required. Create an extra file in your
|
project, some extra configuration is required. Create an extra file in your
|
||||||
project (or somewhere else) that contains something like the following::
|
project (or somewhere else) that contains something like the following:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
import os
|
import os
|
||||||
os.environ['PYTHON_EGG_CACHE'] = '/some/directory'
|
os.environ['PYTHON_EGG_CACHE'] = '/some/directory'
|
||||||
|
@ -322,6 +333,7 @@ of which has to do with Django itself.
|
||||||
1. It may be because your Python code is importing the "pyexpat" module,
|
1. It may be because your Python code is importing the "pyexpat" module,
|
||||||
which may conflict with the version embedded in Apache. For full
|
which may conflict with the version embedded in Apache. For full
|
||||||
information, see `Expat Causing Apache Crash`_.
|
information, see `Expat Causing Apache Crash`_.
|
||||||
|
|
||||||
2. It may be because you're running mod_python and mod_php in the same
|
2. It may be because you're running mod_python and mod_php in the same
|
||||||
Apache instance, with MySQL as your database backend. In some cases,
|
Apache instance, with MySQL as your database backend. In some cases,
|
||||||
this causes a known mod_python issue due to version conflicts in PHP and
|
this causes a known mod_python issue due to version conflicts in PHP and
|
|
@ -0,0 +1,65 @@
|
||||||
|
.. _howto-error-reporting:
|
||||||
|
|
||||||
|
Error reporting via e-mail
|
||||||
|
==========================
|
||||||
|
|
||||||
|
When you're running a public site you should always turn off the
|
||||||
|
:setting:`DEBUG` setting. That will make your server run much faster, and will
|
||||||
|
also prevent malicious users from seeing details of your application that can be
|
||||||
|
revealed by the error pages.
|
||||||
|
|
||||||
|
However, running with :setting:`DEBUG` set to ``False`` means you'll never see
|
||||||
|
errors generated by your site -- everyone will just see your public error pages.
|
||||||
|
You need to keep track of errors that occur in deployed sites, so Django can be
|
||||||
|
configured to email you details of those errors.
|
||||||
|
|
||||||
|
Server errors
|
||||||
|
-------------
|
||||||
|
|
||||||
|
When :setting:`DEBUG` is ``False``, Django will e-mail the users listed in the
|
||||||
|
:setting:`ADMIN` setting whenever your code raises an unhandled exception and
|
||||||
|
results in an internal server error (HTTP status code 500). This gives the
|
||||||
|
administrators immediate notification of any errors. The :setting:`ADMINS` will
|
||||||
|
get a description of the error, a complete Python traceback, and details about
|
||||||
|
the HTTP request that caused the error.
|
||||||
|
|
||||||
|
To disable this behavior, just remove all entries from the :setting:`ADMINS`
|
||||||
|
setting.
|
||||||
|
|
||||||
|
404 errors
|
||||||
|
----------
|
||||||
|
|
||||||
|
Django can also be configured to email errors about broken links (404 "page
|
||||||
|
not found" errors). Django sends emails about 404 errors when:
|
||||||
|
|
||||||
|
* :setting:`DEBUG` is ``False``
|
||||||
|
|
||||||
|
* :setting:`SEND_BROKEN_LINK_EMAILS` is ``True``
|
||||||
|
|
||||||
|
* Your :setting:`MIDDLEWARE_CLASSES` setting includes ``CommonMiddleware``
|
||||||
|
(which it does by default).
|
||||||
|
|
||||||
|
If those conditions are met, Django will e-mail the users listed in the
|
||||||
|
:setting:`MANAGERS` setting whenever your code raises a 404 and the request has
|
||||||
|
a referer. (It doesn't bother to e-mail for 404s that don't have a referer --
|
||||||
|
those are usually just people typing in broken URLs or broken web 'bots).
|
||||||
|
|
||||||
|
You can tell Django to stop reporting particular 404s by tweaking the
|
||||||
|
:setting:`IGNORABLE_404_ENDS` and :setting:`IGNORABLE_404_STARTS` settings. Both
|
||||||
|
should be a tuple of strings. For example::
|
||||||
|
|
||||||
|
IGNORABLE_404_ENDS = ('.php', '.cgi')
|
||||||
|
IGNORABLE_404_STARTS = ('/phpmyadmin/',)
|
||||||
|
|
||||||
|
In this example, a 404 to any URL ending with ``.php`` or ``.cgi`` will *not* be
|
||||||
|
reported. Neither will any URL starting with ``/phpmyadmin/``.
|
||||||
|
|
||||||
|
The best way to disable this behavior is to set
|
||||||
|
:setting:`SEND_BROKEN_LINK_EMAILS` to ``False``.
|
||||||
|
|
||||||
|
.. seealso::
|
||||||
|
|
||||||
|
You can also set up custom error reporting by writing a custom piece of
|
||||||
|
:ref:`exception middleware <exception-middleware>`. If you do write custom
|
||||||
|
error handling, it's a good idea to emulate Django's built-in error handling
|
||||||
|
and only report/log errors if :setting:`DEBUG` is ``False``.
|
|
@ -0,0 +1,33 @@
|
||||||
|
.. _howto-index:
|
||||||
|
|
||||||
|
"How-to" guides
|
||||||
|
===============
|
||||||
|
|
||||||
|
Here you'll find short answers to "How do I....?" types of questions. These
|
||||||
|
how-to guides don't cover topics in depth -- you'll find that material in the
|
||||||
|
:ref:`topics-index` and the :ref:`ref-index`. However, these guides will help
|
||||||
|
you quickly accomplish common tasks.
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
|
||||||
|
apache-auth
|
||||||
|
custom-management-commands
|
||||||
|
custom-model-fields
|
||||||
|
custom-template-tags
|
||||||
|
custom-file-storage
|
||||||
|
deployment/index
|
||||||
|
error-reporting
|
||||||
|
initial-data
|
||||||
|
legacy-databases
|
||||||
|
outputting-csv
|
||||||
|
outputting-pdf
|
||||||
|
static-files
|
||||||
|
|
||||||
|
.. seealso::
|
||||||
|
|
||||||
|
The `Django community aggregator`_, where we aggregate content from the
|
||||||
|
global Django community. Many writers in the aggregator write this sort of
|
||||||
|
how-to material.
|
||||||
|
|
||||||
|
.. _django community aggregator: http://www.djangoproject.com/community/
|
|
@ -0,0 +1,140 @@
|
||||||
|
.. _howto-initial-data:
|
||||||
|
|
||||||
|
=================================
|
||||||
|
Providing initial data for models
|
||||||
|
=================================
|
||||||
|
|
||||||
|
It's sometimes useful to pre-populate your database with hard-coded data when
|
||||||
|
you're first setting up an app. There's a couple of ways you can have Django
|
||||||
|
automatically create this data: you can provide `initial data via fixtures`_, or
|
||||||
|
you can provide `initial data as SQL`_.
|
||||||
|
|
||||||
|
In general, using a fixture is a cleaner method since it's database-agnostic,
|
||||||
|
but initial SQL is also quite a bit more flexible.
|
||||||
|
|
||||||
|
.. _initial data as sql: `providing initial sql data`_
|
||||||
|
.. _initial data via fixtures: `providing initial data with fixtures`_
|
||||||
|
|
||||||
|
Providing initial data with fixtures
|
||||||
|
====================================
|
||||||
|
|
||||||
|
A fixture is a collection of data that Django knows how to import into a
|
||||||
|
database. The most straightforward way of creating a fixture if you've already
|
||||||
|
got some data is to use the :djadmin:`manage.py dumpdata` command. Or, you can
|
||||||
|
write fixtures by hand; fixtures can be written as XML, YAML, or JSON documents.
|
||||||
|
The :ref:`serialization documentation <topics-serialization>` has more details
|
||||||
|
about each of these supported :ref:`serialization formats
|
||||||
|
<serialization-formats>`.
|
||||||
|
|
||||||
|
As an example, though, here's what a fixture for a simple ``Person`` model might
|
||||||
|
look like in JSON:
|
||||||
|
|
||||||
|
.. code-block:: js
|
||||||
|
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"model": "myapp.person",
|
||||||
|
"pk": 1,
|
||||||
|
"fields": {
|
||||||
|
"first_name": "John",
|
||||||
|
"last_name": "Lennon",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "myapp.person",
|
||||||
|
"pk": 2,
|
||||||
|
"fields": {
|
||||||
|
"first_name": "Paul",
|
||||||
|
"last_name": "McCartney",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
And here's that same fixture as YAML:
|
||||||
|
|
||||||
|
.. code-block:: none
|
||||||
|
|
||||||
|
- model: myapp.person
|
||||||
|
pk: 1
|
||||||
|
fields:
|
||||||
|
first_name: John
|
||||||
|
last_name: Lennon
|
||||||
|
- model: myapp.person
|
||||||
|
pk: 1
|
||||||
|
fields:
|
||||||
|
first_name: Paul
|
||||||
|
last_name: McCartney
|
||||||
|
|
||||||
|
You'll store this data in a ``fixtures`` directory inside you app.
|
||||||
|
|
||||||
|
Loading data is easy: just call :djadmin:`manage.py loaddata fixturename
|
||||||
|
<loaddata>`, where *fixturename* is the name of the fixture file you've created.
|
||||||
|
Every time you run :djadmin:`loaddata` the data will be read from the fixture
|
||||||
|
and re-loaded into the database. Note that this means that if you change one of
|
||||||
|
the rows created by a fixture and the run :djadmin:`loaddata` again you'll wipe
|
||||||
|
out any changes you've made.
|
||||||
|
|
||||||
|
Automatically loading initial data fixtures
|
||||||
|
-------------------------------------------
|
||||||
|
|
||||||
|
If you create a fixture named ``initial_data.[xml/yml/json]``, that fixture will
|
||||||
|
be loaded every time you run :djadmin:`syncdb`. This is extremely convenient,
|
||||||
|
but be careful: remember that the data will be refreshed *every time* you run
|
||||||
|
:djadmin:`syncdb`. So don't use ``initial_data`` for data you'll want to edit.
|
||||||
|
|
||||||
|
.. seealso::
|
||||||
|
|
||||||
|
Fixtures are also used by the :ref:`testing framework
|
||||||
|
<topics-testing-fixtures>` to help set up a consistent test environment.
|
||||||
|
|
||||||
|
.. _initial-sql:
|
||||||
|
|
||||||
|
Providing initial SQL data
|
||||||
|
==========================
|
||||||
|
|
||||||
|
Django provides a hook for passing the database arbitrary SQL that's executed
|
||||||
|
just after the CREATE TABLE statements when you run :djadmin:`syncdb`. You can
|
||||||
|
use this hook to populate default records, or you could also create SQL
|
||||||
|
functions, views, triggers, etc.
|
||||||
|
|
||||||
|
The hook is simple: Django just looks for a file called ``sql/<modelname>.sql``,
|
||||||
|
in your app directory, where ``<modelname>`` is the model's name in lowercase.
|
||||||
|
|
||||||
|
So, if you had a ``Person`` model in an app called ``myapp``, you could add
|
||||||
|
arbitrary SQL to the file ``sql/person.sql`` inside your ``myapp`` directory.
|
||||||
|
Here's an example of what the file might contain:
|
||||||
|
|
||||||
|
.. code-block:: sql
|
||||||
|
|
||||||
|
INSERT INTO myapp_person (first_name, last_name) VALUES ('John', 'Lennon');
|
||||||
|
INSERT INTO myapp_person (first_name, last_name) VALUES ('Paul', 'McCartney');
|
||||||
|
|
||||||
|
Each SQL file, if given, is expected to contain valid SQL statements
|
||||||
|
which will insert the desired data (e.g., properly-formatted
|
||||||
|
``INSERT`` statements separated by semicolons).
|
||||||
|
|
||||||
|
The SQL files are read by the :djadmin:`sqlcustom`, :djadmin:`sqlreset`,
|
||||||
|
:djadmin:`sqlall` and :djadmin:`reset` commands in :ref:`manage.py
|
||||||
|
<ref-django-admin>`. Refer to the :ref:`manage.py documentation
|
||||||
|
<ref-django-admin>` for more information.
|
||||||
|
|
||||||
|
Note that if you have multiple SQL data files, there's no guarantee of the order
|
||||||
|
in which they're executed. The only thing you can assume is that, by the time
|
||||||
|
your custom data files are executed, all the database tables already will have
|
||||||
|
been created.
|
||||||
|
|
||||||
|
Database-backend-specific SQL data
|
||||||
|
----------------------------------
|
||||||
|
|
||||||
|
There's also a hook for backend-specific SQL data. For example, you can have
|
||||||
|
separate initial-data files for PostgreSQL and MySQL. For each app, Django
|
||||||
|
looks for a file called ``<appname>/sql/<modelname>.<backend>.sql``, where
|
||||||
|
``<appname>`` is your app directory, ``<modelname>`` is the model's name in
|
||||||
|
lowercase and ``<backend>`` is the value of :setting:`DATABASE_ENGINE` in your
|
||||||
|
settings file (e.g., ``postgresql``, ``mysql``).
|
||||||
|
|
||||||
|
Backend-specific SQL data is executed before non-backend-specific SQL data. For
|
||||||
|
example, if your app contains the files ``sql/person.sql`` and
|
||||||
|
``sql/person.postgresql.sql`` and you're installing the app on PostgreSQL,
|
||||||
|
Django will execute the contents of ``sql/person.postgresql.sql`` first, then
|
||||||
|
``sql/person.sql``.
|
|
@ -0,0 +1,67 @@
|
||||||
|
.. _howto-legacy-databases:
|
||||||
|
|
||||||
|
=========================================
|
||||||
|
Integrating Django with a legacy database
|
||||||
|
=========================================
|
||||||
|
|
||||||
|
While Django is best suited for developing new applications, it's quite
|
||||||
|
possible to integrate it into legacy databases. Django includes a couple of
|
||||||
|
utilities to automate as much of this process as possible.
|
||||||
|
|
||||||
|
This document assumes you know the Django basics, as covered in the
|
||||||
|
:ref:`tutorial <intro-tutorial01>`.
|
||||||
|
|
||||||
|
Once you've got Django set up, you'll follow this general process to integrate
|
||||||
|
with an existing database.
|
||||||
|
|
||||||
|
Give Django your database parameters
|
||||||
|
====================================
|
||||||
|
|
||||||
|
You'll need to tell Django what your database connection parameters are, and
|
||||||
|
what the name of the database is. Do that by editing these settings in your
|
||||||
|
:ref:`settings file <topics-settings>`:
|
||||||
|
|
||||||
|
* :setting:`DATABASE_NAME`
|
||||||
|
* :setting:`DATABASE_ENGINE`
|
||||||
|
* :setting:`DATABASE_USER`
|
||||||
|
* :setting:`DATABASE_PASSWORD`
|
||||||
|
* :setting:`DATABASE_HOST`
|
||||||
|
* :setting:`DATABASE_PORT`
|
||||||
|
|
||||||
|
Auto-generate the models
|
||||||
|
========================
|
||||||
|
|
||||||
|
.. highlight:: bash
|
||||||
|
|
||||||
|
Django comes with a utility called :djadmin:`inspectdb` that can create models
|
||||||
|
by introspecting an existing database. You can view the output by running this
|
||||||
|
command::
|
||||||
|
|
||||||
|
python manage.py inspectdb
|
||||||
|
|
||||||
|
Save this as a file by using standard Unix output redirection::
|
||||||
|
|
||||||
|
python manage.py inspectdb > models.py
|
||||||
|
|
||||||
|
This feature is meant as a shortcut, not as definitive model generation. See the
|
||||||
|
:djadmin:`documentation of inspectdb <inspectdb>` for more information.
|
||||||
|
|
||||||
|
Once you've cleaned up your models, name the file ``models.py`` and put it in
|
||||||
|
the Python package that holds your app. Then add the app to your
|
||||||
|
:setting:`INSTALLED_APPS` setting.
|
||||||
|
|
||||||
|
Install the core Django tables
|
||||||
|
==============================
|
||||||
|
|
||||||
|
Next, run the :djadmin:`syncdb` command to install any extra needed database
|
||||||
|
records such as admin permissions and content types::
|
||||||
|
|
||||||
|
python manage.py syncdb
|
||||||
|
|
||||||
|
Test and tweak
|
||||||
|
==============
|
||||||
|
|
||||||
|
Those are the basic steps -- from here you'll want to tweak the models Django
|
||||||
|
generated until they work the way you'd like. Try accessing your data via the
|
||||||
|
Django database API, and try editing objects via Django's admin site, and edit
|
||||||
|
the models file accordingly.
|
|
@ -1,12 +1,12 @@
|
||||||
|
.. _howto-outputting-csv:
|
||||||
|
|
||||||
==========================
|
==========================
|
||||||
Outputting CSV with Django
|
Outputting CSV with Django
|
||||||
==========================
|
==========================
|
||||||
|
|
||||||
This document explains how to output CSV (Comma Separated Values) dynamically
|
This document explains how to output CSV (Comma Separated Values) dynamically
|
||||||
using Django views.
|
using Django views. To do this, you can either use the `Python CSV library`_ or
|
||||||
|
the Django template system.
|
||||||
To do this, you can either use the `Python CSV library`_ or the Django template
|
|
||||||
system.
|
|
||||||
|
|
||||||
.. _Python CSV library: http://www.python.org/doc/current/lib/module-csv.html
|
.. _Python CSV library: http://www.python.org/doc/current/lib/module-csv.html
|
||||||
|
|
||||||
|
@ -14,18 +14,8 @@ Using the Python CSV library
|
||||||
============================
|
============================
|
||||||
|
|
||||||
Python comes with a CSV library, ``csv``. The key to using it with Django is
|
Python comes with a CSV library, ``csv``. The key to using it with Django is
|
||||||
that the ``csv`` module's CSV-creation capability acts on file-like objects,
|
that the ``csv`` module's CSV-creation capability acts on file-like objects, and
|
||||||
and Django's ``HttpResponse`` objects are file-like objects.
|
Django's :class:`~django.http.HttpResponse` objects are file-like objects.
|
||||||
|
|
||||||
.. admonition:: Note
|
|
||||||
|
|
||||||
For more information on ``HttpResponse`` objects, see
|
|
||||||
`Request and response objects`_.
|
|
||||||
|
|
||||||
For more information on the CSV library, see the `CSV library docs`_.
|
|
||||||
|
|
||||||
.. _Request and response objects: ../request_response/
|
|
||||||
.. _CSV library docs: http://www.python.org/doc/current/lib/module-csv.html
|
|
||||||
|
|
||||||
Here's an example::
|
Here's an example::
|
||||||
|
|
||||||
|
@ -46,7 +36,7 @@ Here's an example::
|
||||||
The code and comments should be self-explanatory, but a few things deserve a
|
The code and comments should be self-explanatory, but a few things deserve a
|
||||||
mention:
|
mention:
|
||||||
|
|
||||||
* The response gets a special mimetype, ``text/csv``. This tells
|
* The response gets a special MIME type, ``text/csv``. This tells
|
||||||
browsers that the document is a CSV file, rather than an HTML file. If
|
browsers that the document is a CSV file, rather than an HTML file. If
|
||||||
you leave this off, browsers will probably interpret the output as HTML,
|
you leave this off, browsers will probably interpret the output as HTML,
|
||||||
which will result in ugly, scary gobbledygook in the browser window.
|
which will result in ugly, scary gobbledygook in the browser window.
|
||||||
|
@ -56,9 +46,10 @@ mention:
|
||||||
whatever you want. It'll be used by browsers in the "Save as..."
|
whatever you want. It'll be used by browsers in the "Save as..."
|
||||||
dialogue, etc.
|
dialogue, etc.
|
||||||
|
|
||||||
* Hooking into the CSV-generation API is easy: Just pass ``response`` as
|
* Hooking into the CSV-generation API is easy: Just pass ``response`` as the
|
||||||
the first argument to ``csv.writer``. The ``csv.writer`` function expects
|
first argument to ``csv.writer``. The ``csv.writer`` function expects a
|
||||||
a file-like object, and ``HttpResponse`` objects fit the bill.
|
file-like object, and :class:`~django.http.HttpResponse` objects fit the
|
||||||
|
bill.
|
||||||
|
|
||||||
* For each row in your CSV file, call ``writer.writerow``, passing it an
|
* For each row in your CSV file, call ``writer.writerow``, passing it an
|
||||||
iterable object such as a list or tuple.
|
iterable object such as a list or tuple.
|
||||||
|
@ -70,12 +61,12 @@ mention:
|
||||||
Using the template system
|
Using the template system
|
||||||
=========================
|
=========================
|
||||||
|
|
||||||
Alternatively, you can use the `Django template system`_ to generate CSV. This
|
Alternatively, you can use the :ref:`Django template system <topics-templates>`
|
||||||
is lower-level than using the convenient CSV, but the solution is presented
|
to generate CSV. This is lower-level than using the convenient CSV, but the
|
||||||
here for completeness.
|
solution is presented here for completeness.
|
||||||
|
|
||||||
The idea here is to pass a list of items to your template, and have the
|
The idea here is to pass a list of items to your template, and have the
|
||||||
template output the commas in a ``{% for %}`` loop.
|
template output the commas in a :ttag:`for` loop.
|
||||||
|
|
||||||
Here's an example, which generates the same CSV file as above::
|
Here's an example, which generates the same CSV file as above::
|
||||||
|
|
||||||
|
@ -105,15 +96,21 @@ The only difference between this example and the previous example is that this
|
||||||
one uses template loading instead of the CSV module. The rest of the code --
|
one uses template loading instead of the CSV module. The rest of the code --
|
||||||
such as the ``mimetype='text/csv'`` -- is the same.
|
such as the ``mimetype='text/csv'`` -- is the same.
|
||||||
|
|
||||||
Then, create the template ``my_template_name.txt``, with this template code::
|
Then, create the template ``my_template_name.txt``, with this template code:
|
||||||
|
|
||||||
|
.. code-block:: html+django
|
||||||
|
|
||||||
{% for row in data %}"{{ row.0|addslashes }}", "{{ row.1|addslashes }}", "{{ row.2|addslashes }}", "{{ row.3|addslashes }}", "{{ row.4|addslashes }}"
|
{% for row in data %}"{{ row.0|addslashes }}", "{{ row.1|addslashes }}", "{{ row.2|addslashes }}", "{{ row.3|addslashes }}", "{{ row.4|addslashes }}"
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
This template is quite basic. It just iterates over the given data and displays
|
This template is quite basic. It just iterates over the given data and displays
|
||||||
a line of CSV for each row. It uses the `addslashes template filter`_ to ensure
|
a line of CSV for each row. It uses the :tfilter:`addslashes` template filter to
|
||||||
there aren't any problems with quotes. If you can be certain your data doesn't
|
ensure there aren't any problems with quotes.
|
||||||
have single or double quotes in it, you can remove the ``addslashes`` filters.
|
|
||||||
|
|
||||||
.. _Django template system: ../templates/
|
Other text-based formats
|
||||||
.. _addslashes template filter: ../templates/#addslashes
|
========================
|
||||||
|
|
||||||
|
Notice that there isn't very much specific to CSV here -- just the specific
|
||||||
|
output format. You can use either of these techniques to output any text-based
|
||||||
|
format you can dream of. You can also use a similar technique to generate
|
||||||
|
arbitrary binary data; see :ref:`howto-outputting-pdf` for an example.
|
|
@ -1,3 +1,5 @@
|
||||||
|
.. _howto-outputting-pdf:
|
||||||
|
|
||||||
===========================
|
===========================
|
||||||
Outputting PDFs with Django
|
Outputting PDFs with Django
|
||||||
===========================
|
===========================
|
||||||
|
@ -35,15 +37,8 @@ Write your view
|
||||||
===============
|
===============
|
||||||
|
|
||||||
The key to generating PDFs dynamically with Django is that the ReportLab API
|
The key to generating PDFs dynamically with Django is that the ReportLab API
|
||||||
acts on file-like objects, and Django's ``HttpResponse`` objects are file-like
|
acts on file-like objects, and Django's :class:`~django.http.HttpResponse`
|
||||||
objects.
|
objects are file-like objects.
|
||||||
|
|
||||||
.. admonition:: Note
|
|
||||||
|
|
||||||
For more information on ``HttpResponse`` objects, see
|
|
||||||
`Request and response objects`_.
|
|
||||||
|
|
||||||
.. _Request and response objects: ../request_response/
|
|
||||||
|
|
||||||
Here's a "Hello World" example::
|
Here's a "Hello World" example::
|
||||||
|
|
||||||
|
@ -70,7 +65,7 @@ Here's a "Hello World" example::
|
||||||
The code and comments should be self-explanatory, but a few things deserve a
|
The code and comments should be self-explanatory, but a few things deserve a
|
||||||
mention:
|
mention:
|
||||||
|
|
||||||
* The response gets a special mimetype, ``application/pdf``. This tells
|
* The response gets a special MIME type, ``application/pdf``. This tells
|
||||||
browsers that the document is a PDF file, rather than an HTML file. If
|
browsers that the document is a PDF file, rather than an HTML file. If
|
||||||
you leave this off, browsers will probably interpret the output as HTML,
|
you leave this off, browsers will probably interpret the output as HTML,
|
||||||
which would result in ugly, scary gobbledygook in the browser window.
|
which would result in ugly, scary gobbledygook in the browser window.
|
||||||
|
@ -91,7 +86,8 @@ mention:
|
||||||
|
|
||||||
* Hooking into the ReportLab API is easy: Just pass ``response`` as the
|
* Hooking into the ReportLab API is easy: Just pass ``response`` as the
|
||||||
first argument to ``canvas.Canvas``. The ``Canvas`` class expects a
|
first argument to ``canvas.Canvas``. The ``Canvas`` class expects a
|
||||||
file-like object, and ``HttpResponse`` objects fit the bill.
|
file-like object, and :class:`~django.http.HttpResponse` objects fit the
|
||||||
|
bill.
|
||||||
|
|
||||||
* Note that all subsequent PDF-generation methods are called on the PDF
|
* Note that all subsequent PDF-generation methods are called on the PDF
|
||||||
object (in this case, ``p``) -- not on ``response``.
|
object (in this case, ``p``) -- not on ``response``.
|
||||||
|
@ -103,10 +99,9 @@ Complex PDFs
|
||||||
============
|
============
|
||||||
|
|
||||||
If you're creating a complex PDF document with ReportLab, consider using the
|
If you're creating a complex PDF document with ReportLab, consider using the
|
||||||
cStringIO_ library as a temporary holding place for your PDF file. The
|
cStringIO_ library as a temporary holding place for your PDF file. The cStringIO
|
||||||
cStringIO library provides a file-like object interface that is particularly
|
library provides a file-like object interface that is particularly efficient.
|
||||||
efficient. Here's the above "Hello World" example rewritten to use
|
Here's the above "Hello World" example rewritten to use ``cStringIO``::
|
||||||
``cStringIO``::
|
|
||||||
|
|
||||||
from cStringIO import StringIO
|
from cStringIO import StringIO
|
||||||
from reportlab.pdfgen import canvas
|
from reportlab.pdfgen import canvas
|
||||||
|
@ -154,3 +149,12 @@ Further resources
|
||||||
.. _`Pisa HTML2PDF`: http://www.htmltopdf.org/
|
.. _`Pisa HTML2PDF`: http://www.htmltopdf.org/
|
||||||
.. _HTMLdoc: http://www.htmldoc.org/
|
.. _HTMLdoc: http://www.htmldoc.org/
|
||||||
.. _forge_fdf in Python: http://www.accesspdf.com/article.php/20050421092951834
|
.. _forge_fdf in Python: http://www.accesspdf.com/article.php/20050421092951834
|
||||||
|
|
||||||
|
Other formats
|
||||||
|
=============
|
||||||
|
|
||||||
|
Notice that there isn't a lot in these examples that's PDF-specific -- just the
|
||||||
|
bits using ``reportlab``. You can use a similar technique to generate any
|
||||||
|
arbitrary format that you can find a Python library for. Also see
|
||||||
|
:ref:`howto-outputting-csv` for another example and some techniques you can use
|
||||||
|
when generated text-based formats.
|
|
@ -1,7 +1,12 @@
|
||||||
|
.. _howto-static-files:
|
||||||
|
|
||||||
=========================
|
=========================
|
||||||
How to serve static files
|
How to serve static files
|
||||||
=========================
|
=========================
|
||||||
|
|
||||||
|
.. module:: django.views.static
|
||||||
|
:synopsis: Serving of static files during development.
|
||||||
|
|
||||||
Django itself doesn't serve static (media) files, such as images, style sheets,
|
Django itself doesn't serve static (media) files, such as images, style sheets,
|
||||||
or video. It leaves that job to whichever Web server you choose.
|
or video. It leaves that job to whichever Web server you choose.
|
||||||
|
|
||||||
|
@ -9,8 +14,8 @@ The reasoning here is that standard Web servers, such as Apache_ and lighttpd_,
|
||||||
are much more fine-tuned at serving static files than a Web application
|
are much more fine-tuned at serving static files than a Web application
|
||||||
framework.
|
framework.
|
||||||
|
|
||||||
With that said, Django does support static files **during development**. Use
|
With that said, Django does support static files **during development**. You can
|
||||||
the view ``django.views.static.serve`` to serve media files.
|
use the :func:`django.views.static.serve` view to serve media files.
|
||||||
|
|
||||||
.. _Apache: http://httpd.apache.org/
|
.. _Apache: http://httpd.apache.org/
|
||||||
.. _lighttpd: http://www.lighttpd.net/
|
.. _lighttpd: http://www.lighttpd.net/
|
||||||
|
@ -22,23 +27,25 @@ Using this method is **inefficient** and **insecure**. Do not use this in a
|
||||||
production setting. Use this only for development.
|
production setting. Use this only for development.
|
||||||
|
|
||||||
For information on serving static files in an Apache production environment,
|
For information on serving static files in an Apache production environment,
|
||||||
see the `Django mod_python documentation`_.
|
see the :ref:`Django mod_python documentation <serving-media-files>`.
|
||||||
|
|
||||||
.. _Django mod_python documentation: ../modpython/#serving-media-files
|
|
||||||
|
|
||||||
How to do it
|
How to do it
|
||||||
============
|
============
|
||||||
|
|
||||||
Just put this in your URLconf_::
|
Here's the formal definition of the :func:`~django.views.static.serve` view:
|
||||||
|
|
||||||
|
.. function:: def serve(request, path, document_root, show_indexes=False):
|
||||||
|
|
||||||
|
To use it, just put this in your :ref:`URLconf <topics-http-urls>`::
|
||||||
|
|
||||||
(r'^site_media/(?P<path>.*)$', 'django.views.static.serve', {'document_root': '/path/to/media'}),
|
(r'^site_media/(?P<path>.*)$', 'django.views.static.serve', {'document_root': '/path/to/media'}),
|
||||||
|
|
||||||
...where ``site_media`` is the URL where your media will be rooted, and
|
...where ``site_media`` is the URL where your media will be rooted, and
|
||||||
``/path/to/media`` is the filesystem root for your media.
|
``/path/to/media`` is the filesystem root for your media. This will call the
|
||||||
|
:func:`~django.views.static.serve` view, passing in the path from the URLconf
|
||||||
|
and the (required) ``document_root`` parameter.
|
||||||
|
|
||||||
You must pass a ``document_root`` parameter to indicate the filesystem root.
|
Given the above URLconf:
|
||||||
|
|
||||||
Examples:
|
|
||||||
|
|
||||||
* The file ``/path/to/media/foo.jpg`` will be made available at the URL
|
* The file ``/path/to/media/foo.jpg`` will be made available at the URL
|
||||||
``/site_media/foo.jpg``.
|
``/site_media/foo.jpg``.
|
||||||
|
@ -49,26 +56,27 @@ Examples:
|
||||||
* The file ``/path/bar.jpg`` will not be accessible, because it doesn't
|
* The file ``/path/bar.jpg`` will not be accessible, because it doesn't
|
||||||
fall under the document root.
|
fall under the document root.
|
||||||
|
|
||||||
.. _URLconf: ../url_dispatch/
|
|
||||||
|
|
||||||
Directory listings
|
Directory listings
|
||||||
==================
|
==================
|
||||||
|
|
||||||
Optionally, you can pass a ``show_indexes`` parameter to the ``static.serve``
|
Optionally, you can pass the ``show_indexes`` parameter to the
|
||||||
view. This is ``False`` by default. If it's ``True``, Django will display file
|
:func:`~django.views.static.serve` view. This is ``False`` by default. If it's
|
||||||
listings for directories.
|
``True``, Django will display file listings for directories.
|
||||||
|
|
||||||
Example::
|
For example::
|
||||||
|
|
||||||
(r'^site_media/(?P<path>.*)$', 'django.views.static.serve', {'document_root': '/path/to/media', 'show_indexes': True}),
|
(r'^site_media/(?P<path>.*)$', 'django.views.static.serve', {'document_root': '/path/to/media', 'show_indexes': True}),
|
||||||
|
|
||||||
You can customize the index view by creating a template called
|
You can customize the index view by creating a template called
|
||||||
``static/directory_index``. That template gets two objects in its context:
|
``static/directory_index.html``. That template gets two objects in its context:
|
||||||
|
|
||||||
* ``directory`` -- the directory name (a string)
|
* ``directory`` -- the directory name (a string)
|
||||||
* ``file_list`` -- a list of file names (as strings) in the directory
|
* ``file_list`` -- a list of file names (as strings) in the directory
|
||||||
|
|
||||||
Here's the default ``static/directory_index`` template::
|
Here's the default ``static/directory_index`` template:
|
||||||
|
|
||||||
|
.. code-block:: html+django
|
||||||
|
|
||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||||
|
@ -97,7 +105,7 @@ trick to make sure the static-serving view doesn't slip into a production
|
||||||
setting by mistake.
|
setting by mistake.
|
||||||
|
|
||||||
Do this by wrapping an ``if DEBUG`` statement around the
|
Do this by wrapping an ``if DEBUG`` statement around the
|
||||||
``django.views.static.serve`` inclusion. Here's a full example URLconf::
|
:func:`django.views.static.serve` inclusion. Here's a full example URLconf::
|
||||||
|
|
||||||
from django.conf.urls.defaults import *
|
from django.conf.urls.defaults import *
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
@ -115,11 +123,9 @@ Do this by wrapping an ``if DEBUG`` statement around the
|
||||||
)
|
)
|
||||||
|
|
||||||
This code is straightforward. It imports the settings and checks the value of
|
This code is straightforward. It imports the settings and checks the value of
|
||||||
the ``DEBUG`` setting. If it evaluates to ``True``, then ``site_media`` will be
|
the :setting:`DEBUG` setting. If it evaluates to ``True``, then ``site_media``
|
||||||
associated with the ``django.views.static.serve`` view. If not
|
will be associated with the ``django.views.static.serve`` view. If not, then the
|
||||||
(``DEBUG == False``), then the view won't be made available.
|
view won't be made available.
|
||||||
|
|
||||||
Of course, the catch here is that you'll have to remember to set ``DEBUG=False``
|
Of course, the catch here is that you'll have to remember to set ``DEBUG=False``
|
||||||
in your production settings file. But you should be doing that anyway.
|
in your production settings file. But you should be doing that anyway.
|
||||||
|
|
||||||
.. _DEBUG setting: ../settings/#debug
|
|
256
docs/index.txt
|
@ -1,134 +1,162 @@
|
||||||
|
.. _index:
|
||||||
|
|
||||||
====================
|
====================
|
||||||
Django Documentation
|
Django documentation
|
||||||
====================
|
====================
|
||||||
|
|
||||||
The essential documentation
|
.. rubric:: Everything you need to know about Django (and then some).
|
||||||
===========================
|
|
||||||
|
|
||||||
If you're new to Django, make sure to read the following documentation in
|
Getting help
|
||||||
order.. The rest (in the "reference" section below) can be ready in any order as
|
============
|
||||||
you need various functionality.
|
|
||||||
|
|
||||||
.. toctree::
|
Having trouble? We'd like to help!
|
||||||
:maxdepth: 1
|
|
||||||
|
|
||||||
overview
|
* Try the :ref:`FAQ <faq-index>` -- it's got answers to many common questions.
|
||||||
install
|
|
||||||
tutorial01
|
* Looking for specific information? Try the :ref:`genindex`, :ref:`modindex` or
|
||||||
tutorial02
|
the :ref:`detailed table of contents <contents>`.
|
||||||
tutorial03
|
|
||||||
tutorial04
|
* Search for information in the `archives of the django-users mailing list`_, or
|
||||||
faq
|
`post a question`_
|
||||||
documentation
|
|
||||||
|
* Ask a question in the `#django IRC channel`_, or search the `IRC logs`_ to see
|
||||||
|
if its been asked before
|
||||||
|
|
||||||
|
* Report bugs with Django in our `ticket tracker`_.
|
||||||
|
|
||||||
|
.. _archives of the django-users mailing list: http://groups.google.com/group/django-users/
|
||||||
|
.. _post a question: http://groups.google.com/group/django-users/
|
||||||
|
.. _#django IRC channel: irc://irc.freenode.net/django
|
||||||
|
.. _IRC logs: http://oebfare.com/logger/django/
|
||||||
|
.. _ticket tracker: http://code.djangoproject.com/
|
||||||
|
|
||||||
|
First steps
|
||||||
|
===========
|
||||||
|
|
||||||
|
:ref:`Overview <intro-overview>`
|
||||||
|
See what writing a database-driven application with Django looks like.
|
||||||
|
|
||||||
|
:ref:`Installation <intro-install>`
|
||||||
|
Get Django installed on your computer.
|
||||||
|
|
||||||
|
Tutorial: Writing your first Django application
|
||||||
|
===============================================
|
||||||
|
|
||||||
|
:ref:`Part 1 <intro-tutorial01>`
|
||||||
|
Get set up, create models, and play with the database API.
|
||||||
|
|
||||||
|
:ref:`Part 2 <intro-tutorial02>`
|
||||||
|
Explore the automatically-generated admin site.
|
||||||
|
|
||||||
|
:ref:`Part 3 <intro-tutorial03>`
|
||||||
|
Write the public interface views.
|
||||||
|
|
||||||
|
:ref:`Part 4 <intro-tutorial04>`
|
||||||
|
Learn how to process forms.
|
||||||
|
|
||||||
|
Using Django
|
||||||
|
============
|
||||||
|
|
||||||
|
:ref:`Models <topics-db-index>`
|
||||||
|
Design a single, definitive source of data about your data.
|
||||||
|
|
||||||
|
:ref:`Handling web requests <topics-http-index>`
|
||||||
|
Handle web requests, map them to views, and return pages.
|
||||||
|
|
||||||
|
:ref:`Forms <topics-forms-index>`
|
||||||
|
Build and handle HTML forms.
|
||||||
|
|
||||||
|
:ref:`Templates <topics-templates>`
|
||||||
|
Develop the visual design of your site.
|
||||||
|
|
||||||
|
And more:
|
||||||
|
---------
|
||||||
|
|
||||||
|
:ref:`topics-auth` ... :ref:`topics-cache` ... :ref:`topics-email` ...
|
||||||
|
:ref:`topics-files` ... :ref:`topics-i18n` ... :ref:`topics-install` ...
|
||||||
|
:ref:`topics-pagination` ... :ref:`topics-serialization` ...
|
||||||
|
:ref:`topics-settings` ... :ref:`topics-testing`
|
||||||
|
|
||||||
|
Add-on ("contrib") applications
|
||||||
|
===============================
|
||||||
|
|
||||||
|
:ref:`Django's automatic admin site <ref-contrib-admin>`
|
||||||
|
Get a clean interface to your data with no effort at all.
|
||||||
|
|
||||||
|
:ref:`Form tools <ref-contrib-formtools-index>`
|
||||||
|
Easily handle complex form workflows.
|
||||||
|
|
||||||
|
:ref:`Syndication feeds <ref-contrib-syndication>`
|
||||||
|
Generate RSS and Atom feeds of your data.
|
||||||
|
|
||||||
|
:ref:`"Local flavor" <ref-contrib-localflavor>`
|
||||||
|
Give your site that special local touch.
|
||||||
|
|
||||||
|
And more:
|
||||||
|
---------
|
||||||
|
|
||||||
|
:ref:`ref-contrib-contenttypes` ... :ref:`ref-contrib-csrf` ...
|
||||||
|
:ref:`ref-contrib-databrowse` ... :ref:`ref-contrib-flatpages` ...
|
||||||
|
:ref:`ref-contrib-humanize` ... :ref:`ref-contrib-redirects` ...
|
||||||
|
:ref:`ref-contrib-sitemaps` ... :ref:`ref-contrib-sites` ...
|
||||||
|
:ref:`ref-contrib-webdesign`
|
||||||
|
|
||||||
|
Solving specific problems
|
||||||
|
=========================
|
||||||
|
|
||||||
|
:ref:`Deployment <howto-deployment-index>`
|
||||||
|
Release your project to the world.
|
||||||
|
|
||||||
|
:ref:`Importing data from legacy databases <howto-legacy-databases>`
|
||||||
|
Use Django with an existing database or alongside other web development
|
||||||
|
toolkits.
|
||||||
|
|
||||||
|
:ref:`Custom template tags <howto-custom-template-tags>`
|
||||||
|
Add your own extensions to Django's template language.
|
||||||
|
|
||||||
|
:ref:`Generating CSV <howto-outputting-csv>` & :ref:`PDF <howto-outputting-PDF>`
|
||||||
|
Produce non-HTML content with Django.
|
||||||
|
|
||||||
|
And more:
|
||||||
|
---------
|
||||||
|
|
||||||
|
:ref:`Authenticating in Apache <howto-apache-auth>` ...
|
||||||
|
:ref:`howto-custom-file-storage` ... :ref:`howto-custom-management-commands` ...
|
||||||
|
:ref:`howto-custom-model-fields` ... :ref:`howto-error-reporting` ...
|
||||||
|
:ref:`howto-initial-data` ... :ref:`howto-static-files`
|
||||||
|
|
||||||
Reference
|
Reference
|
||||||
=========
|
=========
|
||||||
|
|
||||||
.. toctree::
|
:ref:`Settings <ref-settings>`
|
||||||
:maxdepth: 1
|
See all of Django's settings and what they do.
|
||||||
|
|
||||||
django-admin
|
:ref:`Request & response objects <ref-request-response>`
|
||||||
model-api
|
Understand the classes Django uses to represent HTTP requests and responses.
|
||||||
db-api
|
|
||||||
transactions
|
|
||||||
templates
|
|
||||||
templates_python
|
|
||||||
forms
|
|
||||||
modelforms
|
|
||||||
files
|
|
||||||
upload_handling
|
|
||||||
testing
|
|
||||||
sessions
|
|
||||||
cache
|
|
||||||
settings
|
|
||||||
url_dispatch
|
|
||||||
request_response
|
|
||||||
generic_views
|
|
||||||
authentication
|
|
||||||
shortcuts
|
|
||||||
unicode
|
|
||||||
pagination
|
|
||||||
serialization
|
|
||||||
i18n
|
|
||||||
middleware
|
|
||||||
custom_model_fields
|
|
||||||
databases
|
|
||||||
|
|
||||||
``django.contrib`` add-ons
|
:ref:`Model API reference <ref-models-index>`
|
||||||
--------------------------
|
Revel in the gory details of Django's model system.
|
||||||
|
|
||||||
.. toctree::
|
:ref:`Form API reference <ref-forms-index>`
|
||||||
:maxdepth: 1
|
Learn the details of forms, fields, and widgets.
|
||||||
|
|
||||||
admin
|
And more:
|
||||||
add_ons
|
|
||||||
contenttypes
|
|
||||||
csrf
|
|
||||||
databrowse
|
|
||||||
flatpages
|
|
||||||
form_preview
|
|
||||||
form_wizard
|
|
||||||
localflavor
|
|
||||||
redirects
|
|
||||||
sites
|
|
||||||
sitemaps
|
|
||||||
syndication_feeds
|
|
||||||
webdesign
|
|
||||||
|
|
||||||
Deployment
|
|
||||||
----------
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 1
|
|
||||||
|
|
||||||
modpython
|
|
||||||
fastcgi
|
|
||||||
|
|
||||||
Solving specific problems
|
|
||||||
-------------------------
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 1
|
|
||||||
|
|
||||||
apache_auth
|
|
||||||
static_files
|
|
||||||
email
|
|
||||||
legacy_databases
|
|
||||||
outputting_pdf
|
|
||||||
outputting_csv
|
|
||||||
|
|
||||||
Et cetera
|
|
||||||
---------
|
---------
|
||||||
|
|
||||||
.. toctree::
|
:ref:`ref-databases` ... :ref:`ref-django-admin` ... :ref:`ref-files-index` ...
|
||||||
:maxdepth: 1
|
:ref:`ref-generic-views` ... :ref:`ref-middleware` ...
|
||||||
|
:ref:`ref-templates-index` ... :ref:`ref-unicode`
|
||||||
|
|
||||||
design_philosophies
|
And all the rest
|
||||||
contributing
|
================
|
||||||
admin_css
|
|
||||||
api_stability
|
|
||||||
distributions
|
|
||||||
|
|
||||||
Release notes
|
:ref:`Internals <internals-index>`
|
||||||
-------------
|
Learn how Django works under the hood, and how you can contribute to the
|
||||||
|
project.
|
||||||
|
|
||||||
.. toctree::
|
:ref:`Release notes <releases-index>`
|
||||||
:maxdepth: 1
|
See what is and was new in each release of Django.
|
||||||
|
|
||||||
release_notes_0.96
|
|
||||||
release_notes_0.95
|
|
||||||
release_notes_1.0_alpha
|
|
||||||
release_notes_1.0_alpha_2
|
|
||||||
|
|
||||||
Also see the list of `backwards-incompatible changes`__ for changes made between
|
|
||||||
releases.
|
|
||||||
|
|
||||||
__ http://code.djangoproject.com/wiki/BackwardsIncompatibleChanges
|
|
||||||
|
|
||||||
Indices and tables
|
|
||||||
==================
|
|
||||||
|
|
||||||
* :ref:`genindex`
|
|
||||||
* :ref:`modindex`
|
|
||||||
* :ref:`search`
|
|
||||||
|
|
||||||
|
:ref:`Miscellany <misc-index>`
|
||||||
|
Stuff we can't find a more organized place for. Like that drawer in your
|
||||||
|
kitchen with the scissors, batteries, and duct tape.
|
||||||
|
|
After Width: | Height: | Size: 51 KiB |
|
@ -1,3 +1,5 @@
|
||||||
|
.. _internals-contributing:
|
||||||
|
|
||||||
======================
|
======================
|
||||||
Contributing to Django
|
Contributing to Django
|
||||||
======================
|
======================
|
||||||
|
@ -30,6 +32,8 @@ community. The rest of this document describes the details of how our community
|
||||||
works and how it handles bugs, mailing lists, and all the other minutiae of
|
works and how it handles bugs, mailing lists, and all the other minutiae of
|
||||||
Django development.
|
Django development.
|
||||||
|
|
||||||
|
.. _reporting-bugs:
|
||||||
|
|
||||||
Reporting bugs
|
Reporting bugs
|
||||||
==============
|
==============
|
||||||
|
|
||||||
|
@ -38,7 +42,7 @@ amount of overhead involved in working with any bug tracking system, so your
|
||||||
help in keeping our ticket tracker as useful as possible is appreciated. In
|
help in keeping our ticket tracker as useful as possible is appreciated. In
|
||||||
particular:
|
particular:
|
||||||
|
|
||||||
* **Do** read the FAQ_ to see if your issue might be a well-known question.
|
* **Do** read the :ref:`FAQ <faq-index>` to see if your issue might be a well-known question.
|
||||||
|
|
||||||
* **Do** `search the tracker`_ to see if your issue has already been filed.
|
* **Do** `search the tracker`_ to see if your issue has already been filed.
|
||||||
|
|
||||||
|
@ -74,6 +78,8 @@ particular:
|
||||||
|
|
||||||
.. _django-updates: http://groups.google.com/group/django-updates
|
.. _django-updates: http://groups.google.com/group/django-updates
|
||||||
|
|
||||||
|
.. _reporting-security-issues:
|
||||||
|
|
||||||
Reporting security issues
|
Reporting security issues
|
||||||
=========================
|
=========================
|
||||||
|
|
||||||
|
@ -231,7 +237,7 @@ ticket is waiting on.
|
||||||
|
|
||||||
Since a picture is worth a thousand words, let's start there:
|
Since a picture is worth a thousand words, let's start there:
|
||||||
|
|
||||||
.. image:: http://media.djangoproject.com/img/doc/djangotickets.png
|
.. image:: _images/djangotickets.png
|
||||||
:height: 451
|
:height: 451
|
||||||
:width: 590
|
:width: 590
|
||||||
:alt: Django's ticket workflow
|
:alt: Django's ticket workflow
|
||||||
|
@ -377,6 +383,8 @@ the ticket database:
|
||||||
be making a change, don't make the change -- leave a comment with your
|
be making a change, don't make the change -- leave a comment with your
|
||||||
concerns on the ticket, or post a message to `django-developers`_.
|
concerns on the ticket, or post a message to `django-developers`_.
|
||||||
|
|
||||||
|
.. _contributing-translations:
|
||||||
|
|
||||||
Submitting and maintaining translations
|
Submitting and maintaining translations
|
||||||
=======================================
|
=======================================
|
||||||
|
|
||||||
|
@ -390,21 +398,20 @@ translated, here's what to do:
|
||||||
|
|
||||||
* Join the `Django i18n mailing list`_ and introduce yourself.
|
* Join the `Django i18n mailing list`_ and introduce yourself.
|
||||||
* Create translations using the methods described in the
|
* Create translations using the methods described in the
|
||||||
`i18n documentation`_.
|
:ref:`i18n documentation <topics-i18n>`.
|
||||||
* Create a diff of the ``.po`` file against the current Subversion trunk.
|
* Create a diff of the ``.po`` file against the current Subversion trunk.
|
||||||
* Make sure that `` django-admin.py compilemessages -l <lang>`` runs without
|
* Make sure that `` django-admin.py compilemessages -l <lang>`` runs without
|
||||||
producing any warnings.
|
producing any warnings.
|
||||||
* Attach the patch to a ticket in Django's ticket system.
|
* Attach the patch to a ticket in Django's ticket system.
|
||||||
|
|
||||||
.. _Django i18n mailing list: http://groups.google.com/group/django-i18n/
|
.. _Django i18n mailing list: http://groups.google.com/group/django-i18n/
|
||||||
.. _i18n documentation: ../i18n/
|
|
||||||
|
|
||||||
Coding style
|
Coding style
|
||||||
============
|
============
|
||||||
|
|
||||||
Please follow these coding standards when writing code for inclusion in Django:
|
Please follow these coding standards when writing code for inclusion in Django:
|
||||||
|
|
||||||
* Unless otherwise specified, follow `PEP 8`_.
|
* Unless otherwise specified, follow :pep:8.
|
||||||
|
|
||||||
You could use a tool like `pep8.py`_ to check for some problems in this
|
You could use a tool like `pep8.py`_ to check for some problems in this
|
||||||
area, but remember that PEP 8 is only a guide, so respect the style of
|
area, but remember that PEP 8 is only a guide, so respect the style of
|
||||||
|
@ -418,8 +425,8 @@ Please follow these coding standards when writing code for inclusion in Django:
|
||||||
* Use ``InitialCaps`` for class names (or for factory functions that
|
* Use ``InitialCaps`` for class names (or for factory functions that
|
||||||
return classes).
|
return classes).
|
||||||
|
|
||||||
* Mark all strings for internationalization; see the `i18n documentation`_
|
* Mark all strings for internationalization; see the :ref:`i18n
|
||||||
for details.
|
documentation <topics-i18n>` for details.
|
||||||
|
|
||||||
* In docstrings, use "action words" such as::
|
* In docstrings, use "action words" such as::
|
||||||
|
|
||||||
|
@ -449,11 +456,15 @@ Template style
|
||||||
* In Django template code, put one (and only one) space between the curly
|
* In Django template code, put one (and only one) space between the curly
|
||||||
brackets and the tag contents.
|
brackets and the tag contents.
|
||||||
|
|
||||||
Do this::
|
Do this:
|
||||||
|
|
||||||
|
.. code-block:: html+django
|
||||||
|
|
||||||
{{ foo }}
|
{{ foo }}
|
||||||
|
|
||||||
Don't do this::
|
Don't do this:
|
||||||
|
|
||||||
|
.. code-block:: html+django
|
||||||
|
|
||||||
{{foo}}
|
{{foo}}
|
||||||
|
|
||||||
|
@ -706,15 +717,15 @@ The tests cover:
|
||||||
We appreciate any and all contributions to the test suite!
|
We appreciate any and all contributions to the test suite!
|
||||||
|
|
||||||
The Django tests all use the testing infrastructure that ships with Django for
|
The Django tests all use the testing infrastructure that ships with Django for
|
||||||
testing applications. See `Testing Django applications`_ for an explanation of
|
testing applications. See :ref:`Testing Django applications <topics-testing>`
|
||||||
how to write new tests.
|
for an explanation of how to write new tests.
|
||||||
|
|
||||||
.. _Testing Django applications: ../testing/
|
|
||||||
|
|
||||||
Running the unit tests
|
Running the unit tests
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
To run the tests, ``cd`` to the ``tests/`` directory and type::
|
To run the tests, ``cd`` to the ``tests/`` directory and type:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
./runtests.py --settings=path.to.django.settings
|
./runtests.py --settings=path.to.django.settings
|
||||||
|
|
||||||
|
@ -727,13 +738,13 @@ needed. A temporary database will be created in memory when running the tests.
|
||||||
|
|
||||||
If you're using another backend:
|
If you're using another backend:
|
||||||
|
|
||||||
* Your ``DATABASE_USER`` setting needs to specify an existing user account
|
* Your :setting:`DATABASE_USER` setting needs to specify an existing user account
|
||||||
for the database engine.
|
for the database engine.
|
||||||
|
|
||||||
* The ``DATABASE_NAME`` setting must be the name of an existing database to
|
* The :setting:`DATABASE_NAME` setting must be the name of an existing database to
|
||||||
which the given user has permission to connect. The unit tests will not
|
which the given user has permission to connect. The unit tests will not
|
||||||
touch this database; the test runner creates a new database whose name is
|
touch this database; the test runner creates a new database whose name is
|
||||||
``DATABASE_NAME`` prefixed with ``test_``, and this test database is
|
:setting:`DATABASE_NAME` prefixed with ``test_``, and this test database is
|
||||||
deleted when the tests are finished. This means your user account needs
|
deleted when the tests are finished. This means your user account needs
|
||||||
permission to execute ``CREATE DATABASE``.
|
permission to execute ``CREATE DATABASE``.
|
||||||
|
|
||||||
|
@ -766,7 +777,9 @@ To run a subset of the unit tests, append the names of the test modules to the
|
||||||
|
|
||||||
As an example, if Django is not in your ``PYTHONPATH``, you placed
|
As an example, if Django is not in your ``PYTHONPATH``, you placed
|
||||||
``settings.py`` in the ``tests/`` directory, and you'd like to only run tests
|
``settings.py`` in the ``tests/`` directory, and you'd like to only run tests
|
||||||
for generic relations and internationalization, type::
|
for generic relations and internationalization, type:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
PYTHONPATH=..
|
PYTHONPATH=..
|
||||||
./runtests.py --settings=settings generic_relations i18n
|
./runtests.py --settings=settings generic_relations i18n
|
||||||
|
@ -787,6 +800,7 @@ method as above::
|
||||||
|
|
||||||
./runtests.py --settings=settings markup
|
./runtests.py --settings=settings markup
|
||||||
|
|
||||||
|
|
||||||
Requesting features
|
Requesting features
|
||||||
===================
|
===================
|
||||||
|
|
||||||
|
@ -854,7 +868,9 @@ To use a branch, you'll need to do two things:
|
||||||
Getting the code from Subversion
|
Getting the code from Subversion
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
To get the latest version of a branch's code, check it out using Subversion::
|
To get the latest version of a branch's code, check it out using Subversion:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
svn co http://code.djangoproject.com/svn/django/branches/<branch>/
|
svn co http://code.djangoproject.com/svn/django/branches/<branch>/
|
||||||
|
|
||||||
|
@ -862,7 +878,9 @@ To get the latest version of a branch's code, check it out using Subversion::
|
||||||
|
|
||||||
Alternatively, you can automatically convert an existing directory of the
|
Alternatively, you can automatically convert an existing directory of the
|
||||||
Django source code as long as you've checked it out via Subversion. To do the
|
Django source code as long as you've checked it out via Subversion. To do the
|
||||||
conversion, execute this command from within your ``django`` directory::
|
conversion, execute this command from within your ``django`` directory:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
svn switch http://code.djangoproject.com/svn/django/branches/<branch>/
|
svn switch http://code.djangoproject.com/svn/django/branches/<branch>/
|
||||||
|
|
||||||
|
@ -1025,12 +1043,10 @@ requests for commit access are potential flame-war starters, and will be ignored
|
||||||
.. _community page: http://www.djangoproject.com/community/
|
.. _community page: http://www.djangoproject.com/community/
|
||||||
.. _ticket tracker: http://code.djangoproject.com/newticket
|
.. _ticket tracker: http://code.djangoproject.com/newticket
|
||||||
.. _django-developers: http://groups.google.com/group/django-developers
|
.. _django-developers: http://groups.google.com/group/django-developers
|
||||||
.. _FAQ: http://www.djangoproject.com/documentation/faq/
|
|
||||||
.. _search the tracker: http://code.djangoproject.com/search
|
.. _search the tracker: http://code.djangoproject.com/search
|
||||||
.. _django-users: http://groups.google.com/group/django-users
|
.. _django-users: http://groups.google.com/group/django-users
|
||||||
.. _`#django`: irc://irc.freenode.net/django
|
.. _`#django`: irc://irc.freenode.net/django
|
||||||
.. _list of tickets with patches: http://code.djangoproject.com/query?status=new&status=assigned&status=reopened&has_patch=1&order=priority
|
.. _list of tickets with patches: http://code.djangoproject.com/query?status=new&status=assigned&status=reopened&has_patch=1&order=priority
|
||||||
.. _PEP 8: http://www.python.org/peps/pep-0008.html
|
|
||||||
.. _pep8.py: http://svn.browsershots.org/trunk/devtools/pep8/pep8.py
|
.. _pep8.py: http://svn.browsershots.org/trunk/devtools/pep8/pep8.py
|
||||||
.. _i18n branch: http://code.djangoproject.com/browser/django/branches/i18n
|
.. _i18n branch: http://code.djangoproject.com/browser/django/branches/i18n
|
||||||
.. _`tags/releases`: http://code.djangoproject.com/browser/django/tags/releases
|
.. _`tags/releases`: http://code.djangoproject.com/browser/django/tags/releases
|
|
@ -0,0 +1,204 @@
|
||||||
|
.. _internals-documentation:
|
||||||
|
|
||||||
|
How the Django documentation works
|
||||||
|
==================================
|
||||||
|
|
||||||
|
\... and how to contribute.
|
||||||
|
|
||||||
|
Django's documentation uses the Sphinx__ documentation system, which in turn is
|
||||||
|
based on docutils__. The basic idea is that lightly-formatted plain-text
|
||||||
|
documentation is transformed into HTML, PDF, and any other output format.
|
||||||
|
|
||||||
|
__ http://sphinx.pocoo.org/
|
||||||
|
__ http://docutils.sf.net/
|
||||||
|
|
||||||
|
To actually build the documentation locally, you'll currently need to install
|
||||||
|
Sphinx -- ``easy_install Sphinx`` should do the trick.
|
||||||
|
|
||||||
|
Then, building the html is easy; just ``make html`` from the ``docs`` directory.
|
||||||
|
|
||||||
|
To get started contributing, you'll want to read the `ReStructuredText
|
||||||
|
Primer`__. After that, you'll want to read about the `Sphinx-specific markup`__
|
||||||
|
that's used to manage metadata, indexing, and cross-references.
|
||||||
|
|
||||||
|
__ http://sphinx.pocoo.org/rest.html
|
||||||
|
__ http://sphinx.pocoo.org/markup/
|
||||||
|
|
||||||
|
The main thing to keep in mind as you write and edit docs is that the more
|
||||||
|
semantic markup you can add the better. So::
|
||||||
|
|
||||||
|
Add ``django.contrib.auth`` to your ``INSTALLED_APPS``...
|
||||||
|
|
||||||
|
Isn't nearly as helpful as::
|
||||||
|
|
||||||
|
Add :mod:`django.contrib.auth` to your :setting:`INSTALLED_APPS`...
|
||||||
|
|
||||||
|
This is because Sphinx will generate proper links for the later, which greatly
|
||||||
|
helps readers. There's basically no limit to the amount of useful markup you can
|
||||||
|
add.
|
||||||
|
|
||||||
|
Django-specific markup
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
Besides the `Sphinx built-in markup`__, Django's docs defines some extra description units:
|
||||||
|
|
||||||
|
__ http://sphinx.pocoo.org/markup/desc.html
|
||||||
|
|
||||||
|
* Settings::
|
||||||
|
|
||||||
|
.. setting:: INSTALLED_APPS
|
||||||
|
|
||||||
|
To link to a setting, use ``:setting:`INSTALLED_APPS```.
|
||||||
|
|
||||||
|
* Template tags::
|
||||||
|
|
||||||
|
.. templatetag:: regroup
|
||||||
|
|
||||||
|
To link, use ``:ttag:`regroup```.
|
||||||
|
|
||||||
|
* Template filters::
|
||||||
|
|
||||||
|
.. templatefilter:: linebreaksbr
|
||||||
|
|
||||||
|
To link, use ``:tfilter:`linebreaksbr```.
|
||||||
|
|
||||||
|
* Field lookups (i.e. ``Foo.objects.filter(bar__exact=whatever)``)::
|
||||||
|
|
||||||
|
.. fieldlookup:: exact
|
||||||
|
|
||||||
|
To link, use ``:lookup:`exact```.
|
||||||
|
|
||||||
|
* ``django-admin`` commands::
|
||||||
|
|
||||||
|
.. django-admin:: syncdb
|
||||||
|
|
||||||
|
To link, use ``:djadmin:`syncdb```.
|
||||||
|
|
||||||
|
* ``django-admin`` command-line options::
|
||||||
|
|
||||||
|
.. django-admin-option:: --traceback
|
||||||
|
|
||||||
|
To link, use ``:djadminopt:`--traceback```.
|
||||||
|
|
||||||
|
An example
|
||||||
|
----------
|
||||||
|
|
||||||
|
For a quick example of how it all fits together, check this out:
|
||||||
|
|
||||||
|
* First, the ``ref/settings.txt`` document starts out like this::
|
||||||
|
|
||||||
|
.. _ref-settings:
|
||||||
|
|
||||||
|
Available settings
|
||||||
|
==================
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
* Next, if you look at the ``topics/settings.txt`` document, you can see how
|
||||||
|
a link to ``ref/settings`` works::
|
||||||
|
|
||||||
|
Available settings
|
||||||
|
==================
|
||||||
|
|
||||||
|
For a full list of available settings, see the :ref:`settings reference
|
||||||
|
<ref-settings>`.
|
||||||
|
|
||||||
|
* Next, notice how the settings (right now just the top few) are annotated::
|
||||||
|
|
||||||
|
.. setting:: ADMIN_FOR
|
||||||
|
|
||||||
|
ADMIN_FOR
|
||||||
|
---------
|
||||||
|
|
||||||
|
Default: ``()`` (Empty tuple)
|
||||||
|
|
||||||
|
Used for admin-site settings modules, this should be a tuple of settings
|
||||||
|
modules (in the format ``'foo.bar.baz'``) for which this site is an
|
||||||
|
admin.
|
||||||
|
|
||||||
|
The admin site uses this in its automatically-introspected
|
||||||
|
documentation of models, views and template tags.
|
||||||
|
|
||||||
|
This marks up the following header as the "canonical" target for the
|
||||||
|
setting ``ADMIN_FOR`` This means any time I talk about ``ADMIN_FOR``, I
|
||||||
|
can reference it using ``:setting:`ADMIN_FOR```.
|
||||||
|
|
||||||
|
That's basically how everything fits together.
|
||||||
|
|
||||||
|
TODO
|
||||||
|
----
|
||||||
|
|
||||||
|
The work is mostly done, but here's what's left, in rough order of priority.
|
||||||
|
|
||||||
|
* Fix up generic view docs: adapt Chapter 9 of the Django Book (consider
|
||||||
|
this TODO item my permission and license) into
|
||||||
|
``topics/generic-views.txt``; remove the intro material from
|
||||||
|
``ref/generic-views.txt`` and just leave the function reference.
|
||||||
|
|
||||||
|
* Change the "Added/changed in development version" callouts to proper
|
||||||
|
Sphinx ``.. versionadded::`` or ``.. versionchanged::`` directives.
|
||||||
|
|
||||||
|
* Check for and fix malformed links. Do this by running ``make linkcheck``
|
||||||
|
and fix all of the 300+ errors/warnings.
|
||||||
|
|
||||||
|
In particular, look at all the relative links; these need to be
|
||||||
|
changed to proper references.
|
||||||
|
|
||||||
|
* Most of the various ``index.txt`` documents have *very* short or even
|
||||||
|
non-existent intro text. Each of those documents needs a good short intro
|
||||||
|
the content below that point.
|
||||||
|
|
||||||
|
* The glossary is very perfunctory. It needs to be filled out.
|
||||||
|
|
||||||
|
* Add more metadata targets: there's lots of places that look like::
|
||||||
|
|
||||||
|
``File.close()``
|
||||||
|
~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
\... these should be::
|
||||||
|
|
||||||
|
.. method:: File.close()
|
||||||
|
|
||||||
|
That is, use metadata instead of titles.
|
||||||
|
|
||||||
|
* Add more links -- nearly everything that's an inline code literal
|
||||||
|
right now can probably be turned into a xref.
|
||||||
|
|
||||||
|
See the ``literals_to_xrefs.py`` file in ``_ext`` -- it's a shell script
|
||||||
|
to help do this work.
|
||||||
|
|
||||||
|
This will probably be a continuing, never-ending project.
|
||||||
|
|
||||||
|
* Add `info field lists`__ where appropriate.
|
||||||
|
|
||||||
|
__ http://sphinx.pocoo.org/markup/desc.html#info-field-lists
|
||||||
|
|
||||||
|
* Add ``.. code-block:: <lang>`` to literal blocks so that they get
|
||||||
|
highlighted.
|
||||||
|
|
||||||
|
Hints
|
||||||
|
-----
|
||||||
|
|
||||||
|
Some hints for making things look/read better:
|
||||||
|
|
||||||
|
* Whenever possible, use links. So, use ``:setting:`ADMIN_FOR``` instead of
|
||||||
|
````ADMIN_FOR````.
|
||||||
|
|
||||||
|
* Some directives (``.. setting::``, for one) are prefix-style directives;
|
||||||
|
they go *before* the unit they're describing. These are known as
|
||||||
|
"crossref" directives. Others (``.. class::``, e.g.) generate their own
|
||||||
|
markup; these should go inside the section they're describing. These are
|
||||||
|
called "description units".
|
||||||
|
|
||||||
|
You can tell which are which by looking at in :file:`_ext/djangodocs.py`;
|
||||||
|
it registers roles as one of the other.
|
||||||
|
|
||||||
|
* When referring to classes/functions/modules, etc., you'll want to use the
|
||||||
|
fully-qualified name of the target
|
||||||
|
(``:class:`django.contrib.contenttypes.models.ContentType```).
|
||||||
|
|
||||||
|
Since this doesn't look all that awesome in the output -- it shows the
|
||||||
|
entire path to the object -- you can prefix the target with a ``~``
|
||||||
|
(that's a tilde) to get just the "last bit" of that path. So
|
||||||
|
``:class:`~django.contrib.contenttypes.models.ContentType``` will just
|
||||||
|
display a link with the title "ContentType".
|
|
@ -0,0 +1,22 @@
|
||||||
|
.. _internals-index:
|
||||||
|
|
||||||
|
Django internals
|
||||||
|
================
|
||||||
|
|
||||||
|
Documentation for people hacking on Django itself. This is the place to go if
|
||||||
|
you'd like to help improve Django, learn or learn about how Django works "under
|
||||||
|
the hood".
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
Elsewhere in the Django documentation, coverage of a feature is a sort of a
|
||||||
|
contract: once an API is in the official documentation, we consider it
|
||||||
|
"stable" and don't change it without a good reason. APIs covered here,
|
||||||
|
however, are considered "internal-only": we reserve the right to change
|
||||||
|
these internals if we must.
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
|
||||||
|
contributing
|
||||||
|
documentation
|
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 28 KiB |
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 28 KiB |
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 31 KiB |
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 5.4 KiB |
After Width: | Height: | Size: 33 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 28 KiB |
After Width: | Height: | Size: 23 KiB |
|
@ -0,0 +1,38 @@
|
||||||
|
.. _intro-index:
|
||||||
|
|
||||||
|
Getting started
|
||||||
|
===============
|
||||||
|
|
||||||
|
New to Django? Or to web development in general? Well, you came to the right
|
||||||
|
place: read this material to quickly get up and running.
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
|
||||||
|
overview
|
||||||
|
install
|
||||||
|
tutorial01
|
||||||
|
tutorial02
|
||||||
|
tutorial03
|
||||||
|
tutorial04
|
||||||
|
whatsnext
|
||||||
|
|
||||||
|
.. seealso::
|
||||||
|
|
||||||
|
If you're new to Python_, you might want to start by getting an idea of what
|
||||||
|
the language is like. Django is 100% Python, so if you've got minimal
|
||||||
|
comfort with Python you'll probably get a lot more out of Django.
|
||||||
|
|
||||||
|
If you're new to programming entirely, you might want to start with this
|
||||||
|
`list of Python resources for non-programmers`_
|
||||||
|
|
||||||
|
If you already know a few other languages and want to get up to speed with
|
||||||
|
Python quickly, we recommend `Dive Into Python`_ (also available in a
|
||||||
|
`dead-tree version`_). If that's not quite your style, there are quite
|
||||||
|
a few other `books about Python`_.
|
||||||
|
|
||||||
|
.. _python: http://python.org/
|
||||||
|
.. _list of Python resources for non-programmers: http://wiki.python.org/moin/BeginnersGuide/NonProgrammers
|
||||||
|
.. _dive into python: http://diveintopython.org/
|
||||||
|
.. _dead-tree version: http://www.amazon.com/exec/obidos/ASIN/1590593561/ref=nosim/jacobian20
|
||||||
|
.. _books about Python: http://wiki.python.org/moin/PythonBooks
|
|
@ -0,0 +1,75 @@
|
||||||
|
.. _intro-install:
|
||||||
|
|
||||||
|
Quick install guide
|
||||||
|
===================
|
||||||
|
|
||||||
|
Before you can use Django, you'll need to get it installed. We have a
|
||||||
|
:ref:`complete installation guide <topics-install>` that covers all the
|
||||||
|
possibilities; this guide will guide you to a simple, minimal installation
|
||||||
|
that'll work while you walk through the introduction.
|
||||||
|
|
||||||
|
Install Python
|
||||||
|
--------------
|
||||||
|
|
||||||
|
Being a Python Web framework, Django requires Python. It works with any Python
|
||||||
|
version 2.3 and higher, but we recommend installing Python 2.5 or later. If you do so, you won't need to set up a database just yet: Python 2.5 or later includes a lightweight database called SQLite_.
|
||||||
|
|
||||||
|
.. _sqlite: http://sqlite.org/
|
||||||
|
|
||||||
|
Get Python at http://www.python.org. If you're running Linux or Mac OS X, you
|
||||||
|
probably already have it installed.
|
||||||
|
|
||||||
|
You can verify that Python's installed py typing ``python`` from your shell; you should see something like::
|
||||||
|
|
||||||
|
Python 2.5.1 (r251:54863, Jan 17 2008, 19:35:17)
|
||||||
|
[GCC 4.0.1 (Apple Inc. build 5465)] on darwin
|
||||||
|
Type "help", "copyright", "credits" or "license" for more information.
|
||||||
|
>>>
|
||||||
|
|
||||||
|
Set up a database
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
If you installed Python 2.5 or later, you can skip this step for now.
|
||||||
|
|
||||||
|
If not, or if you'd like to work with a "large" database engine like PostgreSQL,
|
||||||
|
MySQL, or Oracle, consult the :ref:`database installation information
|
||||||
|
<database-installation>`.
|
||||||
|
|
||||||
|
Remove any old versions of Django
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
If you are upgrading your installation of Django from a previous version, you
|
||||||
|
will need to :ref:`uninstall the old Django version before installing the new
|
||||||
|
version <removing-old-versions-of-django>`.
|
||||||
|
|
||||||
|
Install Django
|
||||||
|
--------------
|
||||||
|
|
||||||
|
You've got three easy options to install Django:
|
||||||
|
|
||||||
|
* Install a version of Django :ref:`provided by your operating system
|
||||||
|
distribution <misc-distributions>`. This is the quickest option for those
|
||||||
|
who have operating systems that distribute Django.
|
||||||
|
|
||||||
|
* :ref:`Install an official release <installing-official-release>`. This
|
||||||
|
is the best approach for users who want a stable version number and aren't
|
||||||
|
concerned about running a slightly older version of Django.
|
||||||
|
|
||||||
|
* :ref:`Install the latest development version
|
||||||
|
<installing-development-version>`. This is best for users who want the
|
||||||
|
latest-and-greatest features and aren't afraid of running brand-new code.
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
If do either of the first two steps, keep an eye out for parts of the
|
||||||
|
documentation marked **new in development version**. That phrase flags
|
||||||
|
features that are only available in development versions of Django; if you
|
||||||
|
try to use them with an official release they won't work.
|
||||||
|
|
||||||
|
That's it!
|
||||||
|
----------
|
||||||
|
|
||||||
|
That's it -- you can now :ref:`move onto the tutorial <intro-tutorial01>`.
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
.. _intro-overview:
|
||||||
|
|
||||||
==================
|
==================
|
||||||
Django at a glance
|
Django at a glance
|
||||||
==================
|
==================
|
||||||
|
@ -8,10 +10,9 @@ overview of how to write a database-driven Web app with Django.
|
||||||
|
|
||||||
The goal of this document is to give you enough technical specifics to
|
The goal of this document is to give you enough technical specifics to
|
||||||
understand how Django works, but this isn't intended to be a tutorial or
|
understand how Django works, but this isn't intended to be a tutorial or
|
||||||
reference. Please see our more-detailed Django documentation_ when you're ready
|
reference -- but we've got both! When you're ready to start a project, you can
|
||||||
to start a project.
|
:ref:`start with the tutorial <intro-tutorial01>` or :ref:`dive right into more
|
||||||
|
detailed documentation <topics-index>`.
|
||||||
.. _documentation: ../
|
|
||||||
|
|
||||||
Design your model
|
Design your model
|
||||||
=================
|
=================
|
||||||
|
@ -20,9 +21,9 @@ Although you can use Django without a database, it comes with an
|
||||||
object-relational mapper in which you describe your database layout in Python
|
object-relational mapper in which you describe your database layout in Python
|
||||||
code.
|
code.
|
||||||
|
|
||||||
The data-model syntax offers many rich ways of representing your models -- so
|
The :ref:`data-model syntax <topics-db-models>` offers many rich ways of
|
||||||
far, it's been solving two years' worth of database-schema problems. Here's a
|
representing your models -- so far, it's been solving two years' worth of
|
||||||
quick example::
|
database-schema problems. Here's a quick example::
|
||||||
|
|
||||||
class Reporter(models.Model):
|
class Reporter(models.Model):
|
||||||
full_name = models.CharField(max_length=70)
|
full_name = models.CharField(max_length=70)
|
||||||
|
@ -43,18 +44,20 @@ Install it
|
||||||
==========
|
==========
|
||||||
|
|
||||||
Next, run the Django command-line utility to create the database tables
|
Next, run the Django command-line utility to create the database tables
|
||||||
automatically::
|
automatically:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
manage.py syncdb
|
manage.py syncdb
|
||||||
|
|
||||||
The ``syncdb`` command looks at all your available models and creates tables
|
The :djadmin:`syncdb` command looks at all your available models and creates
|
||||||
in your database for whichever tables don't already exist.
|
tables in your database for whichever tables don't already exist.
|
||||||
|
|
||||||
Enjoy the free API
|
Enjoy the free API
|
||||||
==================
|
==================
|
||||||
|
|
||||||
With that, you've got a free, and rich, Python API to access your data. The API
|
With that, you've got a free, and rich, :ref:`Python API <topics-db-queries>` to
|
||||||
is created on the fly, no code generation necessary::
|
access your data. The API is created on the fly, no code generation necessary::
|
||||||
|
|
||||||
>>> from mysite.models import Reporter, Article
|
>>> from mysite.models import Reporter, Article
|
||||||
|
|
||||||
|
@ -128,15 +131,16 @@ A dynamic admin interface: it's not just scaffolding -- it's the whole house
|
||||||
============================================================================
|
============================================================================
|
||||||
|
|
||||||
Once your models are defined, Django can automatically create a professional,
|
Once your models are defined, Django can automatically create a professional,
|
||||||
production ready administrative interface -- a Web site that lets authenticated
|
production ready :ref:`administrative interface <ref-contrib-admin>` -- a Web
|
||||||
users add, change and delete objects. It's as easy as adding a line of code to
|
site that lets authenticated users add, change and delete objects. It's as easy
|
||||||
your model classes::
|
as adding a line of code to your model classes::
|
||||||
|
|
||||||
class Article(models.Model):
|
class Article(models.Model):
|
||||||
pub_date = models.DateTimeField()
|
pub_date = models.DateTimeField()
|
||||||
headline = models.CharField(max_length=200)
|
headline = models.CharField(max_length=200)
|
||||||
content = models.TextField()
|
content = models.TextField()
|
||||||
reporter = models.ForeignKey(Reporter)
|
reporter = models.ForeignKey(Reporter)
|
||||||
|
|
||||||
class Admin: pass
|
class Admin: pass
|
||||||
|
|
||||||
The philosophy here is that your site is edited by a staff, or a client, or
|
The philosophy here is that your site is edited by a staff, or a client, or
|
||||||
|
@ -154,10 +158,10 @@ A clean, elegant URL scheme is an important detail in a high-quality Web
|
||||||
application. Django encourages beautiful URL design and doesn't put any cruft
|
application. Django encourages beautiful URL design and doesn't put any cruft
|
||||||
in URLs, like ``.php`` or ``.asp``.
|
in URLs, like ``.php`` or ``.asp``.
|
||||||
|
|
||||||
To design URLs for an app, you create a Python module called a URLconf. A table
|
To design URLs for an app, you create a Python module called a :ref:`URLconf
|
||||||
of contents for your app, it contains a simple mapping between URL patterns and
|
<topics-http-urls>`. A table of contents for your app, it contains a simple mapping
|
||||||
Python callback functions. URLconfs also serve to decouple URLs from Python
|
between URL patterns and Python callback functions. URLconfs also serve to
|
||||||
code.
|
decouple URLs from Python code.
|
||||||
|
|
||||||
Here's what a URLconf might look like for the ``Reporter``/``Article``
|
Here's what a URLconf might look like for the ``Reporter``/``Article``
|
||||||
example above::
|
example above::
|
||||||
|
@ -190,8 +194,9 @@ Write your views
|
||||||
================
|
================
|
||||||
|
|
||||||
Each view is responsible for doing one of two things: Returning an
|
Each view is responsible for doing one of two things: Returning an
|
||||||
``HttpResponse`` object containing the content for the requested page, or
|
:class:`~django.http.HttpResponse` object containing the content for the
|
||||||
raising an exception such as ``Http404``. The rest is up to you.
|
requested page, or raising an exception such as :class:`~django.http.Http404`.
|
||||||
|
The rest is up to you.
|
||||||
|
|
||||||
Generally, a view retrieves data according to the parameters, loads a template
|
Generally, a view retrieves data according to the parameters, loads a template
|
||||||
and renders the template with the retrieved data. Here's an example view for
|
and renders the template with the retrieved data. Here's an example view for
|
||||||
|
@ -201,8 +206,9 @@ and renders the template with the retrieved data. Here's an example view for
|
||||||
a_list = Article.objects.filter(pub_date__year=year)
|
a_list = Article.objects.filter(pub_date__year=year)
|
||||||
return render_to_response('news/year_archive.html', {'year': year, 'article_list': a_list})
|
return render_to_response('news/year_archive.html', {'year': year, 'article_list': a_list})
|
||||||
|
|
||||||
This example uses Django's template system, which has several powerful
|
This example uses Django's :ref:`template system <topics-templates>`, which has
|
||||||
features but strives to stay simple enough for non-programmers to use.
|
several powerful features but strives to stay simple enough for non-programmers
|
||||||
|
to use.
|
||||||
|
|
||||||
Design your templates
|
Design your templates
|
||||||
=====================
|
=====================
|
||||||
|
@ -215,7 +221,9 @@ for templates. If a template doesn't exist in the first directory, it checks the
|
||||||
second, and so on.
|
second, and so on.
|
||||||
|
|
||||||
Let's say the ``news/article_detail.html`` template was found. Here's what that
|
Let's say the ``news/article_detail.html`` template was found. Here's what that
|
||||||
might look like::
|
might look like:
|
||||||
|
|
||||||
|
.. code-block:: html+django
|
||||||
|
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
@ -252,7 +260,9 @@ Finally, Django uses the concept of "template inheritance": That's what the
|
||||||
following blocks." In short, that lets you dramatically cut down on redundancy
|
following blocks." In short, that lets you dramatically cut down on redundancy
|
||||||
in templates: each template has to define only what's unique to that template.
|
in templates: each template has to define only what's unique to that template.
|
||||||
|
|
||||||
Here's what the "base.html" template might look like::
|
Here's what the "base.html" template might look like:
|
||||||
|
|
||||||
|
.. code-block:: html+django
|
||||||
|
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
|
@ -287,17 +297,18 @@ This is just the surface
|
||||||
This has been only a quick overview of Django's functionality. Some more useful
|
This has been only a quick overview of Django's functionality. Some more useful
|
||||||
features:
|
features:
|
||||||
|
|
||||||
* A caching framework that integrates with memcached or other backends.
|
* A :ref:`caching framework <topics-cache>` that integrates with memcached
|
||||||
* A `syndication framework`_ that makes creating RSS and Atom feeds as easy as
|
or other backends.
|
||||||
writing a small Python class.
|
|
||||||
|
* A :ref:`syndication framework <ref-contrib-syndication>` that makes
|
||||||
|
creating RSS and Atom feeds as easy as writing a small Python class.
|
||||||
|
|
||||||
* More sexy automatically-generated admin features -- this overview barely
|
* More sexy automatically-generated admin features -- this overview barely
|
||||||
scratched the surface.
|
scratched the surface.
|
||||||
|
|
||||||
.. _syndication framework: ../syndication_feeds/
|
The next obvious steps are for you to `download Django`_, read :ref:`the
|
||||||
|
tutorial <intro-tutorial01>` and join `the community`_. Thanks for your
|
||||||
The next obvious steps are for you to `download Django`_, read `the tutorial`_
|
interest!
|
||||||
and join `the community`_. Thanks for your interest!
|
|
||||||
|
|
||||||
.. _download Django: http://www.djangoproject.com/download/
|
.. _download Django: http://www.djangoproject.com/download/
|
||||||
.. _the tutorial: ../tutorial01/
|
|
||||||
.. _the community: http://www.djangoproject.com/community/
|
.. _the community: http://www.djangoproject.com/community/
|
|
@ -1,3 +1,5 @@
|
||||||
|
.. _intro-tutorial01:
|
||||||
|
|
||||||
=====================================
|
=====================================
|
||||||
Writing your first Django app, part 1
|
Writing your first Django app, part 1
|
||||||
=====================================
|
=====================================
|
||||||
|
@ -12,71 +14,70 @@ It'll consist of two parts:
|
||||||
* A public site that lets people view polls and vote in them.
|
* A public site that lets people view polls and vote in them.
|
||||||
* An admin site that lets you add, change and delete polls.
|
* An admin site that lets you add, change and delete polls.
|
||||||
|
|
||||||
We'll assume you have `Django installed`_ already. You can tell Django is
|
We'll assume you have :ref:`Django installed <intro-install>` already. You can
|
||||||
installed by running the Python interactive interpreter and typing
|
tell Django is installed by running the Python interactive interpreter and
|
||||||
``import django``. If that command runs successfully, with no errors, Django is
|
typing ``import django``. If that command runs successfully, with no errors,
|
||||||
installed.
|
Django is installed.
|
||||||
|
|
||||||
.. _`Django installed`: ../install/
|
|
||||||
|
|
||||||
.. admonition:: Where to get help:
|
.. admonition:: Where to get help:
|
||||||
|
|
||||||
If you're having trouble going through this tutorial, please post a message
|
If you're having trouble going through this tutorial, please post a message
|
||||||
to `django-users`_ or drop by `#django`_ on ``irc.freenode.net`` to chat
|
to `django-users`__ or drop by `#django on irc.freenode.net`__ to chat
|
||||||
with other Django users who might be able to help.
|
with other Django users who might be able to help.
|
||||||
|
|
||||||
.. _django-users: http://groups.google.com/group/django-users
|
__ http://groups.google.com/group/django-users
|
||||||
.. _#django: irc://irc.freenode.net/django
|
__ irc://irc.freenode.net/django
|
||||||
|
|
||||||
Creating a project
|
Creating a project
|
||||||
==================
|
==================
|
||||||
|
|
||||||
If this is your first time using Django, you'll have to take care of some
|
If this is your first time using Django, you'll have to take care of some
|
||||||
initial setup. Namely, you'll need to auto-generate some code that establishes
|
initial setup. Namely, you'll need to auto-generate some code that establishes a
|
||||||
a Django *project* -- a collection of settings for an instance of Django,
|
Django :term:`project` -- a collection of settings for an instance of Django,
|
||||||
including database configuration, Django-specific options and
|
including database configuration, Django-specific options and
|
||||||
application-specific settings.
|
application-specific settings.
|
||||||
|
|
||||||
From the command line, ``cd`` into a directory where you'd like to store your
|
From the command line, ``cd`` into a directory where you'd like to store your
|
||||||
code, then run the command ``django-admin.py startproject mysite``. This
|
code, then run the command ``django-admin.py startproject mysite``. This will
|
||||||
will create a ``mysite`` directory in your current directory.
|
create a ``mysite`` directory in your current directory.
|
||||||
|
|
||||||
.. admonition:: Mac OS X permissions
|
.. admonition:: Mac OS X permissions
|
||||||
|
|
||||||
If you're using Mac OS X, you may see the message "permission
|
If you're using Mac OS X, you may see the message "permission denied" when
|
||||||
denied" when you try to run ``django-admin.py startproject``. This
|
you try to run ``django-admin.py startproject``. This is because, on
|
||||||
is because, on Unix-based systems like OS X, a file must be marked
|
Unix-based systems like OS X, a file must be marked as "executable" before it
|
||||||
as "executable" before it can be run as a program. To do this, open
|
can be run as a program. To do this, open Terminal.app and navigate (using
|
||||||
Terminal.app and navigate (using the ``cd`` command) to the directory
|
the ``cd`` command) to the directory where :ref:`django-admin.py
|
||||||
where ``django-admin.py`` is installed, then run the command
|
<ref-django-admin>` is installed, then run the command
|
||||||
``chmod +x django-admin.py``.
|
``chmod +x django-admin.py``.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
You'll need to avoid naming projects after built-in Python or Django
|
You'll need to avoid naming projects after built-in Python or Django
|
||||||
components. In particular, this means you should avoid using names like
|
components. In particular, this means you should avoid using names like
|
||||||
``django`` (which will conflict with Django itself) or ``site`` (which
|
``django`` (which will conflict with Django itself) or ``test`` (which
|
||||||
conflicts with a built-in Python package).
|
conflicts with a built-in Python package).
|
||||||
|
|
||||||
(``django-admin.py`` should be on your system path if you installed Django via
|
:ref:`django-admin.py <ref-django-admin>` should be on your system path if you
|
||||||
``python setup.py``. If it's not on your path, you can find it in
|
installed Django via ``python setup.py``. If it's not on your path, you can find
|
||||||
``site-packages/django/bin``, where ``site-packages`` is a directory within
|
it in ``site-packages/django/bin``, where ```site-packages``` is a directory
|
||||||
your Python installation. Consider symlinking to ``django-admin.py`` from some
|
within your Python installation. Consider symlinking to :ref:`django-admin.py
|
||||||
place on your path, such as ``/usr/local/bin``.)
|
<ref-django-admin>` from some place on your path, such as
|
||||||
|
:file:`/usr/local/bin`.
|
||||||
|
|
||||||
.. admonition:: Where should this code live?
|
.. admonition:: Where should this code live?
|
||||||
|
|
||||||
If your background is in PHP, you're probably used to putting code under the
|
If your background is in PHP, you're probably used to putting code under the
|
||||||
Web server's document root (in a place such as ``/var/www``). With Django,
|
Web server's document root (in a place such as ``/var/www``). With Django,
|
||||||
you don't do that. It's not a good idea to put any of this Python code within
|
you don't do that. It's not a good idea to put any of this Python code
|
||||||
your Web server's document root, because it risks the possibility that
|
within your Web server's document root, because it risks the possibility
|
||||||
people may be able to view your code over the Web. That's not good for
|
that people may be able to view your code over the Web. That's not good for
|
||||||
security.
|
security.
|
||||||
|
|
||||||
Put your code in some directory **outside** of the document root, such as
|
Put your code in some directory **outside** of the document root, such as
|
||||||
``/home/mycode``.
|
:file:`/home/mycode`.
|
||||||
|
|
||||||
Let's look at what ``startproject`` created::
|
Let's look at what :djadmin:`startproject` created::
|
||||||
|
|
||||||
mysite/
|
mysite/
|
||||||
__init__.py
|
__init__.py
|
||||||
|
@ -86,28 +87,34 @@ Let's look at what ``startproject`` created::
|
||||||
|
|
||||||
These files are:
|
These files are:
|
||||||
|
|
||||||
* ``__init__.py``: An empty file that tells Python that this directory
|
* :file:`__init__.py`: An empty file that tells Python that this directory
|
||||||
should be considered a Python package. (Read `more about packages`_ in the
|
should be considered a Python package. (Read `more about packages`_ in the
|
||||||
official Python docs if you're a Python beginner.)
|
official Python docs if you're a Python beginner.)
|
||||||
* ``manage.py``: A command-line utility that lets you interact with this
|
|
||||||
Django project in various ways.
|
* :file:`manage.py`: A command-line utility that lets you interact with this
|
||||||
* ``settings.py``: Settings/configuration for this Django project.
|
Django project in various ways. You can read all the details about
|
||||||
* ``urls.py``: The URL declarations for this Django project; a "table of
|
:file:`manage.py` in :ref:`ref-django-admin`.
|
||||||
contents" of your Django-powered site.
|
|
||||||
|
* :file:`settings.py`: Settings/configuration for this Django project.
|
||||||
|
:ref:`topics-settings` will tell you all about how settings work.
|
||||||
|
|
||||||
|
* :file:`urls.py`: The URL declarations for this Django project; a "table of
|
||||||
|
contents" of your Django-powered site. You can read more about URLs in
|
||||||
|
:ref:`topics-http-urls`.
|
||||||
|
|
||||||
.. _more about packages: http://docs.python.org/tut/node8.html#packages
|
.. _more about packages: http://docs.python.org/tut/node8.html#packages
|
||||||
|
|
||||||
The development server
|
The development server
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
Let's verify this worked. Change into the ``mysite`` directory, if you
|
Let's verify this worked. Change into the :file:`mysite` directory, if you
|
||||||
haven't already, and run the command ``python manage.py runserver``. You'll see
|
haven't already, and run the command ``python manage.py runserver``. You'll see
|
||||||
the following output on the command line::
|
the following output on the command line::
|
||||||
|
|
||||||
Validating models...
|
Validating models...
|
||||||
0 errors found.
|
0 errors found.
|
||||||
|
|
||||||
Django version 0.95, using settings 'mysite.settings'
|
Django version 0.96, using settings 'mysite.settings'
|
||||||
Development server is running at http://127.0.0.1:8000/
|
Development server is running at http://127.0.0.1:8000/
|
||||||
Quit the server with CONTROL-C (Unix) or CTRL-BREAK (Windows).
|
Quit the server with CONTROL-C (Unix) or CTRL-BREAK (Windows).
|
||||||
|
|
||||||
|
@ -126,40 +133,49 @@ It worked!
|
||||||
|
|
||||||
.. admonition:: Changing the port
|
.. admonition:: Changing the port
|
||||||
|
|
||||||
By default, the ``runserver`` command starts the development server on port
|
By default, the :djadmin:`runserver` command starts the development server
|
||||||
8000. If you want to change the server's port, pass it as a command-line
|
on port 8000. If you want to change the server's port, pass it as a
|
||||||
argument. For instance, this command starts the server on port 8080::
|
command-line argument. For instance, this command starts the server on port
|
||||||
|
8080:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
python manage.py runserver 8080
|
python manage.py runserver 8080
|
||||||
|
|
||||||
Full docs for the development server are at `django-admin documentation`_.
|
Full docs for the development server can be found in the
|
||||||
|
:djadmin:`runserver` reference.
|
||||||
|
|
||||||
.. _django-admin documentation: ../django-admin/
|
|
||||||
|
|
||||||
Database setup
|
Database setup
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
Now, edit ``settings.py``. It's a normal Python module with module-level
|
Now, edit :file:`settings.py`. It's a normal Python module with module-level
|
||||||
variables representing Django settings. Change these settings to match your
|
variables representing Django settings. Change these settings to match your
|
||||||
database's connection parameters:
|
database's connection parameters:
|
||||||
|
|
||||||
* ``DATABASE_ENGINE`` -- Either 'postgresql_psycopg2', 'mysql' or 'sqlite3'.
|
* :setting:`DATABASE_ENGINE` -- Either 'postgresql_psycopg2', 'mysql' or
|
||||||
Other backends are `also available`_.
|
'sqlite3'. Other backends are :setting:`also available <DATABASE_ENGINE>`.
|
||||||
* ``DATABASE_NAME`` -- The name of your database. If you're using
|
|
||||||
SQLite, the database will be a file on your computer; in that
|
|
||||||
case, ``DATABASE_NAME`` should be the full absolute path,
|
|
||||||
including filename, of that file. If the file doesn't exist, it
|
|
||||||
will automatically be created when you synchronize the database
|
|
||||||
for the first time (see below).
|
|
||||||
* ``DATABASE_USER`` -- Your database username (not used for SQLite).
|
|
||||||
* ``DATABASE_PASSWORD`` -- Your database password (not used for SQLite).
|
|
||||||
* ``DATABASE_HOST`` -- The host your database is on. Leave this as an
|
|
||||||
empty string if your database server is on the same physical machine
|
|
||||||
(not used for SQLite).
|
|
||||||
|
|
||||||
.. _also available: ../settings/
|
* :setting:`DATABASE_NAME` -- The name of your database. If you're using
|
||||||
|
SQLite, the database will be a file on your computer; in that case,
|
||||||
|
``DATABASE_NAME`` should be the full absolute path, including filename, of
|
||||||
|
that file. If the file doesn't exist, it will automatically be created
|
||||||
|
when you synchronize the database for the first time (see below).
|
||||||
|
|
||||||
.. admonition:: Note
|
* :setting:`DATABASE_USER` -- Your database username (not used for SQLite).
|
||||||
|
|
||||||
|
* :setting:`DATABASE_PASSWORD` -- Your database password (not used for
|
||||||
|
SQLite).
|
||||||
|
|
||||||
|
* :setting:`DATABASE_HOST` -- The host your database is on. Leave this as an
|
||||||
|
empty string if your database server is on the same physical machine (not
|
||||||
|
used for SQLite).
|
||||||
|
|
||||||
|
If you're new to databases, we recommend simply using SQLite (by setting
|
||||||
|
:setting:`DATABASE_ENGINE` to ``'sqlite3'``). SQLite is included as part of
|
||||||
|
Python 2.5 and later, so you won't need to install anything else.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
If you're using PostgreSQL or MySQL, make sure you've created a database by
|
If you're using PostgreSQL or MySQL, make sure you've created a database by
|
||||||
this point. Do that with "``CREATE DATABASE database_name;``" within your
|
this point. Do that with "``CREATE DATABASE database_name;``" within your
|
||||||
|
@ -168,35 +184,39 @@ database's connection parameters:
|
||||||
If you're using SQLite, you don't need to create anything beforehand - the
|
If you're using SQLite, you don't need to create anything beforehand - the
|
||||||
database file will be created automatically when it is needed.
|
database file will be created automatically when it is needed.
|
||||||
|
|
||||||
While you're editing ``settings.py``, take note of the ``INSTALLED_APPS``
|
While you're editing :file:`settings.py`, take note of the
|
||||||
setting towards the bottom of the file. That variable holds the names of all
|
:setting:`INSTALLED_APPS` setting towards the bottom of the file. That variable
|
||||||
Django applications that are activated in this Django instance. Apps can be
|
holds the names of all Django applications that are activated in this Django
|
||||||
used in multiple projects, and you can package and distribute them for use
|
instance. Apps can be used in multiple projects, and you can package and
|
||||||
by others in their projects.
|
distribute them for use by others in their projects.
|
||||||
|
|
||||||
By default, ``INSTALLED_APPS`` contains the following apps, all of which come
|
By default, :setting:`INSTALLED_APPS` contains the following apps, all of which
|
||||||
with Django:
|
come with Django:
|
||||||
|
|
||||||
* ``django.contrib.auth`` -- An authentication system.
|
* :mod:`django.contrib.auth` -- An authentication system.
|
||||||
* ``django.contrib.contenttypes`` -- A framework for content types.
|
|
||||||
* ``django.contrib.sessions`` -- A session framework.
|
* :mod:`django.contrib.contenttypes` -- A framework for content types.
|
||||||
* ``django.contrib.sites`` -- A framework for managing multiple sites
|
|
||||||
|
* :mod:`django.contrib.sessions` -- A session framework.
|
||||||
|
|
||||||
|
* :mod:`django.contrib.sites` -- A framework for managing multiple sites
|
||||||
with one Django installation.
|
with one Django installation.
|
||||||
|
|
||||||
These applications are included by default as a convenience for the common
|
These applications are included by default as a convenience for the common case.
|
||||||
case.
|
|
||||||
|
|
||||||
Each of these applications makes use of at least one database table, though,
|
Each of these applications makes use of at least one database table, though,
|
||||||
so we need to create the tables in the database before we can use them. To do
|
so we need to create the tables in the database before we can use them. To do
|
||||||
that, run the following command::
|
that, run the following command:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
python manage.py syncdb
|
python manage.py syncdb
|
||||||
|
|
||||||
The ``syncdb`` command looks at the ``INSTALLED_APPS`` setting and creates any
|
The :djadmin:`syncdb` command looks at the :setting:`INSTALLED_APPS` setting and
|
||||||
necessary database tables according to the database settings in your
|
creates any necessary database tables according to the database settings in your
|
||||||
``settings.py`` file. You'll see a message for each database table it creates,
|
:file:`settings.py` file. You'll see a message for each database table it
|
||||||
and you'll get a prompt asking you if you'd like to create a superuser account
|
creates, and you'll get a prompt asking you if you'd like to create a superuser
|
||||||
for the authentication system. Go ahead and do that.
|
account for the authentication system. Go ahead and do that.
|
||||||
|
|
||||||
If you're interested, run the command-line client for your database and type
|
If you're interested, run the command-line client for your database and type
|
||||||
``\dt`` (PostgreSQL), ``SHOW TABLES;`` (MySQL), or ``.schema`` (SQLite) to
|
``\dt`` (PostgreSQL), ``SHOW TABLES;`` (MySQL), or ``.schema`` (SQLite) to
|
||||||
|
@ -207,8 +227,11 @@ display the tables Django created.
|
||||||
Like we said above, the default applications are included for the common
|
Like we said above, the default applications are included for the common
|
||||||
case, but not everybody needs them. If you don't need any or all of them,
|
case, but not everybody needs them. If you don't need any or all of them,
|
||||||
feel free to comment-out or delete the appropriate line(s) from
|
feel free to comment-out or delete the appropriate line(s) from
|
||||||
``INSTALLED_APPS`` before running ``syncdb``. The ``syncdb`` command will
|
:setting:`INSTALLED_APPS` before running :djadmin:`syncdb`. The
|
||||||
only create tables for apps in ``INSTALLED_APPS``.
|
:djadmin:`syncdb` command will only create tables for apps in
|
||||||
|
:setting:`INSTALLED_APPS`.
|
||||||
|
|
||||||
|
.. _creating-models:
|
||||||
|
|
||||||
Creating models
|
Creating models
|
||||||
===============
|
===============
|
||||||
|
@ -229,17 +252,19 @@ so you can focus on writing code rather than creating directories.
|
||||||
configuration and apps for a particular Web site. A project can contain
|
configuration and apps for a particular Web site. A project can contain
|
||||||
multiple apps. An app can be in multiple projects.
|
multiple apps. An app can be in multiple projects.
|
||||||
|
|
||||||
In this tutorial, we'll create our poll app in the ``mysite`` directory,
|
In this tutorial, we'll create our poll app in the :file:`mysite` directory,
|
||||||
for simplicity. As a consequence, the app will be coupled to the project --
|
for simplicity. As a consequence, the app will be coupled to the project --
|
||||||
that is, Python code within the poll app will refer to ``mysite.polls``.
|
that is, Python code within the poll app will refer to ``mysite.polls``.
|
||||||
Later in this tutorial, we'll discuss decoupling your apps for distribution.
|
Later in this tutorial, we'll discuss decoupling your apps for distribution.
|
||||||
|
|
||||||
To create your app, make sure you're in the ``mysite`` directory and type
|
To create your app, make sure you're in the :file:`mysite` directory and type
|
||||||
this command::
|
this command:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
python manage.py startapp polls
|
python manage.py startapp polls
|
||||||
|
|
||||||
That'll create a directory ``polls``, which is laid out like this::
|
That'll create a directory :file:`polls`, which is laid out like this::
|
||||||
|
|
||||||
polls/
|
polls/
|
||||||
__init__.py
|
__init__.py
|
||||||
|
@ -253,17 +278,17 @@ The first step in writing a database Web app in Django is to define your models
|
||||||
|
|
||||||
.. admonition:: Philosophy
|
.. admonition:: Philosophy
|
||||||
|
|
||||||
A model is the single, definitive source of data about your
|
A model is the single, definitive source of data about your data. It contains
|
||||||
data. It contains the essential fields and behaviors of the data you're
|
the essential fields and behaviors of the data you're storing. Django follows
|
||||||
storing. Django follows the `DRY Principle`_. The goal is to define your
|
the :ref:`DRY Principle <dry>`. The goal is to define your data model in one
|
||||||
data model in one place and automatically derive things from it.
|
place and automatically derive things from it.
|
||||||
|
|
||||||
In our simple poll app, we'll create two models: polls and choices. A poll has
|
In our simple poll app, we'll create two models: polls and choices. A poll has
|
||||||
a question and a publication date. A choice has two fields: the text of the
|
a question and a publication date. A choice has two fields: the text of the
|
||||||
choice and a vote tally. Each choice is associated with a poll.
|
choice and a vote tally. Each choice is associated with a poll.
|
||||||
|
|
||||||
These concepts are represented by simple Python classes. Edit the
|
These concepts are represented by simple Python classes. Edit the
|
||||||
``polls/models.py`` file so it looks like this::
|
:file:`polls/models.py` file so it looks like this::
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
|
@ -276,51 +301,54 @@ These concepts are represented by simple Python classes. Edit the
|
||||||
choice = models.CharField(max_length=200)
|
choice = models.CharField(max_length=200)
|
||||||
votes = models.IntegerField()
|
votes = models.IntegerField()
|
||||||
|
|
||||||
.. admonition:: Errors about ``max_length``
|
.. admonition:: Errors about :attr:`~django.db.models.Field.max_length`
|
||||||
|
|
||||||
If Django gives you an error message saying that ``max_length`` is
|
If Django gives you an error message saying that
|
||||||
not a valid argument, you're most likely using an old version of
|
:attr:`~django.db.models.Field.max_length` is not a valid argument, you're
|
||||||
Django. (This version of the tutorial is written for the latest
|
most likely using an old version of Django. (This version of the tutorial is
|
||||||
development version of Django.) If you're using a Subversion checkout
|
written for the latest development version of Django.) If you're using a
|
||||||
of Django's development version (see `the installation docs`_ for
|
Subversion checkout of Django's development version (see :ref:`the
|
||||||
more information), you shouldn't have any problems.
|
installation docs <topics-install>` for more information), you shouldn't have
|
||||||
|
any problems.
|
||||||
|
|
||||||
If you want to stick with an older version of Django, you'll want to
|
If you want to stick with an older version of Django, you'll want to switch
|
||||||
switch to `the Django 0.96 tutorial`_, because this tutorial covers
|
to `the Django 0.96 tutorial`_, because this tutorial covers several features
|
||||||
several features that only exist in the Django development version.
|
that only exist in the Django development version.
|
||||||
|
|
||||||
.. _the installation docs: ../install/
|
.. _the Django 0.96 tutorial: http://www.djangoproject.com/documentation/0.96/tutorial01/
|
||||||
.. _the Django 0.96 tutorial: ../0.96/tutorial01/
|
|
||||||
|
|
||||||
The code is straightforward. Each model is represented by a class that
|
The code is straightforward. Each model is represented by a class that
|
||||||
subclasses ``django.db.models.Model``. Each model has a number of class
|
subclasses :class:`django.db.models.Model`. Each model has a number of class
|
||||||
variables, each of which represents a database field in the model.
|
variables, each of which represents a database field in the model.
|
||||||
|
|
||||||
Each field is represented by an instance of a ``models.*Field`` class -- e.g.,
|
Each field is represented by an instance of a :class:`~django.db.models.Field`
|
||||||
``models.CharField`` for character fields and ``models.DateTimeField`` for
|
class -- e.g., :class:`~django.db.models.CharField` for character fields and
|
||||||
datetimes. This tells Django what type of data each field holds.
|
:class:`~django.db.models.DateTimeField` for datetimes. This tells Django what
|
||||||
|
type of data each field holds.
|
||||||
|
|
||||||
The name of each ``models.*Field`` instance (e.g. ``question`` or ``pub_date`` )
|
The name of each :class:`~django.db.models.Field` instance (e.g. ``question`` or
|
||||||
is the field's name, in machine-friendly format. You'll use this value in your
|
``pub_date`` ) is the field's name, in machine-friendly format. You'll use this
|
||||||
Python code, and your database will use it as the column name.
|
value in your Python code, and your database will use it as the column name.
|
||||||
|
|
||||||
You can use an optional first positional argument to a ``Field`` to designate a
|
You can use an optional first positional argument to a
|
||||||
human-readable name. That's used in a couple of introspective parts of Django,
|
:class:`~django.db.models.Field` to designate a human-readable name. That's used
|
||||||
and it doubles as documentation. If this field isn't provided, Django will use
|
in a couple of introspective parts of Django, and it doubles as documentation.
|
||||||
the machine-readable name. In this example, we've only defined a human-readable
|
If this field isn't provided, Django will use the machine-readable name. In this
|
||||||
name for ``Poll.pub_date``. For all other fields in this model, the field's
|
example, we've only defined a human-readable name for ``Poll.pub_date``. For all
|
||||||
machine-readable name will suffice as its human-readable name.
|
other fields in this model, the field's machine-readable name will suffice as
|
||||||
|
its human-readable name.
|
||||||
|
|
||||||
Some ``Field`` classes have required elements. ``CharField``, for example,
|
Some :class:`~django.db.models.Field` classes have required elements.
|
||||||
requires that you give it a ``max_length``. That's used not only in the database
|
:class:`~django.db.models.CharField`, for example, requires that you give it a
|
||||||
|
:attr:`~django.db.models.Field.max_length`. That's used not only in the database
|
||||||
schema, but in validation, as we'll soon see.
|
schema, but in validation, as we'll soon see.
|
||||||
|
|
||||||
Finally, note a relationship is defined, using ``models.ForeignKey``. That tells
|
Finally, note a relationship is defined, using
|
||||||
Django each Choice is related to a single Poll. Django supports all the common
|
:class:`~django.db.models.ForeignKey`. That tells Django each Choice is related
|
||||||
database relationships: many-to-ones, many-to-manys and one-to-ones.
|
to a single Poll. Django supports all the common database relationships:
|
||||||
|
many-to-ones, many-to-manys and one-to-ones.
|
||||||
|
|
||||||
.. _`Python path`: http://docs.python.org/tut/node8.html#SECTION008110000000000000000
|
.. _`Python path`: http://docs.python.org/tut/node8.html#SECTION008110000000000000000
|
||||||
.. _DRY Principle: http://c2.com/cgi/wiki?DontRepeatYourself
|
|
||||||
|
|
||||||
Activating models
|
Activating models
|
||||||
=================
|
=================
|
||||||
|
@ -339,8 +367,9 @@ But first we need to tell our project that the ``polls`` app is installed.
|
||||||
you can distribute apps, because they don't have to be tied to a given
|
you can distribute apps, because they don't have to be tied to a given
|
||||||
Django installation.
|
Django installation.
|
||||||
|
|
||||||
Edit the ``settings.py`` file again, and change the ``INSTALLED_APPS`` setting
|
Edit the :file:`settings.py` file again, and change the
|
||||||
to include the string ``'mysite.polls'``. So it'll look like this::
|
:setting:`INSTALLED_APPS` setting to include the string ``'mysite.polls'``. So
|
||||||
|
it'll look like this::
|
||||||
|
|
||||||
INSTALLED_APPS = (
|
INSTALLED_APPS = (
|
||||||
'django.contrib.auth',
|
'django.contrib.auth',
|
||||||
|
@ -350,12 +379,17 @@ to include the string ``'mysite.polls'``. So it'll look like this::
|
||||||
'mysite.polls'
|
'mysite.polls'
|
||||||
)
|
)
|
||||||
|
|
||||||
Now Django knows ``mysite`` includes the ``polls`` app. Let's run another command::
|
Now Django knows ``mysite`` includes the ``polls`` app. Let's run another
|
||||||
|
command:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
python manage.py sql polls
|
python manage.py sql polls
|
||||||
|
|
||||||
You should see something similar to the following (the CREATE TABLE SQL statements
|
You should see something similar to the following (the ``CREATE TABLE`` SQL
|
||||||
for the polls app)::
|
statements for the polls app):
|
||||||
|
|
||||||
|
.. code-block:: sql
|
||||||
|
|
||||||
BEGIN;
|
BEGIN;
|
||||||
CREATE TABLE "polls_poll" (
|
CREATE TABLE "polls_poll" (
|
||||||
|
@ -384,7 +418,8 @@ Note the following:
|
||||||
* By convention, Django appends ``"_id"`` to the foreign key field name.
|
* By convention, Django appends ``"_id"`` to the foreign key field name.
|
||||||
Yes, you can override this, as well.
|
Yes, you can override this, as well.
|
||||||
|
|
||||||
* The foreign key relationship is made explicit by a ``REFERENCES`` statement.
|
* The foreign key relationship is made explicit by a ``REFERENCES``
|
||||||
|
statement.
|
||||||
|
|
||||||
* It's tailored to the database you're using, so database-specific field
|
* It's tailored to the database you're using, so database-specific field
|
||||||
types such as ``auto_increment`` (MySQL), ``serial`` (PostgreSQL), or
|
types such as ``auto_increment`` (MySQL), ``serial`` (PostgreSQL), or
|
||||||
|
@ -393,53 +428,58 @@ Note the following:
|
||||||
quotes. The author of this tutorial runs PostgreSQL, so the example
|
quotes. The author of this tutorial runs PostgreSQL, so the example
|
||||||
output is in PostgreSQL syntax.
|
output is in PostgreSQL syntax.
|
||||||
|
|
||||||
* The ``sql`` command doesn't actually run the SQL in your database - it just
|
* The :djadmin:`sql` command doesn't actually run the SQL in your database -
|
||||||
prints it to the screen so that you can see what SQL Django thinks is required.
|
it just prints it to the screen so that you can see what SQL Django thinks
|
||||||
If you wanted to, you could copy and paste this SQL into your database prompt.
|
is required. If you wanted to, you could copy and paste this SQL into your
|
||||||
However, as we will see shortly, Django provides an easier way of committing
|
database prompt. However, as we will see shortly, Django provides an
|
||||||
the SQL to the database.
|
easier way of committing the SQL to the database.
|
||||||
|
|
||||||
If you're interested, also run the following commands:
|
If you're interested, also run the following commands:
|
||||||
* ``python manage.py validate`` -- Checks for any errors in the
|
|
||||||
construction of your models.
|
|
||||||
|
|
||||||
* ``python manage.py sqlcustom polls`` -- Outputs any custom SQL statements
|
* :djadmin:`python manage.py validate <validate>` -- Checks for any errors
|
||||||
(such as table modifications or constraints) that are defined for the
|
in the construction of your models.
|
||||||
application.
|
|
||||||
|
|
||||||
* ``python manage.py sqlclear polls`` -- Outputs the necessary ``DROP
|
* :djadmin:`python manage.py sqlcustom polls <sqlcustom>` -- Outputs any
|
||||||
TABLE`` statements for this app, according to which tables already exist
|
:ref:`custom SQL statements <initial-sql>` (such as table modifications or
|
||||||
in your database (if any).
|
constraints) that are defined for the application.
|
||||||
|
|
||||||
* ``python manage.py sqlindexes polls`` -- Outputs the ``CREATE INDEX``
|
* :djadmin:`python manage.py sqlclear polls <sqlclear>` -- Outputs the
|
||||||
statements for this app.
|
necessary ``DROP TABLE`` statements for this app, according to which
|
||||||
|
tables already exist in your database (if any).
|
||||||
|
|
||||||
* ``python manage.py sqlall polls`` -- A combination of all the SQL from
|
* :djadmin:`python manage.py sqlindexes polls <sqlindexes>` -- Outputs the
|
||||||
the 'sql', 'sqlcustom', and 'sqlindexes' commands.
|
``CREATE INDEX`` statements for this app.
|
||||||
|
|
||||||
|
* :djadmin:`python manage.py sqlall polls <sqlall>` -- A combination of all
|
||||||
|
the SQL from the :djadmin:`sql`, :djadmin:`sqlcustom`, and
|
||||||
|
:djadmin:`sqlindexes` commands.
|
||||||
|
|
||||||
Looking at the output of those commands can help you understand what's actually
|
Looking at the output of those commands can help you understand what's actually
|
||||||
happening under the hood.
|
happening under the hood.
|
||||||
|
|
||||||
Now, run ``syncdb`` again to create those model tables in your database::
|
Now, run :djadmin:`syncdb` again to create those model tables in your database:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
python manage.py syncdb
|
python manage.py syncdb
|
||||||
|
|
||||||
The ``syncdb`` command runs the sql from 'sqlall' on your database for all apps
|
The :djadmin:`syncdb` command runs the sql from 'sqlall' on your database for
|
||||||
in ``INSTALLED_APPS`` that don't already exist in your database. This creates
|
all apps in :setting:`INSTALLED_APPS` that don't already exist in your database.
|
||||||
all the tables, initial data and indexes for any apps you have added to your
|
This creates all the tables, initial data and indexes for any apps you have
|
||||||
project since the last time you ran syncdb. ``syncdb`` can be called as often
|
added to your project since the last time you ran syncdb. :djadmin:`syncdb` can
|
||||||
as you like, and it will only ever create the tables that don't exist.
|
be called as often as you like, and it will only ever create the tables that
|
||||||
|
don't exist.
|
||||||
|
|
||||||
Read the `django-admin.py documentation`_ for full information on what the
|
Read the :ref:`django-admin.py documentation <ref-django-admin>` for full
|
||||||
``manage.py`` utility can do.
|
information on what the ``manage.py`` utility can do.
|
||||||
|
|
||||||
.. _django-admin.py documentation: ../django-admin/
|
|
||||||
|
|
||||||
Playing with the API
|
Playing with the API
|
||||||
====================
|
====================
|
||||||
|
|
||||||
Now, let's hop into the interactive Python shell and play around with the free
|
Now, let's hop into the interactive Python shell and play around with the free
|
||||||
API Django gives you. To invoke the Python shell, use this command::
|
API Django gives you. To invoke the Python shell, use this command:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
python manage.py shell
|
python manage.py shell
|
||||||
|
|
||||||
|
@ -449,28 +489,28 @@ things:
|
||||||
|
|
||||||
* Putting ``mysite`` on ``sys.path``. For flexibility, several pieces of
|
* Putting ``mysite`` on ``sys.path``. For flexibility, several pieces of
|
||||||
Django refer to projects in Python dotted-path notation (e.g.
|
Django refer to projects in Python dotted-path notation (e.g.
|
||||||
``'mysite.polls.models'``). In order for this to work, the
|
``'mysite.polls.models'``). In order for this to work, the ``mysite``
|
||||||
``mysite`` package has to be on ``sys.path``.
|
package has to be on ``sys.path``.
|
||||||
|
|
||||||
We've already seen one example of this: the ``INSTALLED_APPS`` setting is
|
We've already seen one example of this: the :setting:`INSTALLED_APPS`
|
||||||
a list of packages in dotted-path notation.
|
setting is a list of packages in dotted-path notation.
|
||||||
|
|
||||||
* Setting the ``DJANGO_SETTINGS_MODULE`` environment variable, which gives
|
* Setting the ``DJANGO_SETTINGS_MODULE`` environment variable, which gives
|
||||||
Django the path to your ``settings.py`` file.
|
Django the path to your ``settings.py`` file.
|
||||||
|
|
||||||
.. admonition:: Bypassing manage.py
|
.. admonition:: Bypassing manage.py
|
||||||
|
|
||||||
If you'd rather not use ``manage.py``, no problem. Just make sure
|
If you'd rather not use ``manage.py``, no problem. Just make sure ``mysite``
|
||||||
``mysite`` is at the root level on the Python path (i.e.,
|
is at the root level on the Python path (i.e., ``import mysite`` works) and
|
||||||
``import mysite`` works) and set the ``DJANGO_SETTINGS_MODULE``
|
set the ``DJANGO_SETTINGS_MODULE`` environment variable to
|
||||||
environment variable to ``mysite.settings``.
|
``mysite.settings``.
|
||||||
|
|
||||||
For more information on all of this, see the `django-admin.py documentation`_.
|
For more information on all of this, see the :ref:`django-admin.py
|
||||||
|
documentation <ref-django-admin>`.
|
||||||
|
|
||||||
Once you're in the shell, explore the database API::
|
Once you're in the shell, explore the :ref:`database API <topics-db-queries>`::
|
||||||
|
|
||||||
# Import the model classes we just wrote.
|
>>> from mysite.polls.models import Poll, Choice # Import the model classes we just wrote.
|
||||||
>>> from mysite.polls.models import Poll, Choice
|
|
||||||
|
|
||||||
# No polls are in the system yet.
|
# No polls are in the system yet.
|
||||||
>>> Poll.objects.all()
|
>>> Poll.objects.all()
|
||||||
|
@ -505,10 +545,11 @@ Once you're in the shell, explore the database API::
|
||||||
[<Poll: Poll object>]
|
[<Poll: Poll object>]
|
||||||
|
|
||||||
|
|
||||||
Wait a minute. ``<Poll: Poll object>`` is, utterly, an unhelpful
|
Wait a minute. ``<Poll: Poll object>`` is, utterly, an unhelpful representation
|
||||||
representation of this object. Let's fix that by editing the polls model (in
|
of this object. Let's fix that by editing the polls model (in the
|
||||||
the ``polls/models.py`` file) and adding a ``__unicode__()`` method to both
|
``polls/models.py`` file) and adding a
|
||||||
``Poll`` and ``Choice``::
|
:meth:`~django.db.models.Model.__unicode__` method to both ``Poll`` and
|
||||||
|
``Choice``::
|
||||||
|
|
||||||
class Poll(models.Model):
|
class Poll(models.Model):
|
||||||
# ...
|
# ...
|
||||||
|
@ -520,43 +561,46 @@ the ``polls/models.py`` file) and adding a ``__unicode__()`` method to both
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return self.choice
|
return self.choice
|
||||||
|
|
||||||
.. admonition:: If ``__unicode__()`` doesn't seem to work
|
.. admonition:: If :meth:`~django.db.models.Model.__unicode__` doesn't seem to work
|
||||||
|
|
||||||
If you add the ``__unicode__()`` method to your models and don't
|
If you add the :meth:`~django.db.models.Model.__unicode__` method to your
|
||||||
see any change in how they're represented, you're most likely using
|
models and don't see any change in how they're represented, you're most
|
||||||
an old version of Django. (This version of the tutorial is written
|
likely using an old version of Django. (This version of the tutorial is
|
||||||
for the latest development version of Django.) If you're using a
|
written for the latest development version of Django.) If you're using a
|
||||||
Subversion checkout of of Django's development version (see `the
|
Subversion checkout of of Django's development version (see :ref:`the
|
||||||
installation docs`_ for more information), you shouldn't have any
|
installation docs <topics-install>` for more information), you shouldn't have
|
||||||
problems.
|
any problems.
|
||||||
|
|
||||||
If you want to stick with an older version of Django, you'll want to
|
If you want to stick with an older version of Django, you'll want to switch
|
||||||
switch to `the Django 0.96 tutorial`_, because this tutorial covers
|
to `the Django 0.96 tutorial`_, because this tutorial covers several features
|
||||||
several features that only exist in the Django development version.
|
that only exist in the Django development version.
|
||||||
|
|
||||||
.. _the installation docs: ../install/
|
.. _the Django 0.96 tutorial: http://www.djangoproject.com/documentation/0.96/tutorial01/
|
||||||
.. _the Django 0.96 tutorial: ../0.96/tutorial01/
|
|
||||||
|
|
||||||
It's important to add ``__unicode__()`` methods to your models, not only for
|
It's important to add :meth:`~django.db.models.Model.__unicode__` methods to
|
||||||
your own sanity when dealing with the interactive prompt, but also because
|
your models, not only for your own sanity when dealing with the interactive
|
||||||
objects' representations are used throughout Django's automatically-generated
|
prompt, but also because objects' representations are used throughout Django's
|
||||||
admin.
|
automatically-generated admin.
|
||||||
|
|
||||||
.. admonition:: Why ``__unicode__()`` and not ``__str__()``?
|
.. admonition:: Why :meth:`~django.db.models.Model.__unicode__` and not
|
||||||
|
:meth:`django.db.models.Model.__str__`?
|
||||||
|
|
||||||
If you're familiar with Python, you might be in the habit of adding
|
If you're familiar with Python, you might be in the habit of adding
|
||||||
``__str__()`` methods to your classes, not ``__unicode__()`` methods.
|
:meth:`django.db.models.Model.__str__` methods to your classes, not
|
||||||
We use ``__unicode__()`` here because Django models deal with Unicode by
|
:meth:`~django.db.models.Model.__unicode__` methods. We use
|
||||||
default. All data stored in your database is converted to Unicode when it's
|
:meth:`~django.db.models.Model.__unicode__` here because Django models deal
|
||||||
returned.
|
with Unicode by default. All data stored in your database is converted to
|
||||||
|
Unicode when it's returned.
|
||||||
|
|
||||||
Django models have a default ``__str__()`` method that calls
|
Django models have a default :meth:`django.db.models.Model.__str__` method
|
||||||
``__unicode__()`` and converts the result to a UTF-8 bytestring. This means
|
that calls :meth:`~django.db.models.Model.__unicode__` and converts the
|
||||||
that ``unicode(p)`` will return a Unicode string, and ``str(p)`` will return
|
result to a UTF-8 bytestring. This means that ``unicode(p)`` will return a
|
||||||
a normal string, with characters encoded as UTF-8.
|
Unicode string, and ``str(p)`` will return a normal string, with characters
|
||||||
|
encoded as UTF-8.
|
||||||
|
|
||||||
If all of this is jibberish to you, just remember to add ``__unicode__()``
|
If all of this is jibberish to you, just remember to add
|
||||||
methods to your models. With any luck, things should Just Work for you.
|
:meth:`~django.db.models.Model.__unicode__` methods to your models. With any
|
||||||
|
luck, things should Just Work for you.
|
||||||
|
|
||||||
Note these are normal Python methods. Let's add a custom method, just for
|
Note these are normal Python methods. Let's add a custom method, just for
|
||||||
demonstration::
|
demonstration::
|
||||||
|
@ -639,10 +683,8 @@ Let's jump back into the Python interactive shell by running
|
||||||
>>> c = p.choice_set.filter(choice__startswith='Just hacking')
|
>>> c = p.choice_set.filter(choice__startswith='Just hacking')
|
||||||
>>> c.delete()
|
>>> c.delete()
|
||||||
|
|
||||||
For full details on the database API, see our `Database API reference`_.
|
For full details on the database API, see our :ref:`Database API reference
|
||||||
|
<topics-db-queries>`.
|
||||||
|
|
||||||
When you're comfortable with the API, read `part 2 of this tutorial`_ to get
|
When you're comfortable with the API, read :ref:`part 2 of this tutorial
|
||||||
Django's automatic admin working.
|
<intro-tutorial02>` to get Django's automatic admin working.
|
||||||
|
|
||||||
.. _Database API reference: ../db-api/
|
|
||||||
.. _part 2 of this tutorial: ../tutorial02/
|
|
|
@ -1,26 +1,27 @@
|
||||||
|
.. _intro-tutorial02:
|
||||||
|
|
||||||
=====================================
|
=====================================
|
||||||
Writing your first Django app, part 2
|
Writing your first Django app, part 2
|
||||||
=====================================
|
=====================================
|
||||||
|
|
||||||
This tutorial begins where `Tutorial 1`_ left off. We're continuing the Web-poll
|
This tutorial begins where :ref:`Tutorial 1 <intro-tutorial01>` left off. We're
|
||||||
application and will focus on Django's automatically-generated admin site.
|
continuing the Web-poll application and will focus on Django's
|
||||||
|
automatically-generated admin site.
|
||||||
.. _Tutorial 1: ../tutorial01/
|
|
||||||
|
|
||||||
.. admonition:: Philosophy
|
.. admonition:: Philosophy
|
||||||
|
|
||||||
Generating admin sites for your staff or clients to add, change and delete
|
Generating admin sites for your staff or clients to add, change and delete
|
||||||
content is tedious work that doesn't require much creativity. For that reason,
|
content is tedious work that doesn't require much creativity. For that
|
||||||
Django entirely automates creation of admin interfaces for models.
|
reason, Django entirely automates creation of admin interfaces for models.
|
||||||
|
|
||||||
Django was written in a newsroom environment, with a very clear separation
|
Django was written in a newsroom environment, with a very clear separation
|
||||||
between "content publishers" and the "public" site. Site managers use the
|
between "content publishers" and the "public" site. Site managers use the
|
||||||
system to add news stories, events, sports scores, etc., and that content is
|
system to add news stories, events, sports scores, etc., and that content is
|
||||||
displayed on the public site. Django solves the problem of creating a unified
|
displayed on the public site. Django solves the problem of creating a
|
||||||
interface for site administrators to edit content.
|
unified interface for site administrators to edit content.
|
||||||
|
|
||||||
The admin isn't necessarily intended to be used by site visitors; it's for site
|
The admin isn't necessarily intended to be used by site visitors; it's for
|
||||||
managers.
|
site managers.
|
||||||
|
|
||||||
Activate the admin site
|
Activate the admin site
|
||||||
=======================
|
=======================
|
||||||
|
@ -28,10 +29,10 @@ Activate the admin site
|
||||||
The Django admin site is not activated by default -- it's an opt-in thing. To
|
The Django admin site is not activated by default -- it's an opt-in thing. To
|
||||||
activate the admin site for your installation, do these three things:
|
activate the admin site for your installation, do these three things:
|
||||||
|
|
||||||
* Add ``"django.contrib.admin"`` to your ``INSTALLED_APPS`` setting.
|
* Add ``"django.contrib.admin"`` to your :setting:`INSTALLED_APPS` setting.
|
||||||
|
|
||||||
* Run ``python manage.py syncdb``. Since you have added a new application
|
* Run ``python manage.py syncdb``. Since you have added a new application
|
||||||
to ``INSTALLED_APPS``, the database tables need to be updated.
|
to :setting:`INSTALLED_APPS`, the database tables need to be updated.
|
||||||
|
|
||||||
* Edit your ``mysite/urls.py`` file and uncomment the lines below the
|
* Edit your ``mysite/urls.py`` file and uncomment the lines below the
|
||||||
"Uncomment this for admin:" comments. This file is a URLconf; we'll dig
|
"Uncomment this for admin:" comments. This file is a URLconf; we'll dig
|
||||||
|
@ -65,14 +66,16 @@ Start the development server
|
||||||
|
|
||||||
Let's start the development server and explore the admin site.
|
Let's start the development server and explore the admin site.
|
||||||
|
|
||||||
Recall from Tutorial 1 that you start the development server like so::
|
Recall from Tutorial 1 that you start the development server like so:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
python manage.py runserver
|
python manage.py runserver
|
||||||
|
|
||||||
Now, open a Web browser and go to "/admin/" on your local domain -- e.g.,
|
Now, open a Web browser and go to "/admin/" on your local domain -- e.g.,
|
||||||
http://127.0.0.1:8000/admin/. You should see the admin's login screen:
|
http://127.0.0.1:8000/admin/. You should see the admin's login screen:
|
||||||
|
|
||||||
.. image:: http://media.djangoproject.com/img/doc/tutorial-trunk/admin01.png
|
.. image:: _images/admin01.png
|
||||||
:alt: Django admin login screen
|
:alt: Django admin login screen
|
||||||
|
|
||||||
Enter the admin site
|
Enter the admin site
|
||||||
|
@ -81,24 +84,22 @@ Enter the admin site
|
||||||
Now, try logging in. (You created a superuser account in the first part of this
|
Now, try logging in. (You created a superuser account in the first part of this
|
||||||
tutorial, remember?) You should see the Django admin index page:
|
tutorial, remember?) You should see the Django admin index page:
|
||||||
|
|
||||||
.. image:: http://media.djangoproject.com/img/doc/tutorial-trunk/admin02t.png
|
.. image:: _images/admin02t.png
|
||||||
:alt: Django admin index page
|
:alt: Django admin index page
|
||||||
:target: http://media.djangoproject.com/img/doc/tutorial-trunk/admin02.png
|
|
||||||
|
|
||||||
You should see a few other types of editable content, including groups, users
|
You should see a few other types of editable content, including groups, users
|
||||||
and sites. These are core features Django ships with by default.
|
and sites. These are core features Django ships with by default.
|
||||||
|
|
||||||
.. _"I can't log in" questions: ../faq/#the-admin-site
|
|
||||||
|
|
||||||
Make the poll app modifiable in the admin
|
Make the poll app modifiable in the admin
|
||||||
=========================================
|
=========================================
|
||||||
|
|
||||||
But where's our poll app? It's not displayed on the admin index page.
|
But where's our poll app? It's not displayed on the admin index page.
|
||||||
|
|
||||||
Just one thing to do: We need to tell the admin that ``Poll``
|
Just one thing to do: We need to tell the admin that ``Poll``
|
||||||
objects have an admin interface. Edit the ``mysite/polls/models.py`` file and
|
objects have an admin interface. Edit the ``mysite/polls/admin.py`` file and
|
||||||
add the following to the bottom of the file::
|
add the following to the bottom of the file::
|
||||||
|
|
||||||
|
from mysite.polls.models import Poll
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
|
||||||
admin.site.register(Poll)
|
admin.site.register(Poll)
|
||||||
|
@ -113,52 +114,54 @@ Explore the free admin functionality
|
||||||
Now that we've registered ``Poll``, Django knows that it should be displayed on
|
Now that we've registered ``Poll``, Django knows that it should be displayed on
|
||||||
the admin index page:
|
the admin index page:
|
||||||
|
|
||||||
.. image:: http://media.djangoproject.com/img/doc/tutorial-trunk/admin03t.png
|
.. image:: _images/admin03t.png
|
||||||
:alt: Django admin index page, now with polls displayed
|
:alt: Django admin index page, now with polls displayed
|
||||||
:target: http://media.djangoproject.com/img/doc/tutorial-trunk/admin03.png
|
|
||||||
|
|
||||||
Click "Polls." Now you're at the "change list" page for polls. This page
|
Click "Polls." Now you're at the "change list" page for polls. This page
|
||||||
displays all the polls in the database and lets you choose one to change it.
|
displays all the polls in the database and lets you choose one to change it.
|
||||||
There's the "What's up?" poll we created in the first tutorial:
|
There's the "What's up?" poll we created in the first tutorial:
|
||||||
|
|
||||||
.. image:: http://media.djangoproject.com/img/doc/tutorial-trunk/admin04t.png
|
.. image:: _images/admin04t.png
|
||||||
:alt: Polls change list page
|
:alt: Polls change list page
|
||||||
:target: http://media.djangoproject.com/img/doc/tutorial-trunk/admin04.png
|
|
||||||
|
|
||||||
Click the "What's up?" poll to edit it:
|
Click the "What's up?" poll to edit it:
|
||||||
|
|
||||||
.. image:: http://media.djangoproject.com/img/doc/tutorial-trunk/admin05t.png
|
.. image:: _images/admin05t.png
|
||||||
:alt: Editing form for poll object
|
:alt: Editing form for poll object
|
||||||
:target: http://media.djangoproject.com/img/doc/tutorial-trunk/admin05.png
|
|
||||||
|
|
||||||
Things to note here:
|
Things to note here:
|
||||||
|
|
||||||
* The form is automatically generated from the Poll model.
|
* The form is automatically generated from the Poll model.
|
||||||
* The different model field types (``models.DateTimeField``, ``models.CharField``)
|
|
||||||
correspond to the appropriate HTML input widget. Each type of field knows
|
* The different model field types (:class:`~django.db.models.DateTimeField`,
|
||||||
how to display itself in the Django admin.
|
:class:`~django.db.models.CharField`) correspond to the appropriate HTML
|
||||||
* Each ``DateTimeField`` gets free JavaScript shortcuts. Dates get a "Today"
|
input widget. Each type of field knows how to display itself in the Django
|
||||||
shortcut and calendar popup, and times get a "Now" shortcut and a convenient
|
admin.
|
||||||
popup that lists commonly entered times.
|
|
||||||
|
* Each :class:`~django.db.models.DateTimeField` gets free JavaScript
|
||||||
|
shortcuts. Dates get a "Today" shortcut and calendar popup, and times get
|
||||||
|
a "Now" shortcut and a convenient popup that lists commonly entered times.
|
||||||
|
|
||||||
The bottom part of the page gives you a couple of options:
|
The bottom part of the page gives you a couple of options:
|
||||||
|
|
||||||
* Save -- Saves changes and returns to the change-list page for this type of
|
* Save -- Saves changes and returns to the change-list page for this type of
|
||||||
object.
|
object.
|
||||||
* Save and continue editing -- Saves changes and reloads the admin page for
|
|
||||||
|
* Save and continue editing -- Saves changes and reloads the admin page for
|
||||||
this object.
|
this object.
|
||||||
* Save and add another -- Saves changes and loads a new, blank form for this
|
|
||||||
|
* Save and add another -- Saves changes and loads a new, blank form for this
|
||||||
type of object.
|
type of object.
|
||||||
* Delete -- Displays a delete confirmation page.
|
|
||||||
|
* Delete -- Displays a delete confirmation page.
|
||||||
|
|
||||||
Change the "Date published" by clicking the "Today" and "Now" shortcuts. Then
|
Change the "Date published" by clicking the "Today" and "Now" shortcuts. Then
|
||||||
click "Save and continue editing." Then click "History" in the upper right.
|
click "Save and continue editing." Then click "History" in the upper right.
|
||||||
You'll see a page listing all changes made to this object via the Django admin,
|
You'll see a page listing all changes made to this object via the Django admin,
|
||||||
with the timestamp and username of the person who made the change:
|
with the timestamp and username of the person who made the change:
|
||||||
|
|
||||||
.. image:: http://media.djangoproject.com/img/doc/tutorial-trunk/admin06t.png
|
.. image:: _images/admin06t.png
|
||||||
:alt: History page for poll object
|
:alt: History page for poll object
|
||||||
:target: http://media.djangoproject.com/img/doc/tutorial-trunk/admin06.png
|
|
||||||
|
|
||||||
Customize the admin form
|
Customize the admin form
|
||||||
========================
|
========================
|
||||||
|
@ -184,7 +187,7 @@ admin options for an object.
|
||||||
This particular change above makes the "Publication date" come before the
|
This particular change above makes the "Publication date" come before the
|
||||||
"Question" field:
|
"Question" field:
|
||||||
|
|
||||||
.. image:: http://media.djangoproject.com/img/doc/tutorial-trunk/admin07.png
|
.. image:: _images/admin07.png
|
||||||
:alt: Fields have been reordered
|
:alt: Fields have been reordered
|
||||||
|
|
||||||
This isn't impressive with only two fields, but for admin forms with dozens
|
This isn't impressive with only two fields, but for admin forms with dozens
|
||||||
|
@ -204,9 +207,8 @@ up into fieldsets::
|
||||||
The first element of each tuple in ``fieldsets`` is the title of the fieldset.
|
The first element of each tuple in ``fieldsets`` is the title of the fieldset.
|
||||||
Here's what our form looks like now:
|
Here's what our form looks like now:
|
||||||
|
|
||||||
.. image:: http://media.djangoproject.com/img/doc/tutorial-trunk/admin08t.png
|
.. image:: _images/admin08t.png
|
||||||
:alt: Form has fieldsets now
|
:alt: Form has fieldsets now
|
||||||
:target: http://media.djangoproject.com/img/doc/tutorial-trunk/admin08.png
|
|
||||||
|
|
||||||
You can assign arbitrary HTML classes to each fieldset. Django provides a
|
You can assign arbitrary HTML classes to each fieldset. Django provides a
|
||||||
``"collapse"`` class that displays a particular fieldset initially collapsed.
|
``"collapse"`` class that displays a particular fieldset initially collapsed.
|
||||||
|
@ -219,7 +221,7 @@ aren't commonly used::
|
||||||
('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
|
('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
|
||||||
]
|
]
|
||||||
|
|
||||||
.. image:: http://media.djangoproject.com/img/doc/tutorial-trunk/admin09.png
|
.. image:: _images/admin09.png
|
||||||
:alt: Fieldset is initially collapsed
|
:alt: Fieldset is initially collapsed
|
||||||
|
|
||||||
Adding related objects
|
Adding related objects
|
||||||
|
@ -233,17 +235,20 @@ Yet.
|
||||||
There are two ways to solve this problem. The first register ``Choice`` with the
|
There are two ways to solve this problem. The first register ``Choice`` with the
|
||||||
admin just as we did with ``Poll``. That's easy::
|
admin just as we did with ``Poll``. That's easy::
|
||||||
|
|
||||||
|
from mysite.polls.models import Choice
|
||||||
|
|
||||||
admin.site.register(Choice)
|
admin.site.register(Choice)
|
||||||
|
|
||||||
Now "Choices" is an available option in the Django admin. The "Add choice" form
|
Now "Choices" is an available option in the Django admin. The "Add choice" form
|
||||||
looks like this:
|
looks like this:
|
||||||
|
|
||||||
.. image:: http://media.djangoproject.com/img/doc/tutorial-trunk/admin10.png
|
.. image:: _images/admin10.png
|
||||||
:alt: Choice admin page
|
:alt: Choice admin page
|
||||||
|
|
||||||
In that form, the "Poll" field is a select box containing every poll in the
|
In that form, the "Poll" field is a select box containing every poll in the
|
||||||
database. Django knows that a ``ForeignKey`` should be represented in the admin
|
database. Django knows that a :class:`~django.db.models.ForeignKey` should be
|
||||||
as a ``<select>`` box. In our case, only one poll exists at this point.
|
represented in the admin as a ``<select>`` box. In our case, only one poll
|
||||||
|
exists at this point.
|
||||||
|
|
||||||
Also note the "Add Another" link next to "Poll." Every object with a
|
Also note the "Add Another" link next to "Poll." Every object with a
|
||||||
``ForeignKey`` relationship to another gets this for free. When you click "Add
|
``ForeignKey`` relationship to another gets this for free. When you click "Add
|
||||||
|
@ -259,6 +264,7 @@ Poll object. Let's make that happen.
|
||||||
Remove the ``register()`` call for the Choice model. Then, edit the ``Poll``
|
Remove the ``register()`` call for the Choice model. Then, edit the ``Poll``
|
||||||
registration code to read::
|
registration code to read::
|
||||||
|
|
||||||
|
poll = models.ForeignKey(Poll, edit_inline=models.STACKED, num_in_admin=3)
|
||||||
class ChoiceInline(admin.StackedInline):
|
class ChoiceInline(admin.StackedInline):
|
||||||
model = Choice
|
model = Choice
|
||||||
extra = 3
|
extra = 3
|
||||||
|
@ -277,16 +283,15 @@ default, provide enough fields for 3 choices."
|
||||||
|
|
||||||
Load the "Add poll" page to see how that looks:
|
Load the "Add poll" page to see how that looks:
|
||||||
|
|
||||||
.. image:: http://media.djangoproject.com/img/doc/tutorial-trunk/admin11t.png
|
.. image:: _images/admin11t.png
|
||||||
:alt: Add poll page now has choices on it
|
:alt: Add poll page now has choices on it
|
||||||
:target: http://media.djangoproject.com/img/doc/tutorial-trunk/admin11.png
|
|
||||||
|
|
||||||
It works like this: There are three slots for related Choices -- as specified
|
It works like this: There are three slots for related Choices -- as specified
|
||||||
by ``extra`` -- and each time you come back to the "Change" page for an
|
by ``extra`` -- and each time you come back to the "Change" page for an
|
||||||
already-created object, you get another three extra slots.
|
already-created object, you get another three extra slots.
|
||||||
|
|
||||||
One small problem, though. It takes a lot of screen space to display all the
|
One small problem, though. It takes a lot of screen space to display all the
|
||||||
fields for entering related Choice objects. For that reason, Django offers an
|
fields for entering related Choice objects. For that reason, Django offers a
|
||||||
tabular way of displaying inline related objects; you just need to change
|
tabular way of displaying inline related objects; you just need to change
|
||||||
the ``ChoiceInline`` declaration to read::
|
the ``ChoiceInline`` declaration to read::
|
||||||
|
|
||||||
|
@ -296,7 +301,7 @@ the ``ChoiceInline`` declaration to read::
|
||||||
With that ``TabularInline`` (instead of ``StackedInline``), the
|
With that ``TabularInline`` (instead of ``StackedInline``), the
|
||||||
related objects are displayed in a more compact, table-based format:
|
related objects are displayed in a more compact, table-based format:
|
||||||
|
|
||||||
.. image:: http://media.djangoproject.com/img/doc/tutorial-trunk/admin12.png
|
.. image:: _images/admin12.png
|
||||||
:alt: Add poll page now has more compact choices
|
:alt: Add poll page now has more compact choices
|
||||||
|
|
||||||
Customize the admin change list
|
Customize the admin change list
|
||||||
|
@ -307,9 +312,8 @@ Now that the Poll admin page is looking good, let's make some tweaks to the
|
||||||
|
|
||||||
Here's what it looks like at this point:
|
Here's what it looks like at this point:
|
||||||
|
|
||||||
.. image:: http://media.djangoproject.com/img/doc/tutorial-trunk/admin04t.png
|
.. image:: _images/admin04t.png
|
||||||
:alt: Polls change list page
|
:alt: Polls change list page
|
||||||
:target: http://media.djangoproject.com/img/doc/tutorial-trunk/admin04.png
|
|
||||||
|
|
||||||
By default, Django displays the ``str()`` of each object. But sometimes it'd be
|
By default, Django displays the ``str()`` of each object. But sometimes it'd be
|
||||||
more helpful if we could display individual fields. To do that, use the
|
more helpful if we could display individual fields. To do that, use the
|
||||||
|
@ -329,9 +333,8 @@ method from Tutorial 1::
|
||||||
|
|
||||||
Now the poll change list page looks like this:
|
Now the poll change list page looks like this:
|
||||||
|
|
||||||
.. image:: http://media.djangoproject.com/img/doc/tutorial-trunk/admin13t.png
|
.. image:: _images/admin13t.png
|
||||||
:alt: Polls change list page, updated
|
:alt: Polls change list page, updated
|
||||||
:target: http://media.djangoproject.com/img/doc/tutorial-trunk/admin13.png
|
|
||||||
|
|
||||||
You can click on the column headers to sort by those values -- except in the
|
You can click on the column headers to sort by those values -- except in the
|
||||||
case of the ``was_published_today`` header, because sorting by the output of
|
case of the ``was_published_today`` header, because sorting by the output of
|
||||||
|
@ -352,9 +355,8 @@ following line to ``PollAdmin``::
|
||||||
That adds a "Filter" sidebar that lets people filter the change list by the
|
That adds a "Filter" sidebar that lets people filter the change list by the
|
||||||
``pub_date`` field:
|
``pub_date`` field:
|
||||||
|
|
||||||
.. image:: http://media.djangoproject.com/img/doc/tutorial-trunk/admin14t.png
|
.. image:: _images/admin14t.png
|
||||||
:alt: Polls change list page, updated
|
:alt: Polls change list page, updated
|
||||||
:target: http://media.djangoproject.com/img/doc/tutorial-trunk/admin14.png
|
|
||||||
|
|
||||||
The type of filter displayed depends on the type of field you're filtering on.
|
The type of filter displayed depends on the type of field you're filtering on.
|
||||||
Because ``pub_date`` is a DateTimeField, Django knows to give the default
|
Because ``pub_date`` is a DateTimeField, Django knows to give the default
|
||||||
|
@ -395,11 +397,12 @@ is powered by Django itself, and its interfaces use Django's own template
|
||||||
system. (How meta!)
|
system. (How meta!)
|
||||||
|
|
||||||
Open your settings file (``mysite/settings.py``, remember) and look at the
|
Open your settings file (``mysite/settings.py``, remember) and look at the
|
||||||
``TEMPLATE_DIRS`` setting. ``TEMPLATE_DIRS`` is a tuple of filesystem
|
:setting:`TEMPLATE_DIRS` setting. :setting:`TEMPLATE_DIRS` is a tuple of
|
||||||
directories to check when loading Django templates. It's a search path.
|
filesystem directories to check when loading Django templates. It's a search
|
||||||
|
path.
|
||||||
|
|
||||||
By default, ``TEMPLATE_DIRS`` is empty. So, let's add a line to it, to tell
|
By default, :setting:`TEMPLATE_DIRS` is empty. So, let's add a line to it, to
|
||||||
Django where our templates live::
|
tell Django where our templates live::
|
||||||
|
|
||||||
TEMPLATE_DIRS = (
|
TEMPLATE_DIRS = (
|
||||||
"/home/my_username/mytemplates", # Change this to your own directory.
|
"/home/my_username/mytemplates", # Change this to your own directory.
|
||||||
|
@ -407,9 +410,10 @@ Django where our templates live::
|
||||||
|
|
||||||
Now copy the template ``admin/base_site.html`` from within the default Django
|
Now copy the template ``admin/base_site.html`` from within the default Django
|
||||||
admin template directory (``django/contrib/admin/templates``) into an ``admin``
|
admin template directory (``django/contrib/admin/templates``) into an ``admin``
|
||||||
subdirectory of whichever directory you're using in ``TEMPLATE_DIRS``. For
|
subdirectory of whichever directory you're using in :setting:`TEMPLATE_DIRS`.
|
||||||
example, if your ``TEMPLATE_DIRS`` includes ``"/home/my_username/mytemplates"``,
|
For example, if your :setting:`TEMPLATE_DIRS` includes
|
||||||
as above, then copy ``django/contrib/admin/templates/admin/base_site.html`` to
|
``"/home/my_username/mytemplates"``, as above, then copy
|
||||||
|
``django/contrib/admin/templates/admin/base_site.html`` to
|
||||||
``/home/my_username/mytemplates/admin/base_site.html``. Don't forget that
|
``/home/my_username/mytemplates/admin/base_site.html``. Don't forget that
|
||||||
``admin`` subdirectory.
|
``admin`` subdirectory.
|
||||||
|
|
||||||
|
@ -421,13 +425,11 @@ override a template, just do the same thing you did with ``base_site.html`` --
|
||||||
copy it from the default directory into your custom directory, and make
|
copy it from the default directory into your custom directory, and make
|
||||||
changes.
|
changes.
|
||||||
|
|
||||||
Astute readers will ask: But if ``TEMPLATE_DIRS`` was empty by default, how was
|
Astute readers will ask: But if :setting:`TEMPLATE_DIRS` was empty by default,
|
||||||
Django finding the default admin templates? The answer is that, by default,
|
how was Django finding the default admin templates? The answer is that, by
|
||||||
Django automatically looks for a ``templates/`` subdirectory within each app
|
default, Django automatically looks for a ``templates/`` subdirectory within
|
||||||
package, for use as a fallback. See the `loader types documentation`_ for full
|
each app package, for use as a fallback. See the :ref:`template loader
|
||||||
information.
|
documentation <template-loaders>` for full information.
|
||||||
|
|
||||||
.. _loader types documentation: ../templates_python/#loader-types
|
|
||||||
|
|
||||||
Customize the admin index page
|
Customize the admin index page
|
||||||
==============================
|
==============================
|
||||||
|
@ -435,10 +437,10 @@ Customize the admin index page
|
||||||
On a similar note, you might want to customize the look and feel of the Django
|
On a similar note, you might want to customize the look and feel of the Django
|
||||||
admin index page.
|
admin index page.
|
||||||
|
|
||||||
By default, it displays all the apps in your ``INSTALLED_APPS`` setting that
|
By default, it displays all the apps in :setting:`INSTALLED_APPS` that have been
|
||||||
have been registered with the admin application, in alphabetical order. You
|
registered with the admin application, in alphabetical order. You may want to
|
||||||
may want to make significant changes to the layout. After all, the index is
|
make significant changes to the layout. After all, the index is probably the
|
||||||
probably the most important page of the admin, and it should be easy to use.
|
most important page of the admin, and it should be easy to use.
|
||||||
|
|
||||||
The template to customize is ``admin/index.html``. (Do the same as with
|
The template to customize is ``admin/index.html``. (Do the same as with
|
||||||
``admin/base_site.html`` in the previous section -- copy it from the default
|
``admin/base_site.html`` in the previous section -- copy it from the default
|
||||||
|
@ -447,15 +449,9 @@ uses a template variable called ``app_list``. That variable contains every
|
||||||
installed Django app. Instead of using that, you can hard-code links to
|
installed Django app. Instead of using that, you can hard-code links to
|
||||||
object-specific admin pages in whatever way you think is best.
|
object-specific admin pages in whatever way you think is best.
|
||||||
|
|
||||||
Django offers another shortcut in this department. Run the command
|
Django offers another shortcut in this department. Run the command ``python
|
||||||
``python manage.py adminindex polls`` to get a chunk of template code for
|
manage.py adminindex polls`` to get a chunk of template code for inclusion in
|
||||||
inclusion in the admin index template. It's a useful starting point.
|
the admin index template. It's a useful starting point.
|
||||||
|
|
||||||
For full details on customizing the look and feel of the Django admin site in
|
When you're comfortable with the admin site, read :ref:`part 3 of this tutorial
|
||||||
general, see the `Django admin CSS guide`_.
|
<intro-tutorial03>` to start working on public poll views.
|
||||||
|
|
||||||
When you're comfortable with the admin site, read `part 3 of this tutorial`_ to
|
|
||||||
start working on public poll views.
|
|
||||||
|
|
||||||
.. _Django admin CSS guide: ../admin_css/
|
|
||||||
.. _part 3 of this tutorial: ../tutorial03/
|
|
|
@ -1,11 +1,12 @@
|
||||||
|
.. _intro-tutorial03:
|
||||||
|
|
||||||
=====================================
|
=====================================
|
||||||
Writing your first Django app, part 3
|
Writing your first Django app, part 3
|
||||||
=====================================
|
=====================================
|
||||||
|
|
||||||
This tutorial begins where `Tutorial 2`_ left off. We're continuing the Web-poll
|
This tutorial begins where :ref:`Tutorial 2 <intro-tutorial02>` left off. We're
|
||||||
application and will focus on creating the public interface -- "views."
|
continuing the Web-poll application and will focus on creating the public
|
||||||
|
interface -- "views."
|
||||||
.. _Tutorial 2: ../tutorial02/
|
|
||||||
|
|
||||||
Philosophy
|
Philosophy
|
||||||
==========
|
==========
|
||||||
|
@ -15,20 +16,28 @@ a specific function and has a specific template. For example, in a weblog
|
||||||
application, you might have the following views:
|
application, you might have the following views:
|
||||||
|
|
||||||
* Blog homepage -- displays the latest few entries.
|
* Blog homepage -- displays the latest few entries.
|
||||||
|
|
||||||
* Entry "detail" page -- permalink page for a single entry.
|
* Entry "detail" page -- permalink page for a single entry.
|
||||||
|
|
||||||
* Year-based archive page -- displays all months with entries in the
|
* Year-based archive page -- displays all months with entries in the
|
||||||
given year.
|
given year.
|
||||||
|
|
||||||
* Month-based archive page -- displays all days with entries in the
|
* Month-based archive page -- displays all days with entries in the
|
||||||
given month.
|
given month.
|
||||||
|
|
||||||
* Day-based archive page -- displays all entries in the given day.
|
* Day-based archive page -- displays all entries in the given day.
|
||||||
|
|
||||||
* Comment action -- handles posting comments to a given entry.
|
* Comment action -- handles posting comments to a given entry.
|
||||||
|
|
||||||
In our poll application, we'll have the following four views:
|
In our poll application, we'll have the following four views:
|
||||||
|
|
||||||
* Poll "archive" page -- displays the latest few polls.
|
* Poll "archive" page -- displays the latest few polls.
|
||||||
|
|
||||||
* Poll "detail" page -- displays a poll question, with no results but
|
* Poll "detail" page -- displays a poll question, with no results but
|
||||||
with a form to vote.
|
with a form to vote.
|
||||||
|
|
||||||
* Poll "results" page -- displays results for a particular poll.
|
* Poll "results" page -- displays results for a particular poll.
|
||||||
|
|
||||||
* Vote action -- handles voting for a particular choice in a particular
|
* Vote action -- handles voting for a particular choice in a particular
|
||||||
poll.
|
poll.
|
||||||
|
|
||||||
|
@ -42,8 +51,8 @@ creating a Python module, called a URLconf. URLconfs are how Django associates
|
||||||
a given URL with given Python code.
|
a given URL with given Python code.
|
||||||
|
|
||||||
When a user requests a Django-powered page, the system looks at the
|
When a user requests a Django-powered page, the system looks at the
|
||||||
``ROOT_URLCONF`` setting, which contains a string in Python dotted syntax.
|
:setting:`ROOT_URLCONF` setting, which contains a string in Python dotted
|
||||||
Django loads that module and looks for a module-level variable called
|
syntax. Django loads that module and looks for a module-level variable called
|
||||||
``urlpatterns``, which is a sequence of tuples in the following format::
|
``urlpatterns``, which is a sequence of tuples in the following format::
|
||||||
|
|
||||||
(regular expression, Python callback function [, optional dictionary])
|
(regular expression, Python callback function [, optional dictionary])
|
||||||
|
@ -53,17 +62,19 @@ comparing the requested URL against each regular expression until it finds one
|
||||||
that matches.
|
that matches.
|
||||||
|
|
||||||
When it finds a match, Django calls the Python callback function, with an
|
When it finds a match, Django calls the Python callback function, with an
|
||||||
``HTTPRequest`` object as the first argument, any "captured" values from the
|
:class:`~django.http.HttpRequest` object as the first argument, any "captured"
|
||||||
regular expression as keyword arguments, and, optionally, arbitrary keyword
|
values from the regular expression as keyword arguments, and, optionally,
|
||||||
arguments from the dictionary (an optional third item in the tuple).
|
arbitrary keyword arguments from the dictionary (an optional third item in the
|
||||||
|
tuple).
|
||||||
|
|
||||||
For more on ``HTTPRequest`` objects, see the `request and response documentation`_.
|
For more on :class:`~django.http.HttpRequest` objects, see the
|
||||||
For more details on URLconfs, see the `URLconf documentation`_.
|
:ref:`ref-request-response`. For more details on URLconfs, see the
|
||||||
|
:ref:`topics-http-urls`.
|
||||||
|
|
||||||
When you ran ``python django-admin.py startproject mysite`` at the beginning of
|
When you ran ``python django-admin.py startproject mysite`` at the beginning of
|
||||||
Tutorial 1, it created a default URLconf in ``mysite/urls.py``. It also
|
Tutorial 1, it created a default URLconf in ``mysite/urls.py``. It also
|
||||||
automatically set your ``ROOT_URLCONF`` setting (in ``settings.py``) to point
|
automatically set your :setting:`ROOT_URLCONF` setting (in ``settings.py``) to
|
||||||
at that file::
|
point at that file::
|
||||||
|
|
||||||
ROOT_URLCONF = 'mysite.urls'
|
ROOT_URLCONF = 'mysite.urls'
|
||||||
|
|
||||||
|
@ -78,27 +89,27 @@ Time for an example. Edit ``mysite/urls.py`` so it looks like this::
|
||||||
(r'^polls/(?P<poll_id>\d+)/vote/$', 'mysite.polls.views.vote'),
|
(r'^polls/(?P<poll_id>\d+)/vote/$', 'mysite.polls.views.vote'),
|
||||||
)
|
)
|
||||||
|
|
||||||
This is worth a review. When somebody requests a page from your Web site --
|
This is worth a review. When somebody requests a page from your Web site -- say,
|
||||||
say, "/polls/23/", Django will load this Python module, because it's pointed to
|
"/polls/23/", Django will load this Python module, because it's pointed to by
|
||||||
by the ``ROOT_URLCONF`` setting. It finds the variable named ``urlpatterns``
|
the :setting:`ROOT_URLCONF` setting. It finds the variable named ``urlpatterns``
|
||||||
and traverses the regular expressions in order. When it finds a regular
|
and traverses the regular expressions in order. When it finds a regular
|
||||||
expression that matches -- ``r'^polls/(?P<poll_id>\d+)/$'`` -- it loads the
|
expression that matches -- ``r'^polls/(?P<poll_id>\d+)/$'`` -- it loads the
|
||||||
associated Python package/module: ``mysite.polls.views.detail``. That
|
associated Python package/module: ``mysite.polls.views.detail``. That
|
||||||
corresponds to the function ``detail()`` in ``mysite/polls/views.py``.
|
corresponds to the function ``detail()`` in ``mysite/polls/views.py``. Finally,
|
||||||
Finally, it calls that ``detail()`` function like so::
|
it calls that ``detail()`` function like so::
|
||||||
|
|
||||||
detail(request=<HttpRequest object>, poll_id='23')
|
detail(request=<HttpRequest object>, poll_id='23')
|
||||||
|
|
||||||
The ``poll_id='23'`` part comes from ``(?P<poll_id>\d+)``. Using parenthesis around a
|
The ``poll_id='23'`` part comes from ``(?P<poll_id>\d+)``. Using parenthesis
|
||||||
pattern "captures" the text matched by that pattern and sends it as an argument
|
around a pattern "captures" the text matched by that pattern and sends it as an
|
||||||
to the view function; the ``?P<poll_id>`` defines the name that will be used to
|
argument to the view function; the ``?P<poll_id>`` defines the name that will be
|
||||||
identify the matched pattern; and ``\d+`` is a regular expression to match a sequence of
|
used to identify the matched pattern; and ``\d+`` is a regular expression to
|
||||||
digits (i.e., a number).
|
match a sequence of digits (i.e., a number).
|
||||||
|
|
||||||
Because the URL patterns are regular expressions, there really is no limit on
|
Because the URL patterns are regular expressions, there really is no limit on
|
||||||
what you can do with them. And there's no need to add URL cruft such as
|
what you can do with them. And there's no need to add URL cruft such as ``.php``
|
||||||
``.php`` -- unless you have a sick sense of humor, in which case you can do
|
-- unless you have a sick sense of humor, in which case you can do something
|
||||||
something like this::
|
like this::
|
||||||
|
|
||||||
(r'^polls/latest\.php$', 'mysite.polls.views.index'),
|
(r'^polls/latest\.php$', 'mysite.polls.views.index'),
|
||||||
|
|
||||||
|
@ -110,16 +121,14 @@ the URLconf will look for ``/myapp/``. In a request to
|
||||||
``http://www.example.com/myapp/?page=3``, the URLconf will look for ``/myapp/``.
|
``http://www.example.com/myapp/?page=3``, the URLconf will look for ``/myapp/``.
|
||||||
|
|
||||||
If you need help with regular expressions, see `Wikipedia's entry`_ and the
|
If you need help with regular expressions, see `Wikipedia's entry`_ and the
|
||||||
`Python documentation`_. Also, the O'Reilly book "Mastering Regular
|
`Python documentation`_. Also, the O'Reilly book "Mastering Regular Expressions"
|
||||||
Expressions" by Jeffrey Friedl is fantastic.
|
by Jeffrey Friedl is fantastic.
|
||||||
|
|
||||||
Finally, a performance note: these regular expressions are compiled the first
|
Finally, a performance note: these regular expressions are compiled the first
|
||||||
time the URLconf module is loaded. They're super fast.
|
time the URLconf module is loaded. They're super fast.
|
||||||
|
|
||||||
.. _Wikipedia's entry: http://en.wikipedia.org/wiki/Regular_expression
|
.. _Wikipedia's entry: http://en.wikipedia.org/wiki/Regular_expression
|
||||||
.. _Python documentation: http://www.python.org/doc/current/lib/module-re.html
|
.. _Python documentation: http://www.python.org/doc/current/lib/module-re.html
|
||||||
.. _request and response documentation: ../request_response/
|
|
||||||
.. _URLconf documentation: ../url_dispatch/
|
|
||||||
|
|
||||||
Write your first view
|
Write your first view
|
||||||
=====================
|
=====================
|
||||||
|
@ -127,7 +136,9 @@ Write your first view
|
||||||
Well, we haven't created any views yet -- we just have the URLconf. But let's
|
Well, we haven't created any views yet -- we just have the URLconf. But let's
|
||||||
make sure Django is following the URLconf properly.
|
make sure Django is following the URLconf properly.
|
||||||
|
|
||||||
Fire up the Django development Web server::
|
Fire up the Django development Web server:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
python manage.py runserver
|
python manage.py runserver
|
||||||
|
|
||||||
|
@ -170,21 +181,22 @@ provide in the URL.
|
||||||
Write views that actually do something
|
Write views that actually do something
|
||||||
======================================
|
======================================
|
||||||
|
|
||||||
Each view is responsible for doing one of two things: Returning an ``HttpResponse``
|
Each view is responsible for doing one of two things: Returning an
|
||||||
object containing the content for the requested page, or raising an exception
|
:class:`~django.http.HttpResponse` object containing the content for the
|
||||||
such as ``Http404``. The rest is up to you.
|
requested page, or raising an exception such as :exc:`~django.http.Http404`. The
|
||||||
|
rest is up to you.
|
||||||
|
|
||||||
Your view can read records from a database, or not. It can use a template
|
Your view can read records from a database, or not. It can use a template
|
||||||
system such as Django's -- or a third-party Python template system -- or not.
|
system such as Django's -- or a third-party Python template system -- or not.
|
||||||
It can generate a PDF file, output XML, create a ZIP file on the fly, anything
|
It can generate a PDF file, output XML, create a ZIP file on the fly, anything
|
||||||
you want, using whatever Python libraries you want.
|
you want, using whatever Python libraries you want.
|
||||||
|
|
||||||
All Django wants is that ``HttpResponse``. Or an exception.
|
All Django wants is that :class:`~django.http.HttpResponse`. Or an exception.
|
||||||
|
|
||||||
Because it's convenient, let's use Django's own database API, which we covered
|
Because it's convenient, let's use Django's own database API, which we covered
|
||||||
in Tutorial 1. Here's one stab at the ``index()`` view, which displays the
|
in :ref:`Tutorial 1 <intro-tutorial01>`. Here's one stab at the ``index()``
|
||||||
latest 5 poll questions in the system, separated by commas, according to
|
view, which displays the latest 5 poll questions in the system, separated by
|
||||||
publication date::
|
commas, according to publication date::
|
||||||
|
|
||||||
from mysite.polls.models import Poll
|
from mysite.polls.models import Poll
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
|
@ -210,8 +222,8 @@ So let's use Django's template system to separate the design from Python::
|
||||||
})
|
})
|
||||||
return HttpResponse(t.render(c))
|
return HttpResponse(t.render(c))
|
||||||
|
|
||||||
That code loads the template called "polls/index.html" and passes it a context. The
|
That code loads the template called "polls/index.html" and passes it a context.
|
||||||
context is a dictionary mapping template variable names to Python objects.
|
The context is a dictionary mapping template variable names to Python objects.
|
||||||
|
|
||||||
Reload the page. Now you'll see an error::
|
Reload the page. Now you'll see an error::
|
||||||
|
|
||||||
|
@ -219,20 +231,21 @@ Reload the page. Now you'll see an error::
|
||||||
polls/index.html
|
polls/index.html
|
||||||
|
|
||||||
Ah. There's no template yet. First, create a directory, somewhere on your
|
Ah. There's no template yet. First, create a directory, somewhere on your
|
||||||
filesystem, whose contents Django can access. (Django runs as whatever user
|
filesystem, whose contents Django can access. (Django runs as whatever user your
|
||||||
your server runs.) Don't put them under your document root, though. You
|
server runs.) Don't put them under your document root, though. You probably
|
||||||
probably shouldn't make them public, just for security's sake.
|
shouldn't make them public, just for security's sake.
|
||||||
|
Then edit :setting:`TEMPLATE_DIRS` in your ``settings.py`` to tell Django where
|
||||||
Then edit ``TEMPLATE_DIRS`` in your ``settings.py`` to tell Django where it can
|
it can find templates -- just as you did in the "Customize the admin look and
|
||||||
find templates -- just as you did in the "Customize the admin look and feel"
|
feel" section of Tutorial 2.
|
||||||
section of Tutorial 2.
|
|
||||||
|
|
||||||
When you've done that, create a directory ``polls`` in your template directory.
|
When you've done that, create a directory ``polls`` in your template directory.
|
||||||
Within that, create a file called ``index.html``. Note that our
|
Within that, create a file called ``index.html``. Note that our
|
||||||
``loader.get_template('polls/index.html')`` code from above maps to
|
``loader.get_template('polls/index.html')`` code from above maps to
|
||||||
"[template_directory]/polls/index.html" on the filesystem.
|
"[template_directory]/polls/index.html" on the filesystem.
|
||||||
|
|
||||||
Put the following code in that template::
|
Put the following code in that template:
|
||||||
|
|
||||||
|
.. code-block:: html+django
|
||||||
|
|
||||||
{% if latest_poll_list %}
|
{% if latest_poll_list %}
|
||||||
<ul>
|
<ul>
|
||||||
|
@ -251,8 +264,9 @@ A shortcut: render_to_response()
|
||||||
--------------------------------
|
--------------------------------
|
||||||
|
|
||||||
It's a very common idiom to load a template, fill a context and return an
|
It's a very common idiom to load a template, fill a context and return an
|
||||||
``HttpResponse`` object with the result of the rendered template. Django
|
:class:`~django.http.HttpResponse` object with the result of the rendered
|
||||||
provides a shortcut. Here's the full ``index()`` view, rewritten::
|
template. Django provides a shortcut. Here's the full ``index()`` view,
|
||||||
|
rewritten::
|
||||||
|
|
||||||
from django.shortcuts import render_to_response
|
from django.shortcuts import render_to_response
|
||||||
from mysite.polls.models import Poll
|
from mysite.polls.models import Poll
|
||||||
|
@ -261,11 +275,14 @@ provides a shortcut. Here's the full ``index()`` view, rewritten::
|
||||||
latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5]
|
latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5]
|
||||||
return render_to_response('polls/index.html', {'latest_poll_list': latest_poll_list})
|
return render_to_response('polls/index.html', {'latest_poll_list': latest_poll_list})
|
||||||
|
|
||||||
Note that once we've done this in all these views, we no longer need to import ``loader``, ``Context`` and ``HttpResponse``.
|
Note that once we've done this in all these views, we no longer need to import
|
||||||
|
:mod:`~django.template.loader`, :class:`~django.template.Context` and
|
||||||
|
:class:`~django.http.HttpResponse`.
|
||||||
|
|
||||||
The ``render_to_response()`` function takes a template name as its first
|
The :func:`~django.shortcuts.render_to_response` function takes a template name
|
||||||
argument and a dictionary as its optional second argument. It returns an
|
as its first argument and a dictionary as its optional second argument. It
|
||||||
``HttpResponse`` object of the given template rendered with the given context.
|
returns an :class:`~django.http.HttpResponse` object of the given template
|
||||||
|
rendered with the given context.
|
||||||
|
|
||||||
Raising 404
|
Raising 404
|
||||||
===========
|
===========
|
||||||
|
@ -282,15 +299,15 @@ for a given poll. Here's the view::
|
||||||
raise Http404
|
raise Http404
|
||||||
return render_to_response('polls/detail.html', {'poll': p})
|
return render_to_response('polls/detail.html', {'poll': p})
|
||||||
|
|
||||||
The new concept here: The view raises the ``django.http.Http404``
|
The new concept here: The view raises the :exc:`~django.http.Http404` exception
|
||||||
exception if a poll with the requested ID doesn't exist.
|
if a poll with the requested ID doesn't exist.
|
||||||
|
|
||||||
A shortcut: get_object_or_404()
|
A shortcut: get_object_or_404()
|
||||||
-------------------------------
|
-------------------------------
|
||||||
|
|
||||||
It's a very common idiom to use ``get()`` and raise ``Http404`` if the
|
It's a very common idiom to use :meth:`~django.db.models.QuerySet.get` and raise
|
||||||
object doesn't exist. Django provides a shortcut. Here's the ``detail()`` view,
|
:exc:`~django.http.Http404` if the object doesn't exist. Django provides a
|
||||||
rewritten::
|
shortcut. Here's the ``detail()`` view, rewritten::
|
||||||
|
|
||||||
from django.shortcuts import render_to_response, get_object_or_404
|
from django.shortcuts import render_to_response, get_object_or_404
|
||||||
# ...
|
# ...
|
||||||
|
@ -298,32 +315,36 @@ rewritten::
|
||||||
p = get_object_or_404(Poll, pk=poll_id)
|
p = get_object_or_404(Poll, pk=poll_id)
|
||||||
return render_to_response('polls/detail.html', {'poll': p})
|
return render_to_response('polls/detail.html', {'poll': p})
|
||||||
|
|
||||||
The ``get_object_or_404()`` function takes a Django model module as its first
|
The :func:`~django.shortcuts.get_object_or_404` function takes a Django model
|
||||||
argument and an arbitrary number of keyword arguments, which it passes to the
|
module as its first argument and an arbitrary number of keyword arguments, which
|
||||||
module's ``get()`` function. It raises ``Http404`` if the object doesn't
|
it passes to the module's :meth:`~django.db.models.QuerySet.get` function. It
|
||||||
exist.
|
raises :exc:`~django.http.Http404` if the object doesn't exist.
|
||||||
|
|
||||||
.. admonition:: Philosophy
|
.. admonition:: Philosophy
|
||||||
|
|
||||||
Why do we use a helper function ``get_object_or_404()`` instead of
|
Why do we use a helper function :func:`~django.shortcuts.get_object_or_404`
|
||||||
automatically catching the ``DoesNotExist`` exceptions at a higher level,
|
instead of automatically catching the
|
||||||
or having the model API raise ``Http404`` instead of ``DoesNotExist``?
|
:exc:`~django.core.exceptions.ObjectDoesNotExist` exceptions at a higher
|
||||||
|
level, or having the model API raise :exc:`~django.http.Http404` instead of
|
||||||
|
:exc:`~django.core.exceptions.ObjectDoesNotExist`?
|
||||||
|
|
||||||
Because that would couple the model layer to the view layer. One of the
|
Because that would couple the model layer to the view layer. One of the
|
||||||
foremost design goals of Django is to maintain loose coupling.
|
foremost design goals of Django is to maintain loose coupling.
|
||||||
|
|
||||||
There's also a ``get_list_or_404()`` function, which works just as
|
There's also a :func:`~django.shortcuts.get_list_or_404` function, which works
|
||||||
``get_object_or_404()`` -- except using ``filter()`` instead of
|
just as :func:`~django.shortcuts.get_object_or_404` -- except using
|
||||||
``get()``. It raises ``Http404`` if the list is empty.
|
:meth:`~django.db.models.QuerySet.filter` instead of
|
||||||
|
:meth:`~django.db.models.QuerySet.get`. It raises :exc:`~django.http.Http404` if
|
||||||
|
the list is empty.
|
||||||
|
|
||||||
Write a 404 (page not found) view
|
Write a 404 (page not found) view
|
||||||
=================================
|
=================================
|
||||||
|
|
||||||
When you raise ``Http404`` from within a view, Django will load a special view
|
When you raise :exc:`~django.http.Http404` from within a view, Django will load
|
||||||
devoted to handling 404 errors. It finds it by looking for the variable
|
a special view devoted to handling 404 errors. It finds it by looking for the
|
||||||
``handler404``, which is a string in Python dotted syntax -- the same format
|
variable ``handler404``, which is a string in Python dotted syntax -- the same
|
||||||
the normal URLconf callbacks use. A 404 view itself has nothing special: It's
|
format the normal URLconf callbacks use. A 404 view itself has nothing special:
|
||||||
just a normal view.
|
It's just a normal view.
|
||||||
|
|
||||||
You normally won't have to bother with writing 404 views. By default, URLconfs
|
You normally won't have to bother with writing 404 views. By default, URLconfs
|
||||||
have the following line up top::
|
have the following line up top::
|
||||||
|
@ -332,18 +353,20 @@ have the following line up top::
|
||||||
|
|
||||||
That takes care of setting ``handler404`` in the current module. As you can see
|
That takes care of setting ``handler404`` in the current module. As you can see
|
||||||
in ``django/conf/urls/defaults.py``, ``handler404`` is set to
|
in ``django/conf/urls/defaults.py``, ``handler404`` is set to
|
||||||
``'django.views.defaults.page_not_found'`` by default.
|
:func:`django.views.defaults.page_not_found` by default.
|
||||||
|
|
||||||
Three more things to note about 404 views:
|
Three more things to note about 404 views:
|
||||||
|
|
||||||
* The 404 view is also called if Django doesn't find a match after checking
|
* The 404 view is also called if Django doesn't find a match after checking
|
||||||
every regular expression in the URLconf.
|
every regular expression in the URLconf.
|
||||||
* If you don't define your own 404 view -- and simply use the default,
|
|
||||||
which is recommended -- you still have one obligation: To create a
|
* If you don't define your own 404 view -- and simply use the default, which
|
||||||
``404.html`` template in the root of your template directory. The default
|
is recommended -- you still have one obligation: To create a ``404.html``
|
||||||
404 view will use that template for all 404 errors.
|
template in the root of your template directory. The default 404 view will
|
||||||
* If ``DEBUG`` is set to ``True`` (in your settings module) then your 404
|
use that template for all 404 errors.
|
||||||
view will never be used, and the traceback will be displayed instead.
|
|
||||||
|
* If :setting:`DEBUG` is set to ``True`` (in your settings module) then your
|
||||||
|
404 view will never be used, and the traceback will be displayed instead.
|
||||||
|
|
||||||
Write a 500 (server error) view
|
Write a 500 (server error) view
|
||||||
===============================
|
===============================
|
||||||
|
@ -357,7 +380,9 @@ Use the template system
|
||||||
|
|
||||||
Back to the ``detail()`` view for our poll application. Given the context
|
Back to the ``detail()`` view for our poll application. Given the context
|
||||||
variable ``poll``, here's what the "polls/detail.html" template might look
|
variable ``poll``, here's what the "polls/detail.html" template might look
|
||||||
like::
|
like:
|
||||||
|
|
||||||
|
.. code-block:: html+django
|
||||||
|
|
||||||
<h1>{{ poll.question }}</h1>
|
<h1>{{ poll.question }}</h1>
|
||||||
<ul>
|
<ul>
|
||||||
|
@ -376,9 +401,7 @@ Method-calling happens in the ``{% for %}`` loop: ``poll.choice_set.all`` is
|
||||||
interpreted as the Python code ``poll.choice_set.all()``, which returns an
|
interpreted as the Python code ``poll.choice_set.all()``, which returns an
|
||||||
iterable of Choice objects and is suitable for use in the ``{% for %}`` tag.
|
iterable of Choice objects and is suitable for use in the ``{% for %}`` tag.
|
||||||
|
|
||||||
See the `template guide`_ for full details on how templates work.
|
See the :ref:`template guide <topics-templates>` for more about templates.
|
||||||
|
|
||||||
.. _template guide: ../templates/
|
|
||||||
|
|
||||||
Simplifying the URLconfs
|
Simplifying the URLconfs
|
||||||
========================
|
========================
|
||||||
|
@ -397,7 +420,7 @@ Namely, ``mysite.polls.views`` is in every callback.
|
||||||
|
|
||||||
Because this is a common case, the URLconf framework provides a shortcut for
|
Because this is a common case, the URLconf framework provides a shortcut for
|
||||||
common prefixes. You can factor out the common prefixes and add them as the
|
common prefixes. You can factor out the common prefixes and add them as the
|
||||||
first argument to ``patterns()``, like so::
|
first argument to :func:`~django.conf.urls.defaults.patterns`, like so::
|
||||||
|
|
||||||
urlpatterns = patterns('mysite.polls.views',
|
urlpatterns = patterns('mysite.polls.views',
|
||||||
(r'^polls/$', 'index'),
|
(r'^polls/$', 'index'),
|
||||||
|
@ -414,7 +437,7 @@ Decoupling the URLconfs
|
||||||
|
|
||||||
While we're at it, we should take the time to decouple our poll-app URLs from
|
While we're at it, we should take the time to decouple our poll-app URLs from
|
||||||
our Django project configuration. Django apps are meant to be pluggable -- that
|
our Django project configuration. Django apps are meant to be pluggable -- that
|
||||||
is, each particular app should be transferrable to another Django installation
|
is, each particular app should be transferable to another Django installation
|
||||||
with minimal fuss.
|
with minimal fuss.
|
||||||
|
|
||||||
Our poll app is pretty decoupled at this point, thanks to the strict directory
|
Our poll app is pretty decoupled at this point, thanks to the strict directory
|
||||||
|
@ -425,28 +448,29 @@ We've been editing the URLs in ``mysite/urls.py``, but the URL design of an
|
||||||
app is specific to the app, not to the Django installation -- so let's move the
|
app is specific to the app, not to the Django installation -- so let's move the
|
||||||
URLs within the app directory.
|
URLs within the app directory.
|
||||||
|
|
||||||
Copy the file ``mysite/urls.py`` to ``mysite/polls/urls.py``. Then,
|
Copy the file ``mysite/urls.py`` to ``mysite/polls/urls.py``. Then, change
|
||||||
change ``mysite/urls.py`` to remove the poll-specific URLs and insert an
|
``mysite/urls.py`` to remove the poll-specific URLs and insert an
|
||||||
``include()``::
|
:func:`~django.conf.urls.defaults.include`::
|
||||||
|
|
||||||
(r'^polls/', include('mysite.polls.urls')),
|
(r'^polls/', include('mysite.polls.urls')),
|
||||||
|
|
||||||
``include()``, simply, references another URLconf. Note that the regular
|
:func:`~django.conf.urls.defaults.include`, simply, references another URLconf.
|
||||||
expression doesn't have a ``$`` (end-of-string match character) but has the
|
Note that the regular expression doesn't have a ``$`` (end-of-string match
|
||||||
trailing slash. Whenever Django encounters ``include()``, it chops off whatever
|
character) but has the trailing slash. Whenever Django encounters
|
||||||
part of the URL matched up to that point and sends the remaining string to the
|
:func:`~django.conf.urls.defaults.include`, it chops off whatever part of the
|
||||||
included URLconf for further processing.
|
URL matched up to that point and sends the remaining string to the included
|
||||||
|
URLconf for further processing.
|
||||||
|
|
||||||
Here's what happens if a user goes to "/polls/34/" in this system:
|
Here's what happens if a user goes to "/polls/34/" in this system:
|
||||||
|
|
||||||
* Django will find the match at ``'^polls/'``
|
* Django will find the match at ``'^polls/'``
|
||||||
* It will strip off the matching text (``"polls/"``) and send the remaining
|
|
||||||
text -- ``"34/"`` -- to the 'mysite.polls.urls' URLconf for
|
* Then, Django will strip off the matching text (``"polls/"``) and send the
|
||||||
|
remaining text -- ``"34/"`` -- to the 'mysite.polls.urls' URLconf for
|
||||||
further processing.
|
further processing.
|
||||||
|
|
||||||
Now that we've decoupled that, we need to decouple the
|
Now that we've decoupled that, we need to decouple the 'mysite.polls.urls'
|
||||||
'mysite.polls.urls' URLconf by removing the leading "polls/" from each
|
URLconf by removing the leading "polls/" from each line::
|
||||||
line::
|
|
||||||
|
|
||||||
urlpatterns = patterns('mysite.polls.views',
|
urlpatterns = patterns('mysite.polls.views',
|
||||||
(r'^$', 'index'),
|
(r'^$', 'index'),
|
||||||
|
@ -455,14 +479,12 @@ line::
|
||||||
(r'^(?P<poll_id>\d+)/vote/$', 'vote'),
|
(r'^(?P<poll_id>\d+)/vote/$', 'vote'),
|
||||||
)
|
)
|
||||||
|
|
||||||
The idea behind ``include()`` and URLconf decoupling is to make it easy to
|
The idea behind :func:`~django.conf.urls.defaults.include` and URLconf
|
||||||
plug-and-play URLs. Now that polls are in their own URLconf, they can be placed
|
decoupling is to make it easy to plug-and-play URLs. Now that polls are in their
|
||||||
under "/polls/", or under "/fun_polls/", or under "/content/polls/", or any
|
own URLconf, they can be placed under "/polls/", or under "/fun_polls/", or
|
||||||
other URL root, and the app will still work.
|
under "/content/polls/", or any other URL root, and the app will still work.
|
||||||
|
|
||||||
All the poll app cares about is its relative URLs, not its absolute URLs.
|
All the poll app cares about is its relative URLs, not its absolute URLs.
|
||||||
|
|
||||||
When you're comfortable with writing views, read `part 4 of this tutorial`_ to
|
When you're comfortable with writing views, read :ref:`part 4 of this tutorial
|
||||||
learn about simple form processing and generic views.
|
<intro-tutorial04>` to learn about simple form processing and generic views.
|
||||||
|
|
||||||
.. _part 4 of this tutorial: ../tutorial04/
|
|
|
@ -1,15 +1,20 @@
|
||||||
|
.. _intro-tutorial04:
|
||||||
|
|
||||||
=====================================
|
=====================================
|
||||||
Writing your first Django app, part 4
|
Writing your first Django app, part 4
|
||||||
=====================================
|
=====================================
|
||||||
|
|
||||||
This tutorial begins where `Tutorial 3`_ left off. We're continuing the Web-poll
|
This tutorial begins where :ref:`Tutorial 3 <intro-tutorial03>` left off. We're
|
||||||
application and will focus on simple form processing and cutting down our code.
|
continuing the Web-poll application and will focus on simple form processing and
|
||||||
|
cutting down our code.
|
||||||
|
|
||||||
Write a simple form
|
Write a simple form
|
||||||
===================
|
===================
|
||||||
|
|
||||||
Let's update our poll detail template ("polls/detail.html") from the last
|
Let's update our poll detail template ("polls/detail.html") from the last
|
||||||
tutorial, so that the template contains an HTML ``<form>`` element::
|
tutorial, so that the template contains an HTML ``<form>`` element:
|
||||||
|
|
||||||
|
.. code-block:: html+django
|
||||||
|
|
||||||
<h1>{{ poll.question }}</h1>
|
<h1>{{ poll.question }}</h1>
|
||||||
|
|
||||||
|
@ -38,15 +43,12 @@ A quick rundown:
|
||||||
data server-side, use ``method="post"``. This tip isn't specific to
|
data server-side, use ``method="post"``. This tip isn't specific to
|
||||||
Django; it's just good Web development practice.
|
Django; it's just good Web development practice.
|
||||||
|
|
||||||
* ``forloop.counter`` indicates how many times the ``for`` tag has
|
* ``forloop.counter`` indicates how many times the ;ttag:`for` tag has gone
|
||||||
gone through its loop. For more information, see `the
|
through its loop
|
||||||
documentation for the "for" tag`_.
|
|
||||||
|
|
||||||
.. _the documentation for the "for" tag: ../templates/#for
|
|
||||||
|
|
||||||
Now, let's create a Django view that handles the submitted data and does
|
Now, let's create a Django view that handles the submitted data and does
|
||||||
something with it. Remember, in `Tutorial 3`_, we created a URLconf for the
|
something with it. Remember, in :ref:`Tutorial 3 <intro-tutorial03>`, we created
|
||||||
polls application that includes this line::
|
a URLconf for the polls application that includes this line::
|
||||||
|
|
||||||
(r'^(?P<poll_id>\d+)/vote/$', 'mysite.polls.views.vote'),
|
(r'^(?P<poll_id>\d+)/vote/$', 'mysite.polls.views.vote'),
|
||||||
|
|
||||||
|
@ -77,47 +79,52 @@ So let's create a ``vote()`` function in ``mysite/polls/views.py``::
|
||||||
|
|
||||||
This code includes a few things we haven't covered yet in this tutorial:
|
This code includes a few things we haven't covered yet in this tutorial:
|
||||||
|
|
||||||
* ``request.POST`` is a dictionary-like object that lets you access
|
* :attr:`request.POST <django.http.HttpRequest.POST>` is a dictionary-like
|
||||||
submitted data by key name. In this case, ``request.POST['choice']``
|
object that lets you access submitted data by key name. In this case,
|
||||||
returns the ID of the selected choice, as a string. ``request.POST``
|
``request.POST['choice']`` returns the ID of the selected choice, as a
|
||||||
values are always strings.
|
string. :attr:`request.POST <django.http.HttpRequest.POST>` values are
|
||||||
|
always strings.
|
||||||
|
|
||||||
Note that Django also provides ``request.GET`` for accessing GET data
|
Note that Django also provides :attr:`request.GET
|
||||||
in the same way -- but we're explicitly using ``request.POST`` in our
|
<django.http.HttpRequest.GET>` for accessing GET data in the same way --
|
||||||
code, to ensure that data is only altered via a POST call.
|
but we're explicitly using :attr:`request.POST
|
||||||
|
<django.http.HttpRequest.POST>` in our code, to ensure that data is only
|
||||||
|
altered via a POST call.
|
||||||
|
|
||||||
* ``request.POST['choice']`` will raise ``KeyError`` if ``choice`` wasn't
|
* ``request.POST['choice']`` will raise :exc:`KeyError` if ``choice`` wasn't
|
||||||
provided in POST data. The above code checks for ``KeyError`` and
|
provided in POST data. The above code checks for :exc:`KeyError` and
|
||||||
redisplays the poll form with an error message if ``choice`` isn't given.
|
redisplays the poll form with an error message if ``choice`` isn't given.
|
||||||
|
|
||||||
* After incrementing the choice count, the code returns an
|
* After incrementing the choice count, the code returns an
|
||||||
``HttpResponseRedirect`` rather than a normal ``HttpResponse``.
|
:class:`~django.http.HttpResponseRedirect` rather than a normal
|
||||||
``HttpResponseRedirect`` takes a single argument: the URL to which the
|
:class:`~django.http.HttpResponse`.
|
||||||
user will be redirected (see the following point for how we construct
|
:class:`~django.http.HttpResponseRedirect` takes a single argument: the
|
||||||
the URL in this case).
|
URL to which the user will be redirected (see the following point for how
|
||||||
|
we construct the URL in this case).
|
||||||
|
|
||||||
As the Python comment above points out, you should always return an
|
As the Python comment above points out, you should always return an
|
||||||
``HttpResponseRedirect`` after successfully dealing with POST data. This
|
:class:`~django.http.HttpResponseRedirect` after successfully dealing with
|
||||||
tip isn't specific to Django; it's just good Web development practice.
|
POST data. This tip isn't specific to Django; it's just good Web
|
||||||
|
development practice.
|
||||||
|
|
||||||
* We are using the ``reverse()`` function in the ``HttpResponseRedirect``
|
* We are using the :func:`~django.core.urlresolvers.reverse` function in the
|
||||||
constructor in this example. This function helps avoid having to
|
:class:`~django.http.HttpResponseRedirect` constructor in this example.
|
||||||
hardcode a URL in the view function. It is given the name of the view
|
This function helps avoid having to hardcode a URL in the view function.
|
||||||
that we want to pass control to and the variable portion of the URL
|
It is given the name of the view that we want to pass control to and the
|
||||||
pattern that points to that view. In this case, using the URLConf we set
|
variable portion of the URL pattern that points to that view. In this
|
||||||
up in Tutorial 3, this ``reverse()`` call will return a string like ::
|
case, using the URLConf we set up in Tutorial 3, this
|
||||||
|
:func:`~django.core.urlresolvers.reverse` call will return a string like
|
||||||
|
::
|
||||||
|
|
||||||
'/polls/3/results/'
|
'/polls/3/results/'
|
||||||
|
|
||||||
... where the ``3`` is the value of ``p.id``. This redirected URL will
|
... where the ``3`` is the value of ``p.id``. This redirected URL will
|
||||||
then call the ``'results'`` view to display the final page. Note that
|
then call the ``'results'`` view to display the final page. Note that you
|
||||||
you need to use the full name of the view here (including the prefix).
|
need to use the full name of the view here (including the prefix).
|
||||||
|
|
||||||
For more information about ``reverse()``, see the `URL dispatcher`_
|
As mentioned in Tutorial 3, ``request`` is a :class:`~django.http.HttpRequest`
|
||||||
documentation.
|
object. For more on :class:`~django.http.HttpRequest` objects, see the
|
||||||
|
:ref:`request and response documentation <ref-request-response>`.
|
||||||
As mentioned in Tutorial 3, ``request`` is a ``HTTPRequest`` object. For more
|
|
||||||
on ``HTTPRequest`` objects, see the `request and response documentation`_.
|
|
||||||
|
|
||||||
After somebody votes in a poll, the ``vote()`` view redirects to the results
|
After somebody votes in a poll, the ``vote()`` view redirects to the results
|
||||||
page for the poll. Let's write that view::
|
page for the poll. Let's write that view::
|
||||||
|
@ -126,10 +133,13 @@ page for the poll. Let's write that view::
|
||||||
p = get_object_or_404(Poll, pk=poll_id)
|
p = get_object_or_404(Poll, pk=poll_id)
|
||||||
return render_to_response('polls/results.html', {'poll': p})
|
return render_to_response('polls/results.html', {'poll': p})
|
||||||
|
|
||||||
This is almost exactly the same as the ``detail()`` view from `Tutorial 3`_.
|
This is almost exactly the same as the ``detail()`` view from :ref:`Tutorial 3
|
||||||
The only difference is the template name. We'll fix this redundancy later.
|
<intro-tutorial03>`. The only difference is the template name. We'll fix this
|
||||||
|
redundancy later.
|
||||||
|
|
||||||
Now, create a ``results.html`` template::
|
Now, create a ``results.html`` template:
|
||||||
|
|
||||||
|
.. code-block:: html+django
|
||||||
|
|
||||||
<h1>{{ poll.question }}</h1>
|
<h1>{{ poll.question }}</h1>
|
||||||
|
|
||||||
|
@ -143,15 +153,12 @@ Now, go to ``/polls/1/`` in your browser and vote in the poll. You should see a
|
||||||
results page that gets updated each time you vote. If you submit the form
|
results page that gets updated each time you vote. If you submit the form
|
||||||
without having chosen a choice, you should see the error message.
|
without having chosen a choice, you should see the error message.
|
||||||
|
|
||||||
.. _request and response documentation: ../request_response/
|
|
||||||
.. _URL dispatcher: ../url_dispatch#reverse
|
|
||||||
|
|
||||||
Use generic views: Less code is better
|
Use generic views: Less code is better
|
||||||
======================================
|
======================================
|
||||||
|
|
||||||
The ``detail()`` (from `Tutorial 3`_) and ``results()`` views are stupidly
|
The ``detail()`` (from :ref:`Tutorial 3 <intro-tutorial03>`) and ``results()``
|
||||||
simple -- and, as mentioned above, redundant. The ``index()`` view (also from
|
views are stupidly simple -- and, as mentioned above, redundant. The ``index()``
|
||||||
Tutorial 3), which displays a list of polls, is similar.
|
view (also from Tutorial 3), which displays a list of polls, is similar.
|
||||||
|
|
||||||
These views represent a common case of basic Web development: getting data from
|
These views represent a common case of basic Web development: getting data from
|
||||||
the database according to a parameter passed in the URL, loading a template and
|
the database according to a parameter passed in the URL, loading a template and
|
||||||
|
@ -175,7 +182,7 @@ conversion.
|
||||||
|
|
||||||
You should know basic math before you start using a calculator.
|
You should know basic math before you start using a calculator.
|
||||||
|
|
||||||
First, open the polls/urls.py URLconf. It looks like this, according to the
|
First, open the ``polls/urls.py`` URLconf. It looks like this, according to the
|
||||||
tutorial so far::
|
tutorial so far::
|
||||||
|
|
||||||
from django.conf.urls.defaults import *
|
from django.conf.urls.defaults import *
|
||||||
|
@ -203,92 +210,95 @@ Change it like so::
|
||||||
(r'^(?P<poll_id>\d+)/vote/$', 'mysite.polls.views.vote'),
|
(r'^(?P<poll_id>\d+)/vote/$', 'mysite.polls.views.vote'),
|
||||||
)
|
)
|
||||||
|
|
||||||
We're using two generic views here: ``object_list`` and ``object_detail``.
|
We're using two generic views here:
|
||||||
Respectively, those two views abstract the concepts of "display a list of
|
:func:`~django.views.generic.list_detail.object_list` and
|
||||||
objects" and "display a detail page for a particular type of object."
|
:func:`~django.views.generic.list_detail.object_detail`. Respectively, those two
|
||||||
|
views abstract the concepts of "display a list of objects" and "display a detail
|
||||||
|
page for a particular type of object."
|
||||||
|
|
||||||
* Each generic view needs to know what data it will be acting upon. This
|
* Each generic view needs to know what data it will be acting upon. This
|
||||||
data is provided in a dictionary. The ``queryset`` key in this dictionary
|
data is provided in a dictionary. The ``queryset`` key in this dictionary
|
||||||
points to the list of objects to be manipulated by the generic view.
|
points to the list of objects to be manipulated by the generic view.
|
||||||
|
|
||||||
* The ``object_detail`` generic view expects the ID value captured
|
* The :func:`~django.views.generic.list_detail.object_detail` generic view
|
||||||
from the URL to be called ``"object_id"``, so we've changed ``poll_id`` to
|
expects the ID value captured from the URL to be called ``"object_id"``,
|
||||||
``object_id`` for the generic views.
|
so we've changed ``poll_id`` to ``object_id`` for the generic views.
|
||||||
|
|
||||||
* We've added a name, ``poll_results``, to the results view so that we
|
* We've added a name, ``poll_results``, to the results view so that we have
|
||||||
have a way to refer to its URL later on (see the documentation about
|
a way to refer to its URL later on (see the documentation about
|
||||||
`naming URL patterns`_ for information). We're also using the `url()`_
|
:ref:`naming URL patterns <naming-url-patterns>` for information). We're
|
||||||
function from ``django.conf.urls.defaults`` here. It's a good habit to
|
also using the :func:`~django.conf.urls.default.url` function from
|
||||||
use ``url()`` when you are providing a pattern name like this.
|
:mod:`django.conf.urls.defaults` here. It's a good habit to use
|
||||||
|
:func:`~django.conf.urls.defaults.url` when you are providing a pattern
|
||||||
|
name like this.
|
||||||
|
|
||||||
.. _naming URL patterns: ../url_dispatch/#naming-url-patterns
|
By default, the :func:`~django.views.generic.list_detail.object_detail` generic
|
||||||
.. _url(): ../url_dispatch/#url
|
view uses a template called ``<app name>/<model name>_detail.html``. In our
|
||||||
|
case, it'll use the template ``"polls/poll_detail.html"``. Thus, rename your
|
||||||
|
``polls/detail.html`` template to ``polls/poll_detail.html``, and change the
|
||||||
|
:func:`~django.shortcuts.render_to_response` line in ``vote()``.
|
||||||
|
|
||||||
By default, the ``object_detail`` generic view uses a template called
|
Similarly, the :func:`~django.views.generic.list_detail.object_list` generic
|
||||||
``<app name>/<model name>_detail.html``. In our case, it'll use the template
|
view uses a template called ``<app name>/<model name>_list.html``. Thus, rename
|
||||||
``"polls/poll_detail.html"``. Thus, rename your ``polls/detail.html`` template to
|
``polls/index.html`` to ``polls/poll_list.html``.
|
||||||
``polls/poll_detail.html``, and change the ``render_to_response()`` line in
|
|
||||||
``vote()``.
|
|
||||||
|
|
||||||
Similarly, the ``object_list`` generic view uses a template called
|
Because we have more than one entry in the URLconf that uses
|
||||||
``<app name>/<model name>_list.html``. Thus, rename ``polls/index.html`` to
|
:func:`~django.views.generic.list_detail.object_detail` for the polls app, we
|
||||||
``polls/poll_list.html``.
|
manually specify a template name for the results view:
|
||||||
|
|
||||||
Because we have more than one entry in the URLconf that uses ``object_detail``
|
|
||||||
for the polls app, we manually specify a template name for the results view:
|
|
||||||
``template_name='polls/results.html'``. Otherwise, both views would use the same
|
``template_name='polls/results.html'``. Otherwise, both views would use the same
|
||||||
template. Note that we use ``dict()`` to return an altered dictionary in place.
|
template. Note that we use ``dict()`` to return an altered dictionary in place.
|
||||||
|
|
||||||
.. note:: ``all()`` is lazy
|
.. note:: :meth:`django.db.models.QuerySet.all` is lazy
|
||||||
|
|
||||||
It might look a little frightening to see ``Poll.objects.all()`` being used
|
It might look a little frightening to see ``Poll.objects.all()`` being used
|
||||||
in a detail view which only needs one ``Poll`` object, but don't worry;
|
in a detail view which only needs one ``Poll`` object, but don't worry;
|
||||||
``Poll.objects.all()`` is actually a special object called a ``QuerySet``,
|
``Poll.objects.all()`` is actually a special object called a
|
||||||
which is "lazy" and doesn't hit your database until it absolutely has to. By
|
:class:`~django.db.models.QuerySet`, which is "lazy" and doesn't hit your
|
||||||
the time the database query happens, the ``object_detail`` generic view will
|
database until it absolutely has to. By the time the database query happens,
|
||||||
have narrowed its scope down to a single object, so the eventual query will
|
the :func:`~django.views.generic.list_detail.object_detail` generic view
|
||||||
only select one row from the database.
|
will have narrowed its scope down to a single object, so the eventual query
|
||||||
|
will only select one row from the database.
|
||||||
|
|
||||||
If you'd like to know more about how that works, The Django database API
|
If you'd like to know more about how that works, The Django database API
|
||||||
documentation `explains the lazy nature of QuerySet objects`_.
|
documentation :ref:`explains the lazy nature of QuerySet objects
|
||||||
|
<querysets-are-lazy>`.
|
||||||
|
|
||||||
.. _explains the lazy nature of QuerySet objects: ../db-api/#querysets-are-lazy
|
In previous parts of the tutorial, the templates have been provided with a
|
||||||
|
context that contains the ``poll`` and ``latest_poll_list`` context variables.
|
||||||
In previous parts of the tutorial, the templates have been provided with a context
|
However, the generic views provide the variables ``object`` and ``object_list``
|
||||||
that contains the ``poll`` and ``latest_poll_list`` context variables. However,
|
as context. Therefore, you need to change your templates to match the new
|
||||||
the generic views provide the variables ``object`` and ``object_list`` as context.
|
context variables. Go through your templates, and modify any reference to
|
||||||
Therefore, you need to change your templates to match the new context variables.
|
``latest_poll_list`` to :func:`~django.views.generic.list_detail.object_list`,
|
||||||
Go through your templates, and modify any reference to ``latest_poll_list`` to
|
and change any reference to ``poll`` to ``object``.
|
||||||
``object_list``, and change any reference to ``poll`` to ``object``.
|
|
||||||
|
|
||||||
You can now delete the ``index()``, ``detail()`` and ``results()`` views
|
You can now delete the ``index()``, ``detail()`` and ``results()`` views
|
||||||
from ``polls/views.py``. We don't need them anymore -- they have been replaced
|
from ``polls/views.py``. We don't need them anymore -- they have been replaced
|
||||||
by generic views.
|
by generic views.
|
||||||
|
|
||||||
The ``vote()`` view is still required. However, it must be modified to match
|
The ``vote()`` view is still required. However, it must be modified to match the
|
||||||
the new context variables. In the ``render_to_response()`` call, rename the
|
new context variables. In the :func:`~django.shortcuts.render_to_response` call,
|
||||||
``poll`` context variable to ``object``.
|
rename the ``poll`` context variable to ``object``.
|
||||||
|
|
||||||
The last thing to do is fix the URL handling to account for the use of generic
|
The last thing to do is fix the URL handling to account for the use of generic
|
||||||
views. In the vote view above, we used the ``reverse()`` function to avoid
|
views. In the vote view above, we used the
|
||||||
hard-coding our URLs. Now that we've switched to a generic view, we'll need to
|
:func:`~django.core.urlresolvers.reverse` function to avoid hard-coding our
|
||||||
change the ``reverse()`` call to point back to our new generic view. We can't
|
URLs. Now that we've switched to a generic view, we'll need to change the
|
||||||
simply use the view function anymore -- generic views can be (and are) used
|
:func:`~django.core.urlresolvers.reverse` call to point back to our new generic
|
||||||
multiple times -- but we can use the name we've given::
|
view. We can't simply use the view function anymore -- generic views can be (and
|
||||||
|
are) used multiple times -- but we can use the name we've given::
|
||||||
|
|
||||||
return HttpResponseRedirect(reverse('poll_results', args=(p.id,)))
|
return HttpResponseRedirect(reverse('poll_results', args=(p.id,)))
|
||||||
|
|
||||||
Run the server, and use your new polling app based on generic views.
|
Run the server, and use your new polling app based on generic views.
|
||||||
|
|
||||||
For full details on generic views, see the `generic views documentation`_.
|
For full details on generic views, see the :ref:`generic views documentation
|
||||||
|
<topics-http-generic-views>`.
|
||||||
.. _generic views documentation: ../generic_views/
|
|
||||||
|
|
||||||
Coming soon
|
Coming soon
|
||||||
===========
|
===========
|
||||||
|
|
||||||
The tutorial ends here for the time being. But check back soon for the next
|
The tutorial ends here for the time being. Future installments of the tutorial
|
||||||
installments:
|
will cover:
|
||||||
|
|
||||||
* Advanced form processing
|
* Advanced form processing
|
||||||
* Using the RSS framework
|
* Using the RSS framework
|
||||||
|
@ -297,8 +307,5 @@ installments:
|
||||||
* Advanced admin features: Permissions
|
* Advanced admin features: Permissions
|
||||||
* Advanced admin features: Custom JavaScript
|
* Advanced admin features: Custom JavaScript
|
||||||
|
|
||||||
In the meantime, you can read through the rest of the `Django documentation`_
|
In the meantime, you might want to check out some pointers on :ref:`where to go
|
||||||
and start writing your own applications.
|
from here <intro-whatsnext>`
|
||||||
|
|
||||||
.. _Tutorial 3: ../tutorial03/
|
|
||||||
.. _Django documentation: http://www.djangoproject.com/documentation/
|
|
|
@ -0,0 +1,235 @@
|
||||||
|
.. _intro-whatsnext:
|
||||||
|
|
||||||
|
=================
|
||||||
|
What to read next
|
||||||
|
=================
|
||||||
|
|
||||||
|
So you've read all the :ref:`introductory material <intro-index>` and have
|
||||||
|
decided you'd like to keep using Django. We've only just scratched the surface
|
||||||
|
with this intro (in fact, if you've read every single word you've still read
|
||||||
|
less than 10% of the overall documentation).
|
||||||
|
|
||||||
|
So what's next?
|
||||||
|
|
||||||
|
Well, we've always been big fans of learning by doing. At this point you should
|
||||||
|
know enough to start a project of your own and start fooling around. As you need
|
||||||
|
to learn new tricks, come back to the documentation.
|
||||||
|
|
||||||
|
We've put a lot of effort into making Django's documentation useful, easy to
|
||||||
|
read and as complete as possible. The rest of this document explains more about
|
||||||
|
how the documentation works so that you can get the most out of it.
|
||||||
|
|
||||||
|
(Yes, this is documentation about documentation. Rest assured we have no plans
|
||||||
|
to write a document about how to read the document about documentation.)
|
||||||
|
|
||||||
|
Finding documentation
|
||||||
|
=====================
|
||||||
|
|
||||||
|
Django's got a *lot* of documentation -- almost 200,000 words -- so finding what
|
||||||
|
you need can sometimes be tricky. A few good places to start the :ref:`search`
|
||||||
|
and the :ref:`genindex`.
|
||||||
|
|
||||||
|
Or you can just browse around!
|
||||||
|
|
||||||
|
How the documentation is organized
|
||||||
|
==================================
|
||||||
|
|
||||||
|
Django's main documentation is broken up into "chunks" designed to fill
|
||||||
|
different needs:
|
||||||
|
|
||||||
|
* The :ref:`introductory material <intro-index>` is designed for people new
|
||||||
|
to Django -- or to web development in general. It doesn't cover anything
|
||||||
|
in depth, but instead gives a high-level overview of how developing in
|
||||||
|
Django "feels".
|
||||||
|
|
||||||
|
* The :ref:`topic guides <topics-index>`, on the other hand, dive deep into
|
||||||
|
individual parts of Django. There are complete guides to Django's
|
||||||
|
:ref:`model system <topics-db-index>`, :ref:`template engine
|
||||||
|
<topics-templates>`, :ref:`forms framework <topics-forms-index>`, and much
|
||||||
|
more.`
|
||||||
|
|
||||||
|
This is probably where you'll want to spent most of your time; if you work
|
||||||
|
your way through these guides you should come out knowing pretty much
|
||||||
|
everything there is to know about Django.
|
||||||
|
|
||||||
|
* Web development is often broad, not deep -- problems span many domains.
|
||||||
|
We've written a set of :ref:`how-to guides <howto-index>` that answer
|
||||||
|
common "How do I ...?" questions. Here you'll find information about
|
||||||
|
:ref:`generating PDFs with Django <howto-outputting-pdf>`, :ref:`writing
|
||||||
|
custom template tags <howto-custom-template-tags>`, and more.
|
||||||
|
|
||||||
|
Answers to really common questions can also be found in the :ref:`FAQ
|
||||||
|
<faq-index>`.
|
||||||
|
|
||||||
|
* The guides and how-to's don't cover every single class, function, and
|
||||||
|
method available in Django -- that would be overwhelming when you're
|
||||||
|
trying to learn. Instead, details about individual classes, functions,
|
||||||
|
methods, and modules are kept in the :ref:`reference <ref-index>`. This is
|
||||||
|
where you'll turn to find the details of a particular function or
|
||||||
|
whathaveyou.
|
||||||
|
|
||||||
|
* Finally, there's some "specialized" documentation not usually relevant to
|
||||||
|
most developers. This includes the :ref:`release notes <releases-index>`,
|
||||||
|
:ref:`documentation of obsolete features <obsolete-index>`,
|
||||||
|
:ref:`internals documentation <internals-index>` for those who want to add
|
||||||
|
code to Django itself, and a :ref:`few other things that simply don't fit
|
||||||
|
elsewhere <misc-index>`.
|
||||||
|
|
||||||
|
|
||||||
|
How documentation is updated
|
||||||
|
============================
|
||||||
|
|
||||||
|
Just as the Django code base is developed and improved on a daily basis, our
|
||||||
|
documentation is consistently improving. We improve documentation for several
|
||||||
|
reasons:
|
||||||
|
|
||||||
|
* To make content fixes, such as grammar/typo corrections.
|
||||||
|
|
||||||
|
* To add information and/or examples to existing sections that need to be
|
||||||
|
expanded.
|
||||||
|
|
||||||
|
* To document Django features that aren't yet documented. (The list of
|
||||||
|
such features is shrinking but exists nonetheless.)
|
||||||
|
|
||||||
|
* To add documentation for new features as new features get added, or as
|
||||||
|
Django APIs or behaviors change.
|
||||||
|
|
||||||
|
Django's documentation is kept in the same source control system as its code. It
|
||||||
|
lives in the `django/trunk/docs`_ directory of our Subversion repository. Each
|
||||||
|
document online is a separate text file in the repository.
|
||||||
|
|
||||||
|
.. _django/trunk/docs: http://code.djangoproject.com/browser/django/trunk/docs
|
||||||
|
|
||||||
|
Where to get it
|
||||||
|
===============
|
||||||
|
|
||||||
|
You can read Django documentation in several ways. They are, in order of
|
||||||
|
preference:
|
||||||
|
|
||||||
|
On the Web
|
||||||
|
----------
|
||||||
|
|
||||||
|
The most recent version of the Django documentation lives at
|
||||||
|
http://www.djangoproject.com/documentation/ . These HTML pages are generated
|
||||||
|
automatically from the text files in source control. That means they reflect the
|
||||||
|
"latest and greatest" in Django -- they include the very latest corrections and
|
||||||
|
additions, and they discuss the latest Django features, which may only be
|
||||||
|
available to users of the Django development version. (See "Differences between
|
||||||
|
versions" below.)
|
||||||
|
|
||||||
|
We encourage you to help improve the docs by submitting changes, corrections and
|
||||||
|
suggestions in the `ticket system`_. The Django developers actively monitor the
|
||||||
|
ticket system and use your feedback to improve the documentation for everybody.
|
||||||
|
|
||||||
|
Note, however, that tickets should explicitly relate to the documentation,
|
||||||
|
rather than asking broad tech-support questions. If you need help with your
|
||||||
|
particular Django setup, try the `django-users mailing list`_ or the `#django
|
||||||
|
IRC channel`_ instead.
|
||||||
|
|
||||||
|
.. _ticket system: http://code.djangoproject.com/simpleticket?component=Documentation
|
||||||
|
.. _django-users mailing list: http://groups.google.com/group/django-users
|
||||||
|
.. _#django IRC channel: irc://irc.freenode.net/django
|
||||||
|
|
||||||
|
In plain text
|
||||||
|
-------------
|
||||||
|
|
||||||
|
For offline reading, or just for convenience, you can read the Django
|
||||||
|
documentation in plain text.
|
||||||
|
|
||||||
|
If you're using an official release of Django, note that the zipped package
|
||||||
|
(tarball) of the code includes a ``docs/`` directory, which contains all the
|
||||||
|
documentation for that release.
|
||||||
|
|
||||||
|
If you're using the development version of Django (aka the Subversion "trunk"),
|
||||||
|
note that the ``docs/`` directory contains all of the documentation. You can
|
||||||
|
``svn update`` it, just as you ``svn update`` the Python code, in order to get
|
||||||
|
the latest changes.
|
||||||
|
|
||||||
|
You can check out the latest Django documentation from Subversion using this
|
||||||
|
shell command:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
$ svn co http://code.djangoproject.com/svn/django/trunk/docs/ django_docs
|
||||||
|
|
||||||
|
One low-tech way of taking advantage of the text documentation is by using the
|
||||||
|
Unix ``grep`` utility to search for a phrase in all of the documentation. For
|
||||||
|
example, this will show you each mention of the phrase "edit_inline" in any
|
||||||
|
Django document:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
$ grep edit_inline /path/to/django/docs/*.txt
|
||||||
|
|
||||||
|
As HTML, locally
|
||||||
|
----------------
|
||||||
|
|
||||||
|
You can get a local copy of the HTML documentation following a few easy steps:
|
||||||
|
|
||||||
|
* Django's documentation uses a system called Sphinx__ to convert from
|
||||||
|
plain text to HTML. You'll need to install Sphinx by either downloading
|
||||||
|
and installing the package from the Sphinx website, or by Python's
|
||||||
|
``easy_install``:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
$ easy_install Sphinx
|
||||||
|
|
||||||
|
* Then, just use the included ``Makefile`` to turn the documentation into
|
||||||
|
HTML:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
$ cd path/to/django/docs
|
||||||
|
$ make html
|
||||||
|
|
||||||
|
You'll need `GNU Make`__ installed for this.
|
||||||
|
|
||||||
|
* The HTML documentation will be placed in ``docs/_build/html``.
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
At the time of this writing, Django's using a version of Sphinx not
|
||||||
|
yet released, so you'll currently need to install Sphinx from the
|
||||||
|
source. We'll fix this shortly.
|
||||||
|
|
||||||
|
__ http://sphinx.pocoo.org/
|
||||||
|
__ http://www.gnu.org/software/make/
|
||||||
|
|
||||||
|
Differences between versions
|
||||||
|
============================
|
||||||
|
|
||||||
|
As previously mentioned, the text documentation in our Subversion repository
|
||||||
|
contains the "latest and greatest" changes and additions. These changes often
|
||||||
|
include documentation of new features added in the Django development version
|
||||||
|
-- the Subversion ("trunk") version of Django. For that reason, it's worth
|
||||||
|
pointing out our policy on keeping straight the documentation for various
|
||||||
|
versions of the framework.
|
||||||
|
|
||||||
|
We follow this policy:
|
||||||
|
|
||||||
|
* The primary documentation on djangoproject.com is an HTML version of the
|
||||||
|
latest docs in Subversion. These docs always correspond to the latest
|
||||||
|
official Django release, plus whatever features we've added/changed in
|
||||||
|
the framework *since* the latest release.
|
||||||
|
|
||||||
|
* As we add features to Django's development version, we try to update the
|
||||||
|
documentation in the same Subversion commit transaction.
|
||||||
|
|
||||||
|
* To distinguish feature changes/additions in the docs, we use the phrase
|
||||||
|
**New in Django development version**. In practice, this means that the
|
||||||
|
current documentation on djangoproject.com can be used by users of either
|
||||||
|
the latest release *or* the development version.
|
||||||
|
|
||||||
|
* Documentation for a particular Django release is frozen once the version
|
||||||
|
has been released officially. It remains a snapshot of the docs as of the
|
||||||
|
moment of the release. We will make exceptions to this rule in
|
||||||
|
the case of retroactive security updates or other such retroactive
|
||||||
|
changes. Once documentation is frozen, we add a note to the top of each
|
||||||
|
frozen document that says "These docs are frozen for Django version XXX"
|
||||||
|
and links to the current version of that document.
|
||||||
|
|
||||||
|
* The `main documentation Web page`_ includes links to documentation for
|
||||||
|
all previous versions.
|
||||||
|
|
||||||
|
.. _main documentation Web page: http://www.djangoproject.com/documentation/
|
|
@ -1,69 +0,0 @@
|
||||||
==================================
|
|
||||||
Integrating with a legacy database
|
|
||||||
==================================
|
|
||||||
|
|
||||||
While Django is best suited for developing new applications, it's quite
|
|
||||||
possible to integrate it into legacy databases. Django includes a couple of
|
|
||||||
utilities to automate as much of this process as possible.
|
|
||||||
|
|
||||||
This document assumes you know the Django basics, as covered in the
|
|
||||||
`official tutorial`_.
|
|
||||||
|
|
||||||
.. _official tutorial: ../tutorial01/
|
|
||||||
|
|
||||||
Give Django your database parameters
|
|
||||||
====================================
|
|
||||||
|
|
||||||
You'll need to tell Django what your database connection parameters are, and
|
|
||||||
what the name of the database is. Do that by editing these settings in your
|
|
||||||
`settings file`_:
|
|
||||||
|
|
||||||
* `DATABASE_NAME`_
|
|
||||||
* `DATABASE_ENGINE`_
|
|
||||||
* `DATABASE_USER`_
|
|
||||||
* `DATABASE_PASSWORD`_
|
|
||||||
* `DATABASE_HOST`_
|
|
||||||
* `DATABASE_PORT`_
|
|
||||||
|
|
||||||
.. _settings file: ../settings/
|
|
||||||
.. _DATABASE_NAME: ../settings/#database-name
|
|
||||||
.. _DATABASE_ENGINE: ../settings/#database-engine
|
|
||||||
.. _DATABASE_USER: ../settings/#database-user
|
|
||||||
.. _DATABASE_PASSWORD: ../settings/#database-password
|
|
||||||
.. _DATABASE_HOST: ../settings/#database-host
|
|
||||||
.. _DATABASE_PORT: ../settings/#database-port
|
|
||||||
|
|
||||||
Auto-generate the models
|
|
||||||
========================
|
|
||||||
|
|
||||||
Django comes with a utility that can create models by introspecting an existing
|
|
||||||
database. You can view the output by running this command::
|
|
||||||
|
|
||||||
python manage.py inspectdb
|
|
||||||
|
|
||||||
Save this as a file by using standard Unix output redirection::
|
|
||||||
|
|
||||||
python manage.py inspectdb > models.py
|
|
||||||
|
|
||||||
This feature is meant as a shortcut, not as definitive model generation. See
|
|
||||||
the `django-admin.py documentation`_ for more information.
|
|
||||||
|
|
||||||
Once you've cleaned up your models, name the file ``models.py`` and put it in
|
|
||||||
the Python package that holds your app. Then add the app to your
|
|
||||||
``INSTALLED_APPS`` setting.
|
|
||||||
|
|
||||||
.. _django-admin.py documentation: ../django-admin/
|
|
||||||
|
|
||||||
Install the core Django tables
|
|
||||||
==============================
|
|
||||||
|
|
||||||
Next, run the ``manage.py syncdb`` command to install any extra needed database
|
|
||||||
records such as admin permissions and content types::
|
|
||||||
|
|
||||||
python manage.py syncdb
|
|
||||||
|
|
||||||
See whether it worked
|
|
||||||
=====================
|
|
||||||
|
|
||||||
That's it. Try accessing your data via the Django database API, and try editing
|
|
||||||
objects via Django's admin site.
|
|
|
@ -1,733 +0,0 @@
|
||||||
==========================
|
|
||||||
The "local flavor" add-ons
|
|
||||||
==========================
|
|
||||||
|
|
||||||
Following its "batteries included" philosophy, Django comes with assorted
|
|
||||||
pieces of code that are useful for particular countries or cultures. These are
|
|
||||||
called the "local flavor" add-ons and live in the ``django.contrib.localflavor``
|
|
||||||
package.
|
|
||||||
|
|
||||||
Inside that package, country- or culture-specific code is organized into
|
|
||||||
subpackages, named using `ISO 3166 country codes`_.
|
|
||||||
|
|
||||||
Most of the ``localflavor`` add-ons are localized form components deriving from
|
|
||||||
the forms_ framework -- for example, a ``USStateField`` that knows how to
|
|
||||||
validate U.S. state abbreviations, and a ``FISocialSecurityNumber`` that knows
|
|
||||||
how to validate Finnish social security numbers.
|
|
||||||
|
|
||||||
To use one of these localized components, just import the relevant subpackage.
|
|
||||||
For example, here's how you can create a form with a field representing a
|
|
||||||
French telephone number::
|
|
||||||
|
|
||||||
from django import forms
|
|
||||||
from django.contrib.localflavor import fr
|
|
||||||
|
|
||||||
class MyForm(forms.Form):
|
|
||||||
my_french_phone_no = fr.forms.FRPhoneNumberField()
|
|
||||||
|
|
||||||
Supported countries
|
|
||||||
===================
|
|
||||||
|
|
||||||
Countries currently supported by ``localflavor`` are:
|
|
||||||
|
|
||||||
* Argentina_
|
|
||||||
* Australia_
|
|
||||||
* Austria_
|
|
||||||
* Brazil_
|
|
||||||
* Canada_
|
|
||||||
* Chile_
|
|
||||||
* Finland_
|
|
||||||
* France_
|
|
||||||
* Germany_
|
|
||||||
* Holland_
|
|
||||||
* Iceland_
|
|
||||||
* India_
|
|
||||||
* Italy_
|
|
||||||
* Japan_
|
|
||||||
* Mexico_
|
|
||||||
* Norway_
|
|
||||||
* Peru_
|
|
||||||
* Poland_
|
|
||||||
* Romania_
|
|
||||||
* Slovakia_
|
|
||||||
* `South Africa`_
|
|
||||||
* Spain_
|
|
||||||
* Switzerland_
|
|
||||||
* `United Kingdom`_
|
|
||||||
* `United States of America`_
|
|
||||||
|
|
||||||
The ``localflavor`` package also includes a ``generic`` subpackage, containing
|
|
||||||
useful code that is not specific to one particular country or culture.
|
|
||||||
Currently, it defines date and datetime input fields based on those from
|
|
||||||
forms_, but with non-US default formats. Here's an example of how to use
|
|
||||||
them::
|
|
||||||
|
|
||||||
from django import forms
|
|
||||||
from django.contrib.localflavor import generic
|
|
||||||
|
|
||||||
class MyForm(forms.Form):
|
|
||||||
my_date_field = generic.forms.DateField()
|
|
||||||
|
|
||||||
.. _ISO 3166 country codes: http://www.iso.org/iso/country_codes/iso_3166_code_lists/english_country_names_and_code_elements.htm
|
|
||||||
.. _Argentina: `Argentina (django.contrib.localflavor.ar)`_
|
|
||||||
.. _Australia: `Australia (django.contrib.localflavor.au)`_
|
|
||||||
.. _Austria: `Austria (django.contrib.localflavor.at)`_
|
|
||||||
.. _Brazil: `Brazil (django.contrib.localflavor.br)`_
|
|
||||||
.. _Canada: `Canada (django.contrib.localflavor.ca)`_
|
|
||||||
.. _Chile: `Chile (django.contrib.localflavor.cl)`_
|
|
||||||
.. _Finland: `Finland (django.contrib.localflavor.fi)`_
|
|
||||||
.. _France: `France (django.contrib.localflavor.fr)`_
|
|
||||||
.. _Germany: `Germany (django.contrib.localflavor.de)`_
|
|
||||||
.. _Holland: `Holland (django.contrib.localflavor.nl)`_
|
|
||||||
.. _Iceland: `Iceland (django.contrib.localflavor.is\_)`_
|
|
||||||
.. _India: `India (django.contrib.localflavor.in\_)`_
|
|
||||||
.. _Italy: `Italy (django.contrib.localflavor.it)`_
|
|
||||||
.. _Japan: `Japan (django.contrib.localflavor.jp)`_
|
|
||||||
.. _Mexico: `Mexico (django.contrib.localflavor.mx)`_
|
|
||||||
.. _Norway: `Norway (django.contrib.localflavor.no)`_
|
|
||||||
.. _Peru: `Peru (django.contrib.localflavor.pe)`_
|
|
||||||
.. _Poland: `Poland (django.contrib.localflavor.pl)`_
|
|
||||||
.. _Romania: `Romania (django.contrib.localflavor.ro)`_
|
|
||||||
.. _Slovakia: `Slovakia (django.contrib.localflavor.sk)`_
|
|
||||||
.. _South Africa: `South Africa (django.contrib.localflavor.za)`_
|
|
||||||
.. _Spain: `Spain (django.contrib.localflavor.es)`_
|
|
||||||
.. _Switzerland: `Switzerland (django.contrib.localflavor.ch)`_
|
|
||||||
.. _United Kingdom: `United Kingdom (django.contrib.localflavor.uk)`_
|
|
||||||
.. _United States of America: `United States of America (django.contrib.localflavor.us)`_
|
|
||||||
.. _forms: ../forms/
|
|
||||||
|
|
||||||
Adding flavors
|
|
||||||
==============
|
|
||||||
|
|
||||||
We'd love to add more of these to Django, so please `create a ticket`_ with
|
|
||||||
any code you'd like to contribute. One thing we ask is that you please use
|
|
||||||
Unicode objects (``u'mystring'``) for strings, rather than setting the encoding
|
|
||||||
in the file. See any of the existing flavors for examples.
|
|
||||||
|
|
||||||
.. _create a ticket: http://code.djangoproject.com/simpleticket
|
|
||||||
|
|
||||||
Argentina (``django.contrib.localflavor.ar``)
|
|
||||||
=============================================
|
|
||||||
|
|
||||||
ARPostalCodeField
|
|
||||||
-----------------
|
|
||||||
|
|
||||||
A form field that validates input as either a classic four-digit Argentinian
|
|
||||||
postal code or a CPA_.
|
|
||||||
|
|
||||||
.. _CPA: http://www.correoargentino.com.ar/consulta_cpa/home.php
|
|
||||||
|
|
||||||
ARDNIField
|
|
||||||
----------
|
|
||||||
|
|
||||||
A form field that validates input as a Documento Nacional de Identidad (DNI)
|
|
||||||
number.
|
|
||||||
|
|
||||||
ARCUITField
|
|
||||||
-----------
|
|
||||||
|
|
||||||
A form field that validates input as a Código Único de Identificación
|
|
||||||
Tributaria (CUIT) number.
|
|
||||||
|
|
||||||
ARProvinceSelect
|
|
||||||
----------------
|
|
||||||
|
|
||||||
A ``Select`` widget that uses a list of Argentina's provinces and autonomous
|
|
||||||
cities as its choices.
|
|
||||||
|
|
||||||
Australia (``django.contrib.localflavor.au``)
|
|
||||||
=============================================
|
|
||||||
|
|
||||||
AUPostCodeField
|
|
||||||
---------------
|
|
||||||
|
|
||||||
A form field that validates input as an Australian postcode.
|
|
||||||
|
|
||||||
AUPhoneNumberField
|
|
||||||
------------------
|
|
||||||
|
|
||||||
A form field that validates input as an Australian phone number. Valid numbers
|
|
||||||
have ten digits.
|
|
||||||
|
|
||||||
AUStateSelect
|
|
||||||
-------------
|
|
||||||
|
|
||||||
A ``Select`` widget that uses a list of Australian states/territories as its
|
|
||||||
choices.
|
|
||||||
|
|
||||||
Austria (``django.contrib.localflavor.at``)
|
|
||||||
=============================================
|
|
||||||
|
|
||||||
ATZipCodeField
|
|
||||||
---------------
|
|
||||||
|
|
||||||
A form field that validates its input as an Austrian zip code.
|
|
||||||
|
|
||||||
ATStateSelect
|
|
||||||
-------------
|
|
||||||
|
|
||||||
A ``Select`` widget that uses a list of Austrian states as its choices.
|
|
||||||
|
|
||||||
ATSocialSecurityNumberField
|
|
||||||
---------------------------
|
|
||||||
|
|
||||||
A form field that validates its input as an Austrian social security number.
|
|
||||||
|
|
||||||
Brazil (``django.contrib.localflavor.br``)
|
|
||||||
==========================================
|
|
||||||
|
|
||||||
BRPhoneNumberField
|
|
||||||
------------------
|
|
||||||
|
|
||||||
A form field that validates input as a Brazilian phone number, with the format
|
|
||||||
XX-XXXX-XXXX.
|
|
||||||
|
|
||||||
BRZipCodeField
|
|
||||||
--------------
|
|
||||||
|
|
||||||
A form field that validates input as a Brazilian zip code, with the format
|
|
||||||
XXXXX-XXX.
|
|
||||||
|
|
||||||
BRStateSelect
|
|
||||||
-------------
|
|
||||||
|
|
||||||
A ``Select`` widget that uses a list of Brazilian states/territories as its
|
|
||||||
choices.
|
|
||||||
|
|
||||||
Canada (``django.contrib.localflavor.ca``)
|
|
||||||
==========================================
|
|
||||||
|
|
||||||
CAPhoneNumberField
|
|
||||||
------------------
|
|
||||||
|
|
||||||
A form field that validates input as a Canadian phone number, with the format
|
|
||||||
XXX-XXX-XXXX.
|
|
||||||
|
|
||||||
CAPostalCodeField
|
|
||||||
-----------------
|
|
||||||
|
|
||||||
A form field that validates input as a Canadian postal code, with the format
|
|
||||||
XXX XXX.
|
|
||||||
|
|
||||||
CAProvinceField
|
|
||||||
---------------
|
|
||||||
|
|
||||||
A form field that validates input as a Canadian province name or abbreviation.
|
|
||||||
|
|
||||||
CASocialInsuranceNumberField
|
|
||||||
----------------------------
|
|
||||||
|
|
||||||
A form field that validates input as a Canadian Social Insurance Number (SIN).
|
|
||||||
A valid number must have the format XXX-XXX-XXX and pass a `Luhn mod-10
|
|
||||||
checksum`_.
|
|
||||||
|
|
||||||
.. _Luhn mod-10 checksum: http://en.wikipedia.org/wiki/Luhn_algorithm
|
|
||||||
|
|
||||||
CAProvinceSelect
|
|
||||||
----------------
|
|
||||||
|
|
||||||
A ``Select`` widget that uses a list of Canadian provinces and territories as
|
|
||||||
its choices.
|
|
||||||
|
|
||||||
Chile (``django.contrib.localflavor.cl``)
|
|
||||||
=========================================
|
|
||||||
|
|
||||||
CLRutField
|
|
||||||
----------
|
|
||||||
|
|
||||||
A form field that validates input as a Chilean national identification number
|
|
||||||
('Rol Unico Tributario' or RUT). The valid format is XX.XXX.XXX-X.
|
|
||||||
|
|
||||||
CLRegionSelect
|
|
||||||
--------------
|
|
||||||
|
|
||||||
A ``Select`` widget that uses a list of Chilean regions (Regiones) as its
|
|
||||||
choices.
|
|
||||||
|
|
||||||
Finland (``django.contrib.localflavor.fi``)
|
|
||||||
===========================================
|
|
||||||
|
|
||||||
FISocialSecurityNumber
|
|
||||||
----------------------
|
|
||||||
|
|
||||||
A form field that validates input as a Finnish social security number.
|
|
||||||
|
|
||||||
FIZipCodeField
|
|
||||||
--------------
|
|
||||||
|
|
||||||
A form field that validates input as a Finnish zip code. Valid codes
|
|
||||||
consist of five digits.
|
|
||||||
|
|
||||||
FIMunicipalitySelect
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
A ``Select`` widget that uses a list of Finnish municipalities as its
|
|
||||||
choices.
|
|
||||||
|
|
||||||
France (``django.contrib.localflavor.fr``)
|
|
||||||
==========================================
|
|
||||||
|
|
||||||
FRPhoneNumberField
|
|
||||||
------------------
|
|
||||||
|
|
||||||
A form field that validates input as a French local phone number. The
|
|
||||||
correct format is 0X XX XX XX XX. 0X.XX.XX.XX.XX and 0XXXXXXXXX validate
|
|
||||||
but are corrected to 0X XX XX XX XX.
|
|
||||||
|
|
||||||
FRZipCodeField
|
|
||||||
--------------
|
|
||||||
|
|
||||||
A form field that validates input as a French zip code. Valid codes
|
|
||||||
consist of five digits.
|
|
||||||
|
|
||||||
FRDepartmentSelect
|
|
||||||
------------------
|
|
||||||
|
|
||||||
A ``Select`` widget that uses a list of French departments as its choices.
|
|
||||||
|
|
||||||
Germany (``django.contrib.localflavor.de``)
|
|
||||||
===========================================
|
|
||||||
|
|
||||||
DEIdentityCardNumberField
|
|
||||||
-------------------------
|
|
||||||
|
|
||||||
A form field that validates input as a German identity card number
|
|
||||||
(Personalausweis_). Valid numbers have the format
|
|
||||||
XXXXXXXXXXX-XXXXXXX-XXXXXXX-X, with no group consisting entirely of zeroes.
|
|
||||||
|
|
||||||
.. _Personalausweis: http://de.wikipedia.org/wiki/Personalausweis
|
|
||||||
|
|
||||||
DEZipCodeField
|
|
||||||
--------------
|
|
||||||
|
|
||||||
A form field that validates input as a German zip code. Valid codes
|
|
||||||
consist of five digits.
|
|
||||||
|
|
||||||
DEStateSelect
|
|
||||||
-------------
|
|
||||||
|
|
||||||
A ``Select`` widget that uses a list of German states as its choices.
|
|
||||||
|
|
||||||
Holland (``django.contrib.localflavor.nl``)
|
|
||||||
===========================================
|
|
||||||
|
|
||||||
NLPhoneNumberField
|
|
||||||
------------------
|
|
||||||
|
|
||||||
A form field that validates input as a Dutch telephone number.
|
|
||||||
|
|
||||||
NLSofiNumberField
|
|
||||||
-----------------
|
|
||||||
|
|
||||||
A form field that validates input as a Dutch social security number
|
|
||||||
(SoFI/BSN).
|
|
||||||
|
|
||||||
NLZipCodeField
|
|
||||||
--------------
|
|
||||||
|
|
||||||
A form field that validates input as a Dutch zip code.
|
|
||||||
|
|
||||||
NLProvinceSelect
|
|
||||||
----------------
|
|
||||||
|
|
||||||
A ``Select`` widget that uses a list of Dutch provinces as its list of
|
|
||||||
choices.
|
|
||||||
|
|
||||||
Iceland (``django.contrib.localflavor.is_``)
|
|
||||||
============================================
|
|
||||||
|
|
||||||
ISIdNumberField
|
|
||||||
---------------
|
|
||||||
|
|
||||||
A form field that validates input as an Icelandic identification number
|
|
||||||
(kennitala). The format is XXXXXX-XXXX.
|
|
||||||
|
|
||||||
ISPhoneNumberField
|
|
||||||
------------------
|
|
||||||
|
|
||||||
A form field that validates input as an Icelandtic phone number (seven
|
|
||||||
digits with an optional hyphen or space after the first three digits).
|
|
||||||
|
|
||||||
ISPostalCodeSelect
|
|
||||||
------------------
|
|
||||||
|
|
||||||
A ``Select`` widget that uses a list of Icelandic postal codes as its
|
|
||||||
choices.
|
|
||||||
|
|
||||||
India (``django.contrib.localflavor.in_``)
|
|
||||||
==========================================
|
|
||||||
|
|
||||||
INStateField
|
|
||||||
------------
|
|
||||||
|
|
||||||
A form field that validates input as an Indian state/territory name or
|
|
||||||
abbreviation. Input is normalized to the standard two-letter vehicle
|
|
||||||
registration abbreviation for the given state or territory.
|
|
||||||
|
|
||||||
INZipCodeField
|
|
||||||
--------------
|
|
||||||
|
|
||||||
A form field that validates input as an Indian zip code, with the
|
|
||||||
format XXXXXXX.
|
|
||||||
|
|
||||||
INStateSelect
|
|
||||||
-------------
|
|
||||||
|
|
||||||
A ``Select`` widget that uses a list of Indian states/territories as its
|
|
||||||
choices.
|
|
||||||
|
|
||||||
Italy (``django.contrib.localflavor.it``)
|
|
||||||
=========================================
|
|
||||||
|
|
||||||
ITSocialSecurityNumberField
|
|
||||||
---------------------------
|
|
||||||
|
|
||||||
A form field that validates input as an Italian social security number
|
|
||||||
(`codice fiscale`_).
|
|
||||||
|
|
||||||
.. _codice fiscale: http://www.agenziaentrate.it/ilwwcm/connect/Nsi/Servizi/Codice+fiscale+-+tessera+sanitaria/Codice+fiscale/NSI+Informazioni+sulla+codificazione+delle+persone+fisiche
|
|
||||||
|
|
||||||
ITVatNumberField
|
|
||||||
----------------
|
|
||||||
|
|
||||||
A form field that validates Italian VAT numbers (partita IVA).
|
|
||||||
|
|
||||||
ITZipCodeField
|
|
||||||
--------------
|
|
||||||
|
|
||||||
A form field that validates input as an Italian zip code. Valid codes
|
|
||||||
must have five digits.
|
|
||||||
|
|
||||||
ITProvinceSelect
|
|
||||||
----------------
|
|
||||||
|
|
||||||
A ``Select`` widget that uses a list of Italian provinces as its choices.
|
|
||||||
|
|
||||||
ITRegionSelect
|
|
||||||
--------------
|
|
||||||
|
|
||||||
A ``Select`` widget that uses a list of Italian regions as its choices.
|
|
||||||
|
|
||||||
Japan (``django.contrib.localflavor.jp``)
|
|
||||||
=========================================
|
|
||||||
|
|
||||||
JPPostalCodeField
|
|
||||||
-----------------
|
|
||||||
|
|
||||||
A form field that validates input as a Japanese postcode. It accepts seven
|
|
||||||
digits, with or without a hyphen.
|
|
||||||
|
|
||||||
JPPrefectureSelect
|
|
||||||
------------------
|
|
||||||
|
|
||||||
A ``Select`` widget that uses a list of Japanese prefectures as its choices.
|
|
||||||
|
|
||||||
Mexico (``django.contrib.localflavor.mx``)
|
|
||||||
==========================================
|
|
||||||
|
|
||||||
MXStateSelect
|
|
||||||
-------------
|
|
||||||
|
|
||||||
A ``Select`` widget that uses a list of Mexican states as its choices.
|
|
||||||
|
|
||||||
Norway (``django.contrib.localflavor.no``)
|
|
||||||
==========================================
|
|
||||||
|
|
||||||
NOSocialSecurityNumber
|
|
||||||
----------------------
|
|
||||||
|
|
||||||
A form field that validates input as a Norwegian social security number
|
|
||||||
(personnummer_).
|
|
||||||
|
|
||||||
.. _personnummer: http://no.wikipedia.org/wiki/Personnummer
|
|
||||||
|
|
||||||
NOZipCodeField
|
|
||||||
--------------
|
|
||||||
|
|
||||||
A form field that validates input as a Norwegian zip code. Valid codes
|
|
||||||
have four digits.
|
|
||||||
|
|
||||||
NOMunicipalitySelect
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
A ``Select`` widget that uses a list of Norwegian municipalities (fylker) as
|
|
||||||
its choices.
|
|
||||||
|
|
||||||
Peru (``django.contrib.localflavor.pe``)
|
|
||||||
========================================
|
|
||||||
|
|
||||||
PEDNIField
|
|
||||||
----------
|
|
||||||
|
|
||||||
A form field that validates input as a DNI (Peruvian national identity)
|
|
||||||
number.
|
|
||||||
|
|
||||||
PERUCField
|
|
||||||
----------
|
|
||||||
|
|
||||||
A form field that validates input as an RUC (Registro Unico de
|
|
||||||
Contribuyentes) number. Valid RUC numbers have 11 digits.
|
|
||||||
|
|
||||||
PEDepartmentSelect
|
|
||||||
------------------
|
|
||||||
|
|
||||||
A ``Select`` widget that uses a list of Peruvian Departments as its choices.
|
|
||||||
|
|
||||||
Poland (``django.contrib.localflavor.pl``)
|
|
||||||
==========================================
|
|
||||||
|
|
||||||
PLNationalIdentificationNumberField
|
|
||||||
-----------------------------------
|
|
||||||
|
|
||||||
A form field that validates input as a Polish national identification number
|
|
||||||
(PESEL_).
|
|
||||||
|
|
||||||
.. _PESEL: http://en.wikipedia.org/wiki/PESEL
|
|
||||||
|
|
||||||
PLNationalBusinessRegisterField
|
|
||||||
-------------------------------
|
|
||||||
|
|
||||||
A form field that validates input as a Polish National Official Business
|
|
||||||
Register Number (REGON_), having either seven or nine digits. The checksum
|
|
||||||
algorithm used for REGONs is documented at
|
|
||||||
http://wipos.p.lodz.pl/zylla/ut/nip-rego.html.
|
|
||||||
|
|
||||||
.. _REGON: http://www.stat.gov.pl/bip/regon_ENG_HTML.htm
|
|
||||||
|
|
||||||
PLPostalCodeField
|
|
||||||
-----------------
|
|
||||||
|
|
||||||
A form field that validates input as a Polish postal code. The valid format
|
|
||||||
is XX-XXX, where X is a digit.
|
|
||||||
|
|
||||||
PLTaxNumberField
|
|
||||||
----------------
|
|
||||||
|
|
||||||
A form field that validates input as a Polish Tax Number (NIP). Valid
|
|
||||||
formats are XXX-XXX-XX-XX or XX-XX-XXX-XXX. The checksum algorithm used
|
|
||||||
for NIPs is documented at http://wipos.p.lodz.pl/zylla/ut/nip-rego.html.
|
|
||||||
|
|
||||||
PLAdministrativeUnitSelect
|
|
||||||
--------------------------
|
|
||||||
|
|
||||||
A ``Select`` widget that uses a list of Polish administrative units as its
|
|
||||||
choices.
|
|
||||||
|
|
||||||
PLVoivodeshipSelect
|
|
||||||
-------------------
|
|
||||||
|
|
||||||
A ``Select`` widget that uses a list of Polish voivodeships (administrative
|
|
||||||
provinces) as its choices.
|
|
||||||
|
|
||||||
Romania (``django.contrib.localflavor.ro``)
|
|
||||||
============================================
|
|
||||||
|
|
||||||
ROCIFField
|
|
||||||
----------
|
|
||||||
|
|
||||||
A form field that validates Romanian fiscal identification codes (CIF). The
|
|
||||||
return value strips the leading RO, if given.
|
|
||||||
|
|
||||||
ROCNPField
|
|
||||||
----------
|
|
||||||
|
|
||||||
A form field that validates Romanian personal numeric codes (CNP).
|
|
||||||
|
|
||||||
ROCountyField
|
|
||||||
-------------
|
|
||||||
|
|
||||||
A form field that validates its input as a Romanian county (judet) name or
|
|
||||||
abbreviation. It normalizes the input to the standard vehicle registration
|
|
||||||
abbreviation for the given county. This field will only accept names written
|
|
||||||
with diacritics; consider using ROCountySelect as an alternative.
|
|
||||||
|
|
||||||
ROCountySelect
|
|
||||||
--------------
|
|
||||||
|
|
||||||
A ``Select`` widget that uses a list of Romanian counties (judete) as its
|
|
||||||
choices.
|
|
||||||
|
|
||||||
ROIBANField
|
|
||||||
-----------
|
|
||||||
|
|
||||||
A form field that validates its input as a Romanian International Bank
|
|
||||||
Account Number (IBAN). The valid format is ROXX-XXXX-XXXX-XXXX-XXXX-XXXX,
|
|
||||||
with or without hyphens.
|
|
||||||
|
|
||||||
ROPhoneNumberField
|
|
||||||
------------------
|
|
||||||
|
|
||||||
A form field that validates Romanian phone numbers, short special numbers
|
|
||||||
excluded.
|
|
||||||
|
|
||||||
ROPostalCodeField
|
|
||||||
-----------------
|
|
||||||
|
|
||||||
A form field that validates Romanian postal codes.
|
|
||||||
|
|
||||||
Slovakia (``django.contrib.localflavor.sk``)
|
|
||||||
============================================
|
|
||||||
|
|
||||||
SKPostalCodeField
|
|
||||||
-----------------
|
|
||||||
|
|
||||||
A form field that validates input as a Slovak postal code. Valid formats
|
|
||||||
are XXXXX or XXX XX, where X is a digit.
|
|
||||||
|
|
||||||
SKDistrictSelect
|
|
||||||
----------------
|
|
||||||
|
|
||||||
A ``Select`` widget that uses a list of Slovak districts as its choices.
|
|
||||||
|
|
||||||
SKRegionSelect
|
|
||||||
--------------
|
|
||||||
|
|
||||||
A ``Select`` widget that uses a list of Slovak regions as its choices.
|
|
||||||
|
|
||||||
South Africa (``django.contrib.localflavor.za``)
|
|
||||||
================================================
|
|
||||||
|
|
||||||
ZAIDField
|
|
||||||
---------
|
|
||||||
|
|
||||||
A form field that validates input as a South African ID number. Validation
|
|
||||||
uses the Luhn checksum and a simplistic (i.e., not entirely accurate) check
|
|
||||||
for birth date.
|
|
||||||
|
|
||||||
ZAPostCodeField
|
|
||||||
---------------
|
|
||||||
|
|
||||||
A form field that validates input as a South African postcode. Valid
|
|
||||||
postcodes must have four digits.
|
|
||||||
|
|
||||||
Spain (``django.contrib.localflavor.es``)
|
|
||||||
=========================================
|
|
||||||
|
|
||||||
ESIdentityCardNumberField
|
|
||||||
-------------------------
|
|
||||||
|
|
||||||
A form field that validates input as a Spanish NIF/NIE/CIF (Fiscal
|
|
||||||
Identification Number) code.
|
|
||||||
|
|
||||||
ESCCCField
|
|
||||||
----------
|
|
||||||
|
|
||||||
A form field that validates input as a Spanish bank account number (Codigo
|
|
||||||
Cuenta Cliente or CCC). A valid CCC number has the format
|
|
||||||
EEEE-OOOO-CC-AAAAAAAAAA, where the E, O, C and A digits denote the entity,
|
|
||||||
office, checksum and account, respectively. The first checksum digit
|
|
||||||
validates the entity and office. The second checksum digit validates the
|
|
||||||
account. It is also valid to use a space as a delimiter, or to use no
|
|
||||||
delimiter.
|
|
||||||
|
|
||||||
ESPhoneNumberField
|
|
||||||
------------------
|
|
||||||
|
|
||||||
A form field that validates input as a Spanish phone number. Valid numbers
|
|
||||||
have nine digits, the first of which is 6, 8 or 9.
|
|
||||||
|
|
||||||
ESPostalCodeField
|
|
||||||
-----------------
|
|
||||||
|
|
||||||
A form field that validates input as a Spanish postal code. Valid codes
|
|
||||||
have five digits, the first two being in the range 01 to 52, representing
|
|
||||||
the province.
|
|
||||||
|
|
||||||
ESProvinceSelect
|
|
||||||
----------------
|
|
||||||
|
|
||||||
A ``Select`` widget that uses a list of Spanish provinces as its choices.
|
|
||||||
|
|
||||||
ESRegionSelect
|
|
||||||
--------------
|
|
||||||
|
|
||||||
A ``Select`` widget that uses a list of Spanish regions as its choices.
|
|
||||||
|
|
||||||
Switzerland (``django.contrib.localflavor.ch``)
|
|
||||||
===============================================
|
|
||||||
|
|
||||||
CHIdentityCardNumberField
|
|
||||||
-------------------------
|
|
||||||
|
|
||||||
A form field that validates input as a Swiss identity card number.
|
|
||||||
A valid number must confirm to the X1234567<0 or 1234567890 format and
|
|
||||||
have the correct checksums -- see http://adi.kousz.ch/artikel/IDCHE.htm.
|
|
||||||
|
|
||||||
CHPhoneNumberField
|
|
||||||
------------------
|
|
||||||
|
|
||||||
A form field that validates input as a Swiss phone number. The correct
|
|
||||||
format is 0XX XXX XX XX. 0XX.XXX.XX.XX and 0XXXXXXXXX validate but are
|
|
||||||
corrected to 0XX XXX XX XX.
|
|
||||||
|
|
||||||
CHZipCodeField
|
|
||||||
--------------
|
|
||||||
|
|
||||||
A form field that validates input as a Swiss zip code. Valid codes
|
|
||||||
consist of four digits.
|
|
||||||
|
|
||||||
CHStateSelect
|
|
||||||
-------------
|
|
||||||
|
|
||||||
A ``Select`` widget that uses a list of Swiss states as its choices.
|
|
||||||
|
|
||||||
United Kingdom (``django.contrib.localflavor.uk``)
|
|
||||||
==================================================
|
|
||||||
|
|
||||||
UKPostcodeField
|
|
||||||
---------------
|
|
||||||
|
|
||||||
A form field that validates input as a UK postcode. The regular
|
|
||||||
expression used is sourced from the schema for British Standard BS7666
|
|
||||||
address types at http://www.govtalk.gov.uk/gdsc/schemas/bs7666-v2-0.xsd.
|
|
||||||
|
|
||||||
UKCountySelect
|
|
||||||
--------------
|
|
||||||
|
|
||||||
A ``Select`` widget that uses a list of UK counties/regions as its choices.
|
|
||||||
|
|
||||||
UKNationSelect
|
|
||||||
--------------
|
|
||||||
|
|
||||||
A ``Select`` widget that uses a list of UK nations as its choices.
|
|
||||||
|
|
||||||
United States of America (``django.contrib.localflavor.us``)
|
|
||||||
============================================================
|
|
||||||
|
|
||||||
USPhoneNumberField
|
|
||||||
------------------
|
|
||||||
|
|
||||||
A form field that validates input as a U.S. phone number.
|
|
||||||
|
|
||||||
USSocialSecurityNumberField
|
|
||||||
---------------------------
|
|
||||||
|
|
||||||
A form field that validates input as a U.S. Social Security Number (SSN).
|
|
||||||
A valid SSN must obey the following rules:
|
|
||||||
|
|
||||||
* Format of XXX-XX-XXXX
|
|
||||||
* No group of digits consisting entirely of zeroes
|
|
||||||
* Leading group of digits cannot be 666
|
|
||||||
* Number not in promotional block 987-65-4320 through 987-65-4329
|
|
||||||
* Number not one known to be invalid due to widespread promotional
|
|
||||||
use or distribution (e.g., the Woolworth's number or the 1962
|
|
||||||
promotional number)
|
|
||||||
|
|
||||||
USStateField
|
|
||||||
------------
|
|
||||||
|
|
||||||
A form field that validates input as a U.S. state name or abbreviation. It
|
|
||||||
normalizes the input to the standard two-letter postal service abbreviation
|
|
||||||
for the given state.
|
|
||||||
|
|
||||||
USZipCodeField
|
|
||||||
--------------
|
|
||||||
|
|
||||||
A form field that validates input as a U.S. ZIP code. Valid formats are
|
|
||||||
XXXXX or XXXXX-XXXX.
|
|
||||||
|
|
||||||
USStateSelect
|
|
||||||
-------------
|
|
||||||
|
|
||||||
A form ``Select`` widget that uses a list of U.S. states/territories as its
|
|
||||||
choices.
|
|
|
@ -159,8 +159,7 @@ The file extension(s) to examine (default: ".html", separate multiple
|
||||||
extensions with commas, or use -e multiple times).
|
extensions with commas, or use -e multiple times).
|
||||||
.TP
|
.TP
|
||||||
.I \-a, \-\-all
|
.I \-a, \-\-all
|
||||||
Process all available locales when using makemessages.
|
Process all available locales when using makemessages..SH "ENVIRONMENT"
|
||||||
.SH "ENVIRONMENT"
|
|
||||||
.TP
|
.TP
|
||||||
.I DJANGO_SETTINGS_MODULE
|
.I DJANGO_SETTINGS_MODULE
|
||||||
In the absence of the
|
In the absence of the
|
||||||
|
|
|
@ -1,288 +0,0 @@
|
||||||
==========
|
|
||||||
Middleware
|
|
||||||
==========
|
|
||||||
|
|
||||||
Middleware is a framework of hooks into Django's request/response processing.
|
|
||||||
It's a light, low-level "plugin" system for globally altering Django's input
|
|
||||||
and/or output.
|
|
||||||
|
|
||||||
Each middleware component is responsible for doing some specific function. For
|
|
||||||
example, Django includes a middleware component, ``XViewMiddleware``, that adds
|
|
||||||
an ``"X-View"`` HTTP header to every response to a ``HEAD`` request.
|
|
||||||
|
|
||||||
This document explains all middleware components that come with Django, how to
|
|
||||||
use them, and how to write your own middleware.
|
|
||||||
|
|
||||||
Activating middleware
|
|
||||||
=====================
|
|
||||||
|
|
||||||
To activate a middleware component, add it to the ``MIDDLEWARE_CLASSES`` list
|
|
||||||
in your Django settings. In ``MIDDLEWARE_CLASSES``, each middleware component
|
|
||||||
is represented by a string: the full Python path to the middleware's class
|
|
||||||
name. For example, here's the default ``MIDDLEWARE_CLASSES`` created by
|
|
||||||
``django-admin.py startproject``::
|
|
||||||
|
|
||||||
MIDDLEWARE_CLASSES = (
|
|
||||||
'django.middleware.common.CommonMiddleware',
|
|
||||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
|
||||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
|
||||||
'django.middleware.doc.XViewMiddleware',
|
|
||||||
)
|
|
||||||
|
|
||||||
Django applies middleware in the order it's defined in ``MIDDLEWARE_CLASSES``,
|
|
||||||
except in the case of response and exception middleware, which is applied in
|
|
||||||
reverse order.
|
|
||||||
|
|
||||||
A Django installation doesn't require any middleware -- e.g.,
|
|
||||||
``MIDDLEWARE_CLASSES`` can be empty, if you'd like -- but it's strongly
|
|
||||||
suggested that you use ``CommonMiddleware``.
|
|
||||||
|
|
||||||
Available middleware
|
|
||||||
====================
|
|
||||||
|
|
||||||
django.middleware.cache.CacheMiddleware
|
|
||||||
---------------------------------------
|
|
||||||
|
|
||||||
Enables site-wide cache. If this is enabled, each Django-powered page will be
|
|
||||||
cached for as long as the ``CACHE_MIDDLEWARE_SECONDS`` setting defines. See
|
|
||||||
the `cache documentation`_.
|
|
||||||
|
|
||||||
.. _`cache documentation`: ../cache/#the-per-site-cache
|
|
||||||
|
|
||||||
django.middleware.common.CommonMiddleware
|
|
||||||
-----------------------------------------
|
|
||||||
|
|
||||||
Adds a few conveniences for perfectionists:
|
|
||||||
|
|
||||||
* Forbids access to user agents in the ``DISALLOWED_USER_AGENTS`` setting,
|
|
||||||
which should be a list of strings.
|
|
||||||
|
|
||||||
* Performs URL rewriting based on the ``APPEND_SLASH`` and ``PREPEND_WWW``
|
|
||||||
settings.
|
|
||||||
|
|
||||||
If ``APPEND_SLASH`` is ``True`` and the initial URL doesn't end with a slash,
|
|
||||||
and it is not found in the URLconf, then a new URL is formed by appending a
|
|
||||||
slash at the end. If this new URL is found in the URLconf, then Django
|
|
||||||
redirects the request to this new URL. Otherwise, the initial URL is
|
|
||||||
processed as usual.
|
|
||||||
|
|
||||||
For example, ``foo.com/bar`` will be redirected to ``foo.com/bar/`` if you
|
|
||||||
don't have a valid URL pattern for ``foo.com/bar`` but *do* have a valid
|
|
||||||
pattern for ``foo.com/bar/``.
|
|
||||||
|
|
||||||
**New in Django development version:** The behavior of ``APPEND_SLASH`` has
|
|
||||||
changed slightly in the development version. It didn't used to check whether
|
|
||||||
the pattern was matched in the URLconf.
|
|
||||||
|
|
||||||
If ``PREPEND_WWW`` is ``True``, URLs that lack a leading "www." will be
|
|
||||||
redirected to the same URL with a leading "www."
|
|
||||||
|
|
||||||
Both of these options are meant to normalize URLs. The philosophy is that
|
|
||||||
each URL should exist in one, and only one, place. Technically a URL
|
|
||||||
``foo.com/bar`` is distinct from ``foo.com/bar/`` -- a search-engine
|
|
||||||
indexer would treat them as separate URLs -- so it's best practice to
|
|
||||||
normalize URLs.
|
|
||||||
|
|
||||||
* Handles ETags based on the ``USE_ETAGS`` setting. If ``USE_ETAGS`` is set
|
|
||||||
to ``True``, Django will calculate an ETag for each request by
|
|
||||||
MD5-hashing the page content, and it'll take care of sending
|
|
||||||
``Not Modified`` responses, if appropriate.
|
|
||||||
|
|
||||||
django.middleware.doc.XViewMiddleware
|
|
||||||
-------------------------------------
|
|
||||||
|
|
||||||
Sends custom ``X-View`` HTTP headers to HEAD requests that come from IP
|
|
||||||
addresses defined in the ``INTERNAL_IPS`` setting. This is used by Django's
|
|
||||||
automatic documentation system.
|
|
||||||
|
|
||||||
django.middleware.gzip.GZipMiddleware
|
|
||||||
-------------------------------------
|
|
||||||
|
|
||||||
Compresses content for browsers that understand gzip compression (all modern
|
|
||||||
browsers).
|
|
||||||
|
|
||||||
It is suggested to place this first in the middleware list, so that the
|
|
||||||
compression of the response content is the last thing that happens. Will not
|
|
||||||
compress content bodies less than 200 bytes long, when the response code is
|
|
||||||
something other than 200, JavaScript files (for IE compatibitility), or
|
|
||||||
responses that have the ``Content-Encoding`` header already specified.
|
|
||||||
|
|
||||||
django.middleware.http.ConditionalGetMiddleware
|
|
||||||
-----------------------------------------------
|
|
||||||
|
|
||||||
Handles conditional GET operations. If the response has a ``ETag`` or
|
|
||||||
``Last-Modified`` header, and the request has ``If-None-Match`` or
|
|
||||||
``If-Modified-Since``, the response is replaced by an HttpNotModified.
|
|
||||||
|
|
||||||
Also sets the ``Date`` and ``Content-Length`` response-headers.
|
|
||||||
|
|
||||||
django.middleware.http.SetRemoteAddrFromForwardedFor
|
|
||||||
----------------------------------------------------
|
|
||||||
|
|
||||||
Sets ``request.META['REMOTE_ADDR']`` based on
|
|
||||||
``request.META['HTTP_X_FORWARDED_FOR']``, if the latter is set. This is useful
|
|
||||||
if you're sitting behind a reverse proxy that causes each request's
|
|
||||||
``REMOTE_ADDR`` to be set to ``127.0.0.1``.
|
|
||||||
|
|
||||||
**Important note:** This does NOT validate ``HTTP_X_FORWARDED_FOR``. If you're
|
|
||||||
not behind a reverse proxy that sets ``HTTP_X_FORWARDED_FOR`` automatically, do
|
|
||||||
not use this middleware. Anybody can spoof the value of
|
|
||||||
``HTTP_X_FORWARDED_FOR``, and because this sets ``REMOTE_ADDR`` based on
|
|
||||||
``HTTP_X_FORWARDED_FOR``, that means anybody can "fake" their IP address. Only
|
|
||||||
use this when you can absolutely trust the value of ``HTTP_X_FORWARDED_FOR``.
|
|
||||||
|
|
||||||
django.middleware.locale.LocaleMiddleware
|
|
||||||
-----------------------------------------
|
|
||||||
|
|
||||||
Enables language selection based on data from the request. It customizes content
|
|
||||||
for each user. See the `internationalization documentation`_.
|
|
||||||
|
|
||||||
.. _`internationalization documentation`: ../i18n/
|
|
||||||
|
|
||||||
django.contrib.sessions.middleware.SessionMiddleware
|
|
||||||
----------------------------------------------------
|
|
||||||
|
|
||||||
Enables session support. See the `session documentation`_.
|
|
||||||
|
|
||||||
.. _`session documentation`: ../sessions/
|
|
||||||
|
|
||||||
django.contrib.auth.middleware.AuthenticationMiddleware
|
|
||||||
-------------------------------------------------------
|
|
||||||
|
|
||||||
Adds the ``user`` attribute, representing the currently-logged-in user, to
|
|
||||||
every incoming ``HttpRequest`` object. See `Authentication in Web requests`_.
|
|
||||||
|
|
||||||
.. _Authentication in Web requests: ../authentication/#authentication-in-web-requests
|
|
||||||
|
|
||||||
django.contrib.csrf.middleware.CsrfMiddleware
|
|
||||||
---------------------------------------------
|
|
||||||
|
|
||||||
**New in Django development version**
|
|
||||||
|
|
||||||
Adds protection against Cross Site Request Forgeries by adding hidden form
|
|
||||||
fields to POST forms and checking requests for the correct value. See the
|
|
||||||
`Cross Site Request Forgery protection documentation`_.
|
|
||||||
|
|
||||||
.. _`Cross Site Request Forgery protection documentation`: ../csrf/
|
|
||||||
|
|
||||||
django.middleware.transaction.TransactionMiddleware
|
|
||||||
---------------------------------------------------
|
|
||||||
|
|
||||||
Binds commit and rollback to the request/response phase. If a view function runs
|
|
||||||
successfully, a commit is done. If it fails with an exception, a rollback is
|
|
||||||
done.
|
|
||||||
|
|
||||||
The order of this middleware in the stack is important: middleware modules
|
|
||||||
running outside of it run with commit-on-save - the default Django behavior.
|
|
||||||
Middleware modules running inside it (coming later in the stack) will be under
|
|
||||||
the same transaction control as the view functions.
|
|
||||||
|
|
||||||
See the `transaction management documentation`_.
|
|
||||||
|
|
||||||
.. _`transaction management documentation`: ../transactions/
|
|
||||||
|
|
||||||
Writing your own middleware
|
|
||||||
===========================
|
|
||||||
|
|
||||||
Writing your own middleware is easy. Each middleware component is a single
|
|
||||||
Python class that defines one or more of the following methods:
|
|
||||||
|
|
||||||
``process_request``
|
|
||||||
-------------------
|
|
||||||
|
|
||||||
Interface: ``process_request(self, request)``
|
|
||||||
|
|
||||||
``request`` is an ``HttpRequest`` object. This method is called on each
|
|
||||||
request, before Django decides which view to execute.
|
|
||||||
|
|
||||||
``process_request()`` should return either ``None`` or an ``HttpResponse``
|
|
||||||
object. If it returns ``None``, Django will continue processing this request,
|
|
||||||
executing any other middleware and, then, the appropriate view. If it returns
|
|
||||||
an ``HttpResponse`` object, Django won't bother calling ANY other request,
|
|
||||||
view or exception middleware, or the appropriate view; it'll return that
|
|
||||||
``HttpResponse``. Response middleware is always called on every response.
|
|
||||||
|
|
||||||
``process_view``
|
|
||||||
----------------
|
|
||||||
|
|
||||||
Interface: ``process_view(self, request, view_func, view_args, view_kwargs)``
|
|
||||||
|
|
||||||
``request`` is an ``HttpRequest`` object. ``view_func`` is the Python function
|
|
||||||
that Django is about to use. (It's the actual function object, not the name of
|
|
||||||
the function as a string.) ``view_args`` is a list of positional arguments that
|
|
||||||
will be passed to the view, and ``view_kwargs`` is a dictionary of keyword
|
|
||||||
arguments that will be passed to the view. Neither ``view_args`` nor
|
|
||||||
``view_kwargs`` include the first view argument (``request``).
|
|
||||||
|
|
||||||
``process_view()`` is called just before Django calls the view. It should
|
|
||||||
return either ``None`` or an ``HttpResponse`` object. If it returns ``None``,
|
|
||||||
Django will continue processing this request, executing any other
|
|
||||||
``process_view()`` middleware and, then, the appropriate view. If it returns an
|
|
||||||
``HttpResponse`` object, Django won't bother calling ANY other request, view
|
|
||||||
or exception middleware, or the appropriate view; it'll return that
|
|
||||||
``HttpResponse``. Response middleware is always called on every response.
|
|
||||||
|
|
||||||
``process_response``
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
Interface: ``process_response(self, request, response)``
|
|
||||||
|
|
||||||
``request`` is an ``HttpRequest`` object. ``response`` is the ``HttpResponse``
|
|
||||||
object returned by a Django view.
|
|
||||||
|
|
||||||
``process_response()`` should return an ``HttpResponse`` object. It could alter
|
|
||||||
the given ``response``, or it could create and return a brand-new
|
|
||||||
``HttpResponse``.
|
|
||||||
|
|
||||||
``process_exception``
|
|
||||||
---------------------
|
|
||||||
|
|
||||||
Interface: ``process_exception(self, request, exception)``
|
|
||||||
|
|
||||||
``request`` is an ``HttpRequest`` object. ``exception`` is an ``Exception``
|
|
||||||
object raised by the view function.
|
|
||||||
|
|
||||||
Django calls ``process_exception()`` when a view raises an exception.
|
|
||||||
``process_exception()`` should return either ``None`` or an ``HttpResponse``
|
|
||||||
object. If it returns an ``HttpResponse`` object, the response will be returned
|
|
||||||
to the browser. Otherwise, default exception handling kicks in.
|
|
||||||
|
|
||||||
``__init__``
|
|
||||||
------------
|
|
||||||
|
|
||||||
Most middleware classes won't need an initializer since middleware classes are
|
|
||||||
essentially placeholders for the ``process_*`` methods. If you do need some
|
|
||||||
global state you may use ``__init__`` to set up. However, keep in mind a couple
|
|
||||||
of caveats:
|
|
||||||
|
|
||||||
* Django initializes your middleware without any arguments, so you can't
|
|
||||||
define ``__init__`` as requiring any arguments.
|
|
||||||
|
|
||||||
* Unlike the ``process_*`` methods which get called once per request,
|
|
||||||
``__init__`` gets called only *once*, when the web server starts up.
|
|
||||||
|
|
||||||
Marking middleware as unused
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
It's sometimes useful to determine at run-time whether a piece of middleware
|
|
||||||
should be used. In these cases, your middleware's ``__init__`` method may raise
|
|
||||||
``django.core.exceptions.MiddlewareNotUsed``. Django will then remove that piece
|
|
||||||
of middleware from the middleware process.
|
|
||||||
|
|
||||||
Guidelines
|
|
||||||
----------
|
|
||||||
|
|
||||||
* Middleware classes don't have to subclass anything.
|
|
||||||
|
|
||||||
* The middleware class can live anywhere on your Python path. All Django
|
|
||||||
cares about is that the ``MIDDLEWARE_CLASSES`` setting includes the path
|
|
||||||
to it.
|
|
||||||
|
|
||||||
* Feel free to look at Django's available middleware for examples. The
|
|
||||||
core Django middleware classes are in ``django/middleware/`` in the
|
|
||||||
Django distribution. The session middleware is in
|
|
||||||
``django/contrib/sessions``.
|
|
||||||
|
|
||||||
* If you write a middleware component that you think would be useful to
|
|
||||||
other people, contribute to the community! Let us know, and we'll
|
|
||||||
consider adding it to Django.
|
|
|
@ -0,0 +1,95 @@
|
||||||
|
.. _misc-api-stability:
|
||||||
|
|
||||||
|
=============
|
||||||
|
API stability
|
||||||
|
=============
|
||||||
|
|
||||||
|
Although Django has not reached a 1.0 release, the bulk of Django's public APIs are
|
||||||
|
stable as of the 0.95 release. This document explains which APIs will and will not
|
||||||
|
change before the 1.0 release.
|
||||||
|
|
||||||
|
What "stable" means
|
||||||
|
===================
|
||||||
|
|
||||||
|
In this context, stable means:
|
||||||
|
|
||||||
|
- All the public APIs -- everything documented in the linked documents, and
|
||||||
|
all methods that don't begin with an underscore -- will not be moved or
|
||||||
|
renamed without providing backwards-compatible aliases.
|
||||||
|
|
||||||
|
- If new features are added to these APIs -- which is quite possible --
|
||||||
|
they will not break or change the meaning of existing methods. In other
|
||||||
|
words, "stable" does not (necessarily) mean "complete."
|
||||||
|
|
||||||
|
- If, for some reason, an API declared stable must be removed or replaced, it
|
||||||
|
will be declared deprecated but will remain in the API until at least
|
||||||
|
version 1.1. Warnings will be issued when the deprecated method is
|
||||||
|
called.
|
||||||
|
|
||||||
|
- We'll only break backwards compatibility of these APIs if a bug or
|
||||||
|
security hole makes it completely unavoidable.
|
||||||
|
|
||||||
|
Stable APIs
|
||||||
|
===========
|
||||||
|
|
||||||
|
These APIs are stable:
|
||||||
|
|
||||||
|
- :ref:`Caching <topics-cache>`.
|
||||||
|
|
||||||
|
- :ref:`Custom template tags and libraries <howto-custom-template-tags>`.
|
||||||
|
|
||||||
|
- :ref:`Database lookup <topics-db-queries>` (with the exception of validation; see below).
|
||||||
|
|
||||||
|
- :ref:`django-admin utility <ref-django-admin>`.
|
||||||
|
|
||||||
|
- :ref:`FastCGI and mod_python integration <howto-deployment-index>`.
|
||||||
|
|
||||||
|
- :ref:`Flatpages <ref-contrib-flatpages>`.
|
||||||
|
|
||||||
|
- :ref:`Generic views <topics-http-generic-views>`.
|
||||||
|
|
||||||
|
- :ref:`Internationalization <topics-i18n>`.
|
||||||
|
|
||||||
|
- :ref:`Legacy database integration <howto-legacy-databases>`.
|
||||||
|
|
||||||
|
- :ref:`Model definition <topics-db-models>` (with the exception of generic relations; see below).
|
||||||
|
|
||||||
|
- :ref:`Redirects <ref-contrib-redirects>`.
|
||||||
|
|
||||||
|
- :ref:`Request/response objects <ref-request-response>`.
|
||||||
|
|
||||||
|
- :ref:`Sending e-mail <topics-email>`.
|
||||||
|
|
||||||
|
- :ref:`Sessions <topics-http-sessions>`.
|
||||||
|
|
||||||
|
- :ref:`Settings <topics-settings>`.
|
||||||
|
|
||||||
|
- :ref:`Syndication <ref-contrib-syndication>`.
|
||||||
|
|
||||||
|
- :ref:`Template language <topics-templates>` (with the exception of some
|
||||||
|
possible disambiguation of how tag arguments are passed to tags and
|
||||||
|
filters).
|
||||||
|
|
||||||
|
- :ref:`Transactions <topics-db-transactions>`.
|
||||||
|
|
||||||
|
- :ref:`URL dispatch <topics-http-urls>`.
|
||||||
|
|
||||||
|
You'll notice that this list comprises the bulk of Django's APIs. That's right
|
||||||
|
-- most of the changes planned between now and Django 1.0 are either under the
|
||||||
|
hood, feature additions, or changes to a few select bits. A good estimate is
|
||||||
|
that 90% of Django can be considered forwards-compatible at this point.
|
||||||
|
|
||||||
|
That said, these APIs should *not* be considered stable, and are likely to
|
||||||
|
change:
|
||||||
|
|
||||||
|
- :ref:`Serialization <topics-serialization>` is under development; changes
|
||||||
|
are possible.
|
||||||
|
|
||||||
|
- Generic relations will most likely be moved out of core and into the
|
||||||
|
content-types contrib package to avoid core dependencies on optional
|
||||||
|
components.
|
||||||
|
|
||||||
|
**New in development version**: this has now been done.
|
||||||
|
|
||||||
|
- The comments framework, which is yet undocumented, will get a complete
|
||||||
|
rewrite before Django 1.0.
|
|
@ -1,3 +1,5 @@
|
||||||
|
.. _misc-design-philosophies:
|
||||||
|
|
||||||
===================
|
===================
|
||||||
Design philosophies
|
Design philosophies
|
||||||
===================
|
===================
|
||||||
|
@ -9,9 +11,13 @@ the future.
|
||||||
Overall
|
Overall
|
||||||
=======
|
=======
|
||||||
|
|
||||||
|
.. _loose-coupling:
|
||||||
|
|
||||||
Loose coupling
|
Loose coupling
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
|
.. index:: coupling; loose
|
||||||
|
|
||||||
A fundamental goal of Django's stack is `loose coupling and tight cohesion`_.
|
A fundamental goal of Django's stack is `loose coupling and tight cohesion`_.
|
||||||
The various layers of the framework shouldn't "know" about each other unless
|
The various layers of the framework shouldn't "know" about each other unless
|
||||||
absolutely necessary.
|
absolutely necessary.
|
||||||
|
@ -25,6 +31,8 @@ stack are independent of another wherever possible.
|
||||||
|
|
||||||
.. _`loose coupling and tight cohesion`: http://c2.com/cgi/wiki?CouplingAndCohesion
|
.. _`loose coupling and tight cohesion`: http://c2.com/cgi/wiki?CouplingAndCohesion
|
||||||
|
|
||||||
|
.. _less-code:
|
||||||
|
|
||||||
Less code
|
Less code
|
||||||
---------
|
---------
|
||||||
|
|
||||||
|
@ -32,6 +40,8 @@ Django apps should use as little code as possible; they should lack boilerplate.
|
||||||
Django should take full advantage of Python's dynamic capabilities, such as
|
Django should take full advantage of Python's dynamic capabilities, such as
|
||||||
introspection.
|
introspection.
|
||||||
|
|
||||||
|
.. _quick-development:
|
||||||
|
|
||||||
Quick development
|
Quick development
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
@ -39,15 +49,29 @@ The point of a Web framework in the 21st century is to make the tedious aspects
|
||||||
of Web development fast. Django should allow for incredibly quick Web
|
of Web development fast. Django should allow for incredibly quick Web
|
||||||
development.
|
development.
|
||||||
|
|
||||||
|
.. _dry:
|
||||||
|
|
||||||
Don't repeat yourself (DRY)
|
Don't repeat yourself (DRY)
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
||||||
|
.. index::
|
||||||
|
single: DRY
|
||||||
|
single: Don't repeat yourself
|
||||||
|
|
||||||
Every distinct concept and/or piece of data should live in one, and only one,
|
Every distinct concept and/or piece of data should live in one, and only one,
|
||||||
place. Redundancy is bad. Normalization is good.
|
place. Redundancy is bad. Normalization is good.
|
||||||
|
|
||||||
The framework, within reason, should deduce as much as possible from as little
|
The framework, within reason, should deduce as much as possible from as little
|
||||||
as possible.
|
as possible.
|
||||||
|
|
||||||
|
.. seealso::
|
||||||
|
|
||||||
|
The `discussion of DRY on the Portland Pattern Repository`__
|
||||||
|
|
||||||
|
__ http://c2.com/cgi/wiki?DontRepeatYourself
|
||||||
|
|
||||||
|
.. _explicit-is-better-than-implicit:
|
||||||
|
|
||||||
Explicit is better than implicit
|
Explicit is better than implicit
|
||||||
--------------------------------
|
--------------------------------
|
||||||
|
|
||||||
|
@ -59,6 +83,8 @@ learn how to use the feature.
|
||||||
|
|
||||||
.. _`core Python principle`: http://www.python.org/dev/peps/pep-0020/
|
.. _`core Python principle`: http://www.python.org/dev/peps/pep-0020/
|
||||||
|
|
||||||
|
.. _consistency:
|
||||||
|
|
||||||
Consistency
|
Consistency
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
|
@ -155,19 +181,25 @@ File extensions in Web-page URLs should be avoided.
|
||||||
|
|
||||||
Vignette-style commas in URLs deserve severe punishment.
|
Vignette-style commas in URLs deserve severe punishment.
|
||||||
|
|
||||||
|
.. _definitive-urls:
|
||||||
|
|
||||||
Definitive URLs
|
Definitive URLs
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
|
.. index:: urls; definitive
|
||||||
|
|
||||||
Technically, ``foo.com/bar`` and ``foo.com/bar/`` are two different URLs, and
|
Technically, ``foo.com/bar`` and ``foo.com/bar/`` are two different URLs, and
|
||||||
search-engine robots (and some Web traffic-analyzing tools) would treat them as
|
search-engine robots (and some Web traffic-analyzing tools) would treat them as
|
||||||
separate pages. Django should make an effort to "normalize" URLs so that
|
separate pages. Django should make an effort to "normalize" URLs so that
|
||||||
search-engine robots don't get confused.
|
search-engine robots don't get confused.
|
||||||
|
|
||||||
This is the reasoning behind the ``APPEND_SLASH`` setting.
|
This is the reasoning behind the :setting:`APPEND_SLASH` setting.
|
||||||
|
|
||||||
Template system
|
Template system
|
||||||
===============
|
===============
|
||||||
|
|
||||||
|
.. _separation-of-logic-and-presentation:
|
||||||
|
|
||||||
Separate logic from presentation
|
Separate logic from presentation
|
||||||
--------------------------------
|
--------------------------------
|
||||||
|
|
||||||
|
@ -186,9 +218,8 @@ a common header, footer, navigation bar, etc. The Django template system should
|
||||||
make it easy to store those elements in a single place, eliminating duplicate
|
make it easy to store those elements in a single place, eliminating duplicate
|
||||||
code.
|
code.
|
||||||
|
|
||||||
This is the philosophy behind `template inheritance`_.
|
This is the philosophy behind :ref:`template inheritance
|
||||||
|
<template-inheritance>`.
|
||||||
.. _template inheritance: ../templates/#template-inheritance
|
|
||||||
|
|
||||||
Be decoupled from HTML
|
Be decoupled from HTML
|
||||||
----------------------
|
----------------------
|
||||||
|
@ -200,6 +231,8 @@ text.
|
||||||
XML should not be used for template languages
|
XML should not be used for template languages
|
||||||
---------------------------------------------
|
---------------------------------------------
|
||||||
|
|
||||||
|
.. index:: xml; suckiness of
|
||||||
|
|
||||||
Using an XML engine to parse templates introduces a whole new world of human
|
Using an XML engine to parse templates introduces a whole new world of human
|
||||||
error in editing templates -- and incurs an unacceptable level of overhead in
|
error in editing templates -- and incurs an unacceptable level of overhead in
|
||||||
template processing.
|
template processing.
|
|
@ -1,3 +1,5 @@
|
||||||
|
.. _misc-distributions:
|
||||||
|
|
||||||
===================================
|
===================================
|
||||||
Third-party distributions of Django
|
Third-party distributions of Django
|
||||||
===================================
|
===================================
|
||||||
|
@ -10,10 +12,8 @@ requires.
|
||||||
|
|
||||||
Typically, these packages are based on the latest stable release of Django, so
|
Typically, these packages are based on the latest stable release of Django, so
|
||||||
if you want to use the development version of Django you'll need to follow the
|
if you want to use the development version of Django you'll need to follow the
|
||||||
instructions for `installing the development version`_ from our Subversion
|
instructions for :ref:`installing the development version
|
||||||
repository.
|
<installing-development-version>` from our Subversion repository.
|
||||||
|
|
||||||
.. _installing the development version: ../install/#installing-the-development-version
|
|
||||||
|
|
||||||
FreeBSD
|
FreeBSD
|
||||||
=======
|
=======
|
|
@ -0,0 +1,14 @@
|
||||||
|
.. _misc-index:
|
||||||
|
|
||||||
|
Meta-documentation and miscellany
|
||||||
|
=================================
|
||||||
|
|
||||||
|
Documentation that we can't find a more organized place for. Like that drawer in
|
||||||
|
your kitchen with the scissors, batteries, duct tape, and other junk.
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
api-stability
|
||||||
|
design-philosophies
|
||||||
|
distributions
|
2145
docs/model-api.txt
After Width: | Height: | Size: 8.9 KiB |
After Width: | Height: | Size: 5.7 KiB |