mirror of
https://github.com/django/django.git
synced 2025-07-04 17:59:13 +00:00
boulder-oracle-sprint: Merged to [5462]
git-svn-id: http://code.djangoproject.com/svn/django/branches/boulder-oracle-sprint@5463 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
5e8eef19dc
commit
0f36cbec13
4
AUTHORS
4
AUTHORS
@ -73,6 +73,7 @@ answer newbie questions, and generally made Django that much better:
|
|||||||
Michal Chruszcz <troll@pld-linux.org>
|
Michal Chruszcz <troll@pld-linux.org>
|
||||||
Ian Clelland <clelland@gmail.com>
|
Ian Clelland <clelland@gmail.com>
|
||||||
crankycoder@gmail.com
|
crankycoder@gmail.com
|
||||||
|
Pete Crosier <pete.crosier@gmail.com>
|
||||||
Matt Croydon <http://www.postneo.com/>
|
Matt Croydon <http://www.postneo.com/>
|
||||||
flavio.curella@gmail.com
|
flavio.curella@gmail.com
|
||||||
Jure Cuhalev <gandalf@owca.info>
|
Jure Cuhalev <gandalf@owca.info>
|
||||||
@ -130,6 +131,7 @@ answer newbie questions, and generally made Django that much better:
|
|||||||
junzhang.jn@gmail.com
|
junzhang.jn@gmail.com
|
||||||
Antti Kaihola <http://akaihola.blogspot.com/>
|
Antti Kaihola <http://akaihola.blogspot.com/>
|
||||||
Ben Dean Kawamura <ben.dean.kawamura@gmail.com>
|
Ben Dean Kawamura <ben.dean.kawamura@gmail.com>
|
||||||
|
ian.g.kelly@gmail.com
|
||||||
Garth Kidd <http://www.deadlybloodyserious.com/>
|
Garth Kidd <http://www.deadlybloodyserious.com/>
|
||||||
kilian <kilian.cavalotti@lip6.fr>
|
kilian <kilian.cavalotti@lip6.fr>
|
||||||
Sune Kirkeby <http://ibofobi.dk/>
|
Sune Kirkeby <http://ibofobi.dk/>
|
||||||
@ -169,6 +171,7 @@ answer newbie questions, and generally made Django that much better:
|
|||||||
mitakummaa@gmail.com
|
mitakummaa@gmail.com
|
||||||
mmarshall
|
mmarshall
|
||||||
Eric Moritz <http://eric.themoritzfamily.com/>
|
Eric Moritz <http://eric.themoritzfamily.com/>
|
||||||
|
mrmachine <real.human@mrmachine.net>
|
||||||
Robin Munn <http://www.geekforgod.com/>
|
Robin Munn <http://www.geekforgod.com/>
|
||||||
Robert Myers <myer0052@gmail.com>
|
Robert Myers <myer0052@gmail.com>
|
||||||
Nebojša Dorđević
|
Nebojša Dorđević
|
||||||
@ -234,6 +237,7 @@ answer newbie questions, and generally made Django that much better:
|
|||||||
wangchun <yaohua2000@gmail.com>
|
wangchun <yaohua2000@gmail.com>
|
||||||
Dan Watson <http://theidioteque.net/>
|
Dan Watson <http://theidioteque.net/>
|
||||||
Chris Wesseling <Chris.Wesseling@cwi.nl>
|
Chris Wesseling <Chris.Wesseling@cwi.nl>
|
||||||
|
James Wheare <django@sparemint.com>
|
||||||
charly.wilhelm@gmail.com
|
charly.wilhelm@gmail.com
|
||||||
Rachel Willmer <http://www.willmer.com/kb/>
|
Rachel Willmer <http://www.willmer.com/kb/>
|
||||||
Gary Wilson <gary.wilson@gmail.com>
|
Gary Wilson <gary.wilson@gmail.com>
|
||||||
|
@ -1 +1,8 @@
|
|||||||
VERSION = (0, 97, 'pre')
|
VERSION = (0, 97, 'pre')
|
||||||
|
|
||||||
|
def get_version():
|
||||||
|
"Returns the version as a human-format string."
|
||||||
|
v = '.'.join([str(i) for i in VERSION[:-1]])
|
||||||
|
if VERSION[-1]:
|
||||||
|
v += '-' + VERSION[-1]
|
||||||
|
return v
|
||||||
|
@ -241,7 +241,8 @@ TRANSACTIONS_MANAGED = False
|
|||||||
|
|
||||||
# The User-Agent string to use when checking for URL validity through the
|
# The User-Agent string to use when checking for URL validity through the
|
||||||
# isExistingURL validator.
|
# isExistingURL validator.
|
||||||
URL_VALIDATOR_USER_AGENT = "Django/0.96pre (http://www.djangoproject.com)"
|
from django import get_version
|
||||||
|
URL_VALIDATOR_USER_AGENT = "Django/%s (http://www.djangoproject.com)" % get_version()
|
||||||
|
|
||||||
##############
|
##############
|
||||||
# MIDDLEWARE #
|
# MIDDLEWARE #
|
||||||
|
Binary file not shown.
@ -2202,10 +2202,11 @@ msgstr[0] "dag"
|
|||||||
msgstr[1] "dagen"
|
msgstr[1] "dagen"
|
||||||
|
|
||||||
#: utils/timesince.py:16
|
#: utils/timesince.py:16
|
||||||
|
# In the timesince context it is stilistically wrong to use the plural for hour in Dutch.
|
||||||
msgid "hour"
|
msgid "hour"
|
||||||
msgid_plural "hours"
|
msgid_plural "hours"
|
||||||
msgstr[0] "uur"
|
msgstr[0] "uur"
|
||||||
msgstr[1] "uren"
|
msgstr[1] "uur"
|
||||||
|
|
||||||
#: utils/timesince.py:17
|
#: utils/timesince.py:17
|
||||||
msgid "minute"
|
msgid "minute"
|
||||||
|
@ -3,14 +3,17 @@
|
|||||||
|
|
||||||
import django
|
import django
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
import os, re, shutil, sys, textwrap
|
|
||||||
from optparse import OptionParser
|
from optparse import OptionParser
|
||||||
from django.utils import termcolors
|
from django.utils import termcolors
|
||||||
|
import os, re, shutil, sys, textwrap
|
||||||
|
|
||||||
# For Python 2.3
|
# For Python 2.3
|
||||||
if not hasattr(__builtins__, 'set'):
|
if not hasattr(__builtins__, 'set'):
|
||||||
from sets import Set as set
|
from sets import Set as set
|
||||||
|
|
||||||
|
# For backwards compatibility: get_version() used to be in this module.
|
||||||
|
get_version = django.get_version
|
||||||
|
|
||||||
MODULE_TEMPLATE = ''' {%% if perms.%(app)s.%(addperm)s or perms.%(app)s.%(changeperm)s %%}
|
MODULE_TEMPLATE = ''' {%% if perms.%(app)s.%(addperm)s or perms.%(app)s.%(changeperm)s %%}
|
||||||
<tr>
|
<tr>
|
||||||
<th>{%% if perms.%(app)s.%(changeperm)s %%}<a href="%(app)s/%(mod)s/">{%% endif %%}%(name)s{%% if perms.%(app)s.%(changeperm)s %%}</a>{%% endif %%}</th>
|
<th>{%% if perms.%(app)s.%(changeperm)s %%}<a href="%(app)s/%(mod)s/">{%% endif %%}%(name)s{%% if perms.%(app)s.%(changeperm)s %%}</a>{%% endif %%}</th>
|
||||||
@ -97,14 +100,6 @@ def _get_sequence_list():
|
|||||||
# field as the field to which it points.
|
# field as the field to which it points.
|
||||||
get_rel_data_type = lambda f: (f.get_internal_type() in ('AutoField', 'PositiveIntegerField', 'PositiveSmallIntegerField')) and 'IntegerField' or f.get_internal_type()
|
get_rel_data_type = lambda f: (f.get_internal_type() in ('AutoField', 'PositiveIntegerField', 'PositiveSmallIntegerField')) and 'IntegerField' or f.get_internal_type()
|
||||||
|
|
||||||
def get_version():
|
|
||||||
"Returns the version as a human-format string."
|
|
||||||
from django import VERSION
|
|
||||||
v = '.'.join([str(i) for i in VERSION[:-1]])
|
|
||||||
if VERSION[-1]:
|
|
||||||
v += '-' + VERSION[-1]
|
|
||||||
return v
|
|
||||||
|
|
||||||
def get_sql_create(app):
|
def get_sql_create(app):
|
||||||
"Returns a list of the CREATE TABLE SQL statements for the given app."
|
"Returns a list of the CREATE TABLE SQL statements for the given app."
|
||||||
from django.db import get_creation_module, models
|
from django.db import get_creation_module, models
|
||||||
|
@ -238,22 +238,27 @@ def get_sql_sequence_reset(style, model_list):
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
output = []
|
output = []
|
||||||
for model in model_list:
|
for model in model_list:
|
||||||
|
# Use `coalesce` to set the sequence for each model to the max pk value if there are records,
|
||||||
|
# or 1 if there are none. Set the `is_called` property (the third argument to `setval`) to true
|
||||||
|
# if there are records (as the max pk value is already in use), otherwise set it to false.
|
||||||
for f in model._meta.fields:
|
for f in model._meta.fields:
|
||||||
if isinstance(f, models.AutoField):
|
if isinstance(f, models.AutoField):
|
||||||
output.append("%s setval('%s', (%s max(%s) %s %s));" % \
|
output.append("%s setval('%s', coalesce(max(%s), 1), max(%s) %s null) %s %s;" % \
|
||||||
(style.SQL_KEYWORD('SELECT'),
|
(style.SQL_KEYWORD('SELECT'),
|
||||||
style.SQL_FIELD(quote_name('%s_%s_seq' % (model._meta.db_table, f.column))),
|
style.SQL_FIELD(quote_name('%s_%s_seq' % (model._meta.db_table, f.column))),
|
||||||
style.SQL_KEYWORD('SELECT'),
|
|
||||||
style.SQL_FIELD(quote_name(f.column)),
|
style.SQL_FIELD(quote_name(f.column)),
|
||||||
|
style.SQL_FIELD(quote_name(f.column)),
|
||||||
|
style.SQL_KEYWORD('IS NOT'),
|
||||||
style.SQL_KEYWORD('FROM'),
|
style.SQL_KEYWORD('FROM'),
|
||||||
style.SQL_TABLE(quote_name(model._meta.db_table))))
|
style.SQL_TABLE(quote_name(model._meta.db_table))))
|
||||||
break # Only one AutoField is allowed per model, so don't bother continuing.
|
break # Only one AutoField is allowed per model, so don't bother continuing.
|
||||||
for f in model._meta.many_to_many:
|
for f in model._meta.many_to_many:
|
||||||
output.append("%s setval('%s', (%s max(%s) %s %s));" % \
|
output.append("%s setval('%s', coalesce(max(%s), 1), max(%s) %s null) %s %s;" % \
|
||||||
(style.SQL_KEYWORD('SELECT'),
|
(style.SQL_KEYWORD('SELECT'),
|
||||||
style.SQL_FIELD(quote_name('%s_id_seq' % f.m2m_db_table())),
|
style.SQL_FIELD(quote_name('%s_id_seq' % f.m2m_db_table())),
|
||||||
style.SQL_KEYWORD('SELECT'),
|
|
||||||
style.SQL_FIELD(quote_name('id')),
|
style.SQL_FIELD(quote_name('id')),
|
||||||
|
style.SQL_FIELD(quote_name('id')),
|
||||||
|
style.SQL_KEYWORD('IS NOT'),
|
||||||
style.SQL_KEYWORD('FROM'),
|
style.SQL_KEYWORD('FROM'),
|
||||||
style.SQL_TABLE(f.m2m_db_table())))
|
style.SQL_TABLE(f.m2m_db_table())))
|
||||||
return output
|
return output
|
||||||
|
@ -195,22 +195,27 @@ def get_sql_sequence_reset(style, model_list):
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
output = []
|
output = []
|
||||||
for model in model_list:
|
for model in model_list:
|
||||||
|
# Use `coalesce` to set the sequence for each model to the max pk value if there are records,
|
||||||
|
# or 1 if there are none. Set the `is_called` property (the third argument to `setval`) to true
|
||||||
|
# if there are records (as the max pk value is already in use), otherwise set it to false.
|
||||||
for f in model._meta.fields:
|
for f in model._meta.fields:
|
||||||
if isinstance(f, models.AutoField):
|
if isinstance(f, models.AutoField):
|
||||||
output.append("%s setval('%s', (%s max(%s) %s %s));" % \
|
output.append("%s setval('%s', coalesce(max(%s), 1), max(%s) %s null) %s %s;" % \
|
||||||
(style.SQL_KEYWORD('SELECT'),
|
(style.SQL_KEYWORD('SELECT'),
|
||||||
style.SQL_FIELD(quote_name('%s_%s_seq' % (model._meta.db_table, f.column))),
|
style.SQL_FIELD(quote_name('%s_%s_seq' % (model._meta.db_table, f.column))),
|
||||||
style.SQL_KEYWORD('SELECT'),
|
|
||||||
style.SQL_FIELD(quote_name(f.column)),
|
style.SQL_FIELD(quote_name(f.column)),
|
||||||
|
style.SQL_FIELD(quote_name(f.column)),
|
||||||
|
style.SQL_KEYWORD('IS NOT'),
|
||||||
style.SQL_KEYWORD('FROM'),
|
style.SQL_KEYWORD('FROM'),
|
||||||
style.SQL_TABLE(quote_name(model._meta.db_table))))
|
style.SQL_TABLE(quote_name(model._meta.db_table))))
|
||||||
break # Only one AutoField is allowed per model, so don't bother continuing.
|
break # Only one AutoField is allowed per model, so don't bother continuing.
|
||||||
for f in model._meta.many_to_many:
|
for f in model._meta.many_to_many:
|
||||||
output.append("%s setval('%s', (%s max(%s) %s %s));" % \
|
output.append("%s setval('%s', coalesce(max(%s), 1), max(%s) %s null) %s %s;" % \
|
||||||
(style.SQL_KEYWORD('SELECT'),
|
(style.SQL_KEYWORD('SELECT'),
|
||||||
style.SQL_FIELD(quote_name('%s_id_seq' % f.m2m_db_table())),
|
style.SQL_FIELD(quote_name('%s_id_seq' % f.m2m_db_table())),
|
||||||
style.SQL_KEYWORD('SELECT'),
|
|
||||||
style.SQL_FIELD(quote_name('id')),
|
style.SQL_FIELD(quote_name('id')),
|
||||||
|
style.SQL_FIELD(quote_name('id')),
|
||||||
|
style.SQL_KEYWORD('IS NOT'),
|
||||||
style.SQL_KEYWORD('FROM'),
|
style.SQL_KEYWORD('FROM'),
|
||||||
style.SQL_TABLE(f.m2m_db_table())))
|
style.SQL_TABLE(f.m2m_db_table())))
|
||||||
return output
|
return output
|
||||||
|
@ -92,7 +92,7 @@ def typecast_boolean(s):
|
|||||||
return str(s)[0].lower() == 't'
|
return str(s)[0].lower() == 't'
|
||||||
|
|
||||||
def typecast_decimal(s):
|
def typecast_decimal(s):
|
||||||
if s is None:
|
if s is None or s == '':
|
||||||
return None
|
return None
|
||||||
return decimal.Decimal(s)
|
return decimal.Decimal(s)
|
||||||
|
|
||||||
|
@ -5,6 +5,15 @@ from django.template import TemplateSyntaxError, VariableDoesNotExist, BLOCK_TAG
|
|||||||
from django.template import get_library, Library, InvalidTemplateLibrary
|
from django.template import get_library, Library, InvalidTemplateLibrary
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
import sys
|
import sys
|
||||||
|
import re
|
||||||
|
|
||||||
|
if not hasattr(__builtins__, 'reversed'):
|
||||||
|
# For Python 2.3.
|
||||||
|
# From http://www.python.org/doc/current/tut/node11.html
|
||||||
|
def reversed(data):
|
||||||
|
for index in xrange(len(data)-1, -1, -1):
|
||||||
|
yield data[index]
|
||||||
|
|
||||||
|
|
||||||
register = Library()
|
register = Library()
|
||||||
|
|
||||||
@ -61,8 +70,8 @@ class FirstOfNode(Node):
|
|||||||
return ''
|
return ''
|
||||||
|
|
||||||
class ForNode(Node):
|
class ForNode(Node):
|
||||||
def __init__(self, loopvar, sequence, reversed, nodelist_loop):
|
def __init__(self, loopvars, sequence, reversed, nodelist_loop):
|
||||||
self.loopvar, self.sequence = loopvar, sequence
|
self.loopvars, self.sequence = loopvars, sequence
|
||||||
self.reversed = reversed
|
self.reversed = reversed
|
||||||
self.nodelist_loop = nodelist_loop
|
self.nodelist_loop = nodelist_loop
|
||||||
|
|
||||||
@ -72,7 +81,7 @@ class ForNode(Node):
|
|||||||
else:
|
else:
|
||||||
reversed = ''
|
reversed = ''
|
||||||
return "<For Node: for %s in %s, tail_len: %d%s>" % \
|
return "<For Node: for %s in %s, tail_len: %d%s>" % \
|
||||||
(self.loopvar, self.sequence, len(self.nodelist_loop), reversed)
|
(', '.join( self.loopvars ), self.sequence, len(self.nodelist_loop), reversed)
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
for node in self.nodelist_loop:
|
for node in self.nodelist_loop:
|
||||||
@ -102,11 +111,8 @@ class ForNode(Node):
|
|||||||
values = list(values)
|
values = list(values)
|
||||||
len_values = len(values)
|
len_values = len(values)
|
||||||
if self.reversed:
|
if self.reversed:
|
||||||
# From http://www.python.org/doc/current/tut/node11.html
|
values = reversed(values)
|
||||||
def reverse(data):
|
unpack = len(self.loopvars) > 1
|
||||||
for index in range(len(data)-1, -1, -1):
|
|
||||||
yield data[index]
|
|
||||||
values = reverse(values)
|
|
||||||
for i, item in enumerate(values):
|
for i, item in enumerate(values):
|
||||||
context['forloop'] = {
|
context['forloop'] = {
|
||||||
# shortcuts for current loop iteration number
|
# shortcuts for current loop iteration number
|
||||||
@ -120,9 +126,20 @@ class ForNode(Node):
|
|||||||
'last': (i == len_values - 1),
|
'last': (i == len_values - 1),
|
||||||
'parentloop': parentloop,
|
'parentloop': parentloop,
|
||||||
}
|
}
|
||||||
context[self.loopvar] = item
|
if unpack:
|
||||||
|
# If there are multiple loop variables, unpack the item into them.
|
||||||
|
context.update(dict(zip(self.loopvars, item)))
|
||||||
|
else:
|
||||||
|
context[self.loopvars[0]] = item
|
||||||
for node in self.nodelist_loop:
|
for node in self.nodelist_loop:
|
||||||
nodelist.append(node.render(context))
|
nodelist.append(node.render(context))
|
||||||
|
if unpack:
|
||||||
|
# The loop variables were pushed on to the context so pop them
|
||||||
|
# off again. This is necessary because the tag lets the length
|
||||||
|
# of loopvars differ to the length of each set of items and we
|
||||||
|
# don't want to leave any vars from the previous loop on the
|
||||||
|
# context.
|
||||||
|
context.pop()
|
||||||
context.pop()
|
context.pop()
|
||||||
return nodelist.render(context)
|
return nodelist.render(context)
|
||||||
|
|
||||||
@ -486,7 +503,7 @@ def do_filter(parser, token):
|
|||||||
nodelist = parser.parse(('endfilter',))
|
nodelist = parser.parse(('endfilter',))
|
||||||
parser.delete_first_token()
|
parser.delete_first_token()
|
||||||
return FilterNode(filter_expr, nodelist)
|
return FilterNode(filter_expr, nodelist)
|
||||||
filter = register.tag("filter", do_filter)
|
do_filter = register.tag("filter", do_filter)
|
||||||
|
|
||||||
#@register.tag
|
#@register.tag
|
||||||
def firstof(parser, token):
|
def firstof(parser, token):
|
||||||
@ -530,9 +547,15 @@ def do_for(parser, token):
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
You can also loop over a list in reverse by using
|
You can loop over a list in reverse by using
|
||||||
``{% for obj in list reversed %}``.
|
``{% for obj in list reversed %}``.
|
||||||
|
|
||||||
|
You can also unpack multiple values from a two-dimensional array::
|
||||||
|
|
||||||
|
{% for key,value in dict.items %}
|
||||||
|
{{ key }}: {{ value }}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
The for loop sets a number of variables available within the loop:
|
The for loop sets a number of variables available within the loop:
|
||||||
|
|
||||||
========================== ================================================
|
========================== ================================================
|
||||||
@ -552,18 +575,23 @@ def do_for(parser, token):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
bits = token.contents.split()
|
bits = token.contents.split()
|
||||||
if len(bits) == 5 and bits[4] != 'reversed':
|
if len(bits) < 4:
|
||||||
raise TemplateSyntaxError, "'for' statements with five words should end in 'reversed': %s" % token.contents
|
raise TemplateSyntaxError, "'for' statements should have at least four words: %s" % token.contents
|
||||||
if len(bits) not in (4, 5):
|
|
||||||
raise TemplateSyntaxError, "'for' statements should have either four or five words: %s" % token.contents
|
reversed = bits[-1] == 'reversed'
|
||||||
if bits[2] != 'in':
|
in_index = reversed and -3 or -2
|
||||||
raise TemplateSyntaxError, "'for' statement must contain 'in' as the second word: %s" % token.contents
|
if bits[in_index] != 'in':
|
||||||
loopvar = bits[1]
|
raise TemplateSyntaxError, "'for' statements should use the format 'for x in y': %s" % token.contents
|
||||||
sequence = parser.compile_filter(bits[3])
|
|
||||||
reversed = (len(bits) == 5)
|
loopvars = re.sub(r' *, *', ',', ' '.join(bits[1:in_index])).split(',')
|
||||||
|
for var in loopvars:
|
||||||
|
if not var or ' ' in var:
|
||||||
|
raise TemplateSyntaxError, "'for' tag received an invalid argument: %s" % token.contents
|
||||||
|
|
||||||
|
sequence = parser.compile_filter(bits[in_index+1])
|
||||||
nodelist_loop = parser.parse(('endfor',))
|
nodelist_loop = parser.parse(('endfor',))
|
||||||
parser.delete_first_token()
|
parser.delete_first_token()
|
||||||
return ForNode(loopvar, sequence, reversed, nodelist_loop)
|
return ForNode(loopvars, sequence, reversed, nodelist_loop)
|
||||||
do_for = register.tag("for", do_for)
|
do_for = register.tag("for", do_for)
|
||||||
|
|
||||||
def do_ifequal(parser, token, negate):
|
def do_ifequal(parser, token, negate):
|
||||||
|
@ -2,7 +2,7 @@ from django.conf import settings
|
|||||||
from django.template import Template, Context, TemplateDoesNotExist
|
from django.template import Template, Context, TemplateDoesNotExist
|
||||||
from django.utils.html import escape
|
from django.utils.html import escape
|
||||||
from django.http import HttpResponseServerError, HttpResponseNotFound
|
from django.http import HttpResponseServerError, HttpResponseNotFound
|
||||||
import os, re
|
import os, re, sys
|
||||||
|
|
||||||
HIDDEN_SETTINGS = re.compile('SECRET|PASSWORD|PROFANITIES_LIST')
|
HIDDEN_SETTINGS = re.compile('SECRET|PASSWORD|PROFANITIES_LIST')
|
||||||
|
|
||||||
@ -131,6 +131,8 @@ def technical_500_response(request, exc_type, exc_value, tb):
|
|||||||
'request': request,
|
'request': request,
|
||||||
'request_protocol': request.is_secure() and "https" or "http",
|
'request_protocol': request.is_secure() and "https" or "http",
|
||||||
'settings': get_safe_settings(),
|
'settings': get_safe_settings(),
|
||||||
|
'sys_executable' : sys.executable,
|
||||||
|
'sys_version_info' : '%d.%d.%d' % sys.version_info[0:3],
|
||||||
'template_info': template_info,
|
'template_info': template_info,
|
||||||
'template_does_not_exist': template_does_not_exist,
|
'template_does_not_exist': template_does_not_exist,
|
||||||
'loader_debug_info': loader_debug_info,
|
'loader_debug_info': loader_debug_info,
|
||||||
@ -334,6 +336,14 @@ TECHNICAL_500_TEMPLATE = """
|
|||||||
<th>Exception Location:</th>
|
<th>Exception Location:</th>
|
||||||
<td>{{ lastframe.filename|escape }} in {{ lastframe.function|escape }}, line {{ lastframe.lineno }}</td>
|
<td>{{ lastframe.filename|escape }} in {{ lastframe.function|escape }}, line {{ lastframe.lineno }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Python Executable:</th>
|
||||||
|
<td>{{ sys_executable|escape }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Python Version:</th>
|
||||||
|
<td>{{ sys_version_info }}</td>
|
||||||
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
{% if template_does_not_exist %}
|
{% if template_does_not_exist %}
|
||||||
|
@ -6,8 +6,9 @@ Django aims to follow Python's `"batteries included" philosophy`_. It ships
|
|||||||
with a variety of extra, optional tools that solve common Web-development
|
with a variety of extra, optional tools that solve common Web-development
|
||||||
problems.
|
problems.
|
||||||
|
|
||||||
This code lives in ``django/contrib`` in the Django distribution. Here's a
|
This code lives in ``django/contrib`` in the Django distribution. This document
|
||||||
rundown of the packages in ``contrib``:
|
gives a rundown of the packages in ``contrib``, along with any dependencies
|
||||||
|
those packages have.
|
||||||
|
|
||||||
.. admonition:: Note
|
.. admonition:: Note
|
||||||
|
|
||||||
@ -26,6 +27,8 @@ The automatic Django administrative interface. For more information, see
|
|||||||
|
|
||||||
.. _Tutorial 2: ../tutorial02/
|
.. _Tutorial 2: ../tutorial02/
|
||||||
|
|
||||||
|
Requires the auth_ and contenttypes_ contrib packages to be installed.
|
||||||
|
|
||||||
auth
|
auth
|
||||||
====
|
====
|
||||||
|
|
||||||
@ -144,6 +147,8 @@ See the `flatpages documentation`_.
|
|||||||
|
|
||||||
.. _flatpages documentation: ../flatpages/
|
.. _flatpages documentation: ../flatpages/
|
||||||
|
|
||||||
|
Requires the sites_ contrib package to be installed as well.
|
||||||
|
|
||||||
localflavor
|
localflavor
|
||||||
===========
|
===========
|
||||||
|
|
||||||
|
@ -730,7 +730,7 @@ Django developers are currently discussing.
|
|||||||
Default permissions
|
Default permissions
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
Three basic permissions -- add, create and delete -- are automatically created
|
Three basic permissions -- add, change and delete -- are automatically created
|
||||||
for each Django model that has a ``class Admin`` set. Behind the scenes, these
|
for each Django model that has a ``class Admin`` set. Behind the scenes, these
|
||||||
permissions are added to the ``auth_permission`` database table when you run
|
permissions are added to the ``auth_permission`` database table when you run
|
||||||
``manage.py syncdb``.
|
``manage.py syncdb``.
|
||||||
|
@ -134,6 +134,15 @@ the database until you explicitly call ``save()``.
|
|||||||
|
|
||||||
The ``save()`` method has no return value.
|
The ``save()`` method has no return value.
|
||||||
|
|
||||||
|
Updating ``ForeignKey`` fields works exactly the same way; simply assign an
|
||||||
|
object of the right type to the field in question::
|
||||||
|
|
||||||
|
joe = Author.objects.create(name="Joe")
|
||||||
|
entry.author = joe
|
||||||
|
entry.save()
|
||||||
|
|
||||||
|
Django will complain if you try to assign an object of the wrong type.
|
||||||
|
|
||||||
How Django knows to UPDATE vs. INSERT
|
How Django knows to UPDATE vs. INSERT
|
||||||
-------------------------------------
|
-------------------------------------
|
||||||
|
|
||||||
@ -379,7 +388,7 @@ The lookup parameters (``**kwargs``) should be in the format described in
|
|||||||
`Field lookups`_ below. Multiple parameters are joined via ``AND`` in the
|
`Field lookups`_ below. Multiple parameters are joined via ``AND`` in the
|
||||||
underlying SQL statement, and the whole thing is enclosed in a ``NOT()``.
|
underlying SQL statement, and the whole thing is enclosed in a ``NOT()``.
|
||||||
|
|
||||||
This example excludes all entries whose ``pub_date`` is the current date/time
|
This example excludes all entries whose ``pub_date`` is later than 2005-1-3
|
||||||
AND whose ``headline`` is "Hello"::
|
AND whose ``headline`` is "Hello"::
|
||||||
|
|
||||||
Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3), headline='Hello')
|
Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3), headline='Hello')
|
||||||
@ -389,8 +398,8 @@ In SQL terms, that evaluates to::
|
|||||||
SELECT ...
|
SELECT ...
|
||||||
WHERE NOT (pub_date > '2005-1-3' AND headline = 'Hello')
|
WHERE NOT (pub_date > '2005-1-3' AND headline = 'Hello')
|
||||||
|
|
||||||
This example excludes all entries whose ``pub_date`` is the current date/time
|
This example excludes all entries whose ``pub_date`` is later than 2005-1-3
|
||||||
OR whose ``headline`` is "Hello"::
|
AND whose headline is NOT "Hello"::
|
||||||
|
|
||||||
Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3)).exclude(headline='Hello')
|
Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3)).exclude(headline='Hello')
|
||||||
|
|
||||||
@ -1229,8 +1238,8 @@ whose ``headline`` contains ``'Lennon'``::
|
|||||||
|
|
||||||
Blog.objects.filter(entry__headline__contains='Lennon')
|
Blog.objects.filter(entry__headline__contains='Lennon')
|
||||||
|
|
||||||
Escaping parenthesis and underscores in LIKE statements
|
Escaping percent signs and underscores in LIKE statements
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
The field lookups that equate to ``LIKE`` SQL statements (``iexact``,
|
The field lookups that equate to ``LIKE`` SQL statements (``iexact``,
|
||||||
``contains``, ``icontains``, ``startswith``, ``istartswith``, ``endswith``
|
``contains``, ``icontains``, ``startswith``, ``istartswith``, ``endswith``
|
||||||
|
@ -203,7 +203,7 @@ This is probably the most common case, if you're using Django's admin site::
|
|||||||
DocumentRoot /home/user/public_html
|
DocumentRoot /home/user/public_html
|
||||||
Alias /media /home/user/python/django/contrib/admin/media
|
Alias /media /home/user/python/django/contrib/admin/media
|
||||||
RewriteEngine On
|
RewriteEngine On
|
||||||
RewriteRule ^/(media.*)$ /$1 [QSA,L]
|
RewriteRule ^/(media.*)$ /$1 [QSA,L,PT]
|
||||||
RewriteCond %{REQUEST_FILENAME} !-f
|
RewriteCond %{REQUEST_FILENAME} !-f
|
||||||
RewriteRule ^/(.*)$ /mysite.fcgi/$1 [QSA,L]
|
RewriteRule ^/(.*)$ /mysite.fcgi/$1 [QSA,L]
|
||||||
</VirtualHost>
|
</VirtualHost>
|
||||||
|
162
docs/man/django-admin.1
Normal file
162
docs/man/django-admin.1
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
.TH "django-admin.py" "1" "June 2007" "Django Project" ""
|
||||||
|
.SH "NAME"
|
||||||
|
django\-admin.py \- Utility script for the Django web framework
|
||||||
|
.SH "SYNOPSIS"
|
||||||
|
.B django\-admin.py
|
||||||
|
.I <action>
|
||||||
|
.B [options]
|
||||||
|
.sp
|
||||||
|
.SH "DESCRIPTION"
|
||||||
|
This utility script provides commands for creation and maintenance of Django
|
||||||
|
projects and apps.
|
||||||
|
.sp
|
||||||
|
With the exception of
|
||||||
|
.BI startproject,
|
||||||
|
all commands listed below can also be performed with the
|
||||||
|
.BI manage.py
|
||||||
|
script found at the top level of each Django project directory.
|
||||||
|
.sp
|
||||||
|
.SH "ACTIONS"
|
||||||
|
.TP
|
||||||
|
.BI "adminindex [" "appname ..." "]"
|
||||||
|
Prints the admin\-index template snippet for the given app name(s).
|
||||||
|
.TP
|
||||||
|
.BI "createcachetable [" "tablename" "]"
|
||||||
|
Creates the table needed to use the SQL cache backend
|
||||||
|
.TP
|
||||||
|
.B dbshell
|
||||||
|
Runs the command\-line client for the current
|
||||||
|
.BI DATABASE_ENGINE.
|
||||||
|
.TP
|
||||||
|
.B diffsettings
|
||||||
|
Displays differences between the current
|
||||||
|
.B settings.py
|
||||||
|
and Django's default settings. Settings that don't appear in the defaults are
|
||||||
|
followed by "###".
|
||||||
|
.TP
|
||||||
|
.B inspectdb
|
||||||
|
Introspects the database tables in the database specified in settings.py and outputs a Django
|
||||||
|
model module.
|
||||||
|
.TP
|
||||||
|
.BI "install [" "appname ..." "]"
|
||||||
|
Executes
|
||||||
|
.B sqlall
|
||||||
|
for the given app(s) in the current database.
|
||||||
|
.TP
|
||||||
|
.BI "reset [" "appname ..." "]"
|
||||||
|
Executes
|
||||||
|
.B sqlreset
|
||||||
|
for the given app(s) in the current database.
|
||||||
|
.TP
|
||||||
|
.BI "runfcgi [" "KEY=val" "] [" "KEY=val" "] " "..."
|
||||||
|
Runs this project as a FastCGI application. Requires flup. Use
|
||||||
|
.B runfcgi help
|
||||||
|
for help on the KEY=val pairs.
|
||||||
|
.TP
|
||||||
|
.BI "runserver [" "\-\-noreload" "] [" "\-\-adminmedia=ADMIN_MEDIA_PATH" "] [" "port|ipaddr:port" "]"
|
||||||
|
Starts a lightweight Web server for development.
|
||||||
|
.TP
|
||||||
|
.BI "shell [" "\-\-plain" "]"
|
||||||
|
Runs a Python interactive interpreter. Tries to use IPython, if it's available.
|
||||||
|
The
|
||||||
|
.BI \-\-plain
|
||||||
|
option forces the use of the standard Python interpreter even when IPython is
|
||||||
|
installed.
|
||||||
|
.TP
|
||||||
|
.BI "sql [" "appname ..." "]"
|
||||||
|
Prints the CREATE TABLE SQL statements for the given app name(s).
|
||||||
|
.TP
|
||||||
|
.BI "sqlall [" "appname ..." "]"
|
||||||
|
Prints the CREATE TABLE, initial\-data and CREATE INDEX SQL statements for the
|
||||||
|
given model module name(s).
|
||||||
|
.TP
|
||||||
|
.BI "sqlclear [" "appname ..." "]"
|
||||||
|
Prints the DROP TABLE SQL statements for the given app name(s).
|
||||||
|
.TP
|
||||||
|
.BI "sqlindexes [" "appname ..." "]"
|
||||||
|
Prints the CREATE INDEX SQL statements for the given model module name(s).
|
||||||
|
.TP
|
||||||
|
.BI "sqlinitialdata [" "appname ..." "]"
|
||||||
|
Prints the initial INSERT SQL statements for the given app name(s).
|
||||||
|
.TP
|
||||||
|
.BI "sqlreset [" "appname ..." "]"
|
||||||
|
Prints the DROP TABLE SQL, then the CREATE TABLE SQL, for the given app
|
||||||
|
name(s).
|
||||||
|
.TP
|
||||||
|
.BI "sqlsequencereset [" "appname ..." "]"
|
||||||
|
Prints the SQL statements for resetting PostgreSQL sequences for the
|
||||||
|
given app name(s).
|
||||||
|
.TP
|
||||||
|
.BI "startapp [" "appname" "]"
|
||||||
|
Creates a Django app directory structure for the given app name in
|
||||||
|
the current directory.
|
||||||
|
.TP
|
||||||
|
.BI "startproject [" "projectname" "]"
|
||||||
|
Creates a Django project directory structure for the given project name
|
||||||
|
in the current directory.
|
||||||
|
.TP
|
||||||
|
.BI syncdb
|
||||||
|
Creates the database tables for all apps in INSTALLED_APPS whose tables
|
||||||
|
haven't already been created.
|
||||||
|
.TP
|
||||||
|
.BI "test [" "\-\-verbosity" "] [" "appname ..." "]"
|
||||||
|
Runs the test suite for the specified applications, or the entire project if
|
||||||
|
no apps are specified
|
||||||
|
.TP
|
||||||
|
.BI validate
|
||||||
|
Validates all installed models.
|
||||||
|
.SH "OPTIONS"
|
||||||
|
.TP
|
||||||
|
.I \-\-version
|
||||||
|
Show program's version number and exit.
|
||||||
|
.TP
|
||||||
|
.I \-h, \-\-help
|
||||||
|
Show this help message and exit.
|
||||||
|
.TP
|
||||||
|
.I \-\-settings=SETTINGS
|
||||||
|
Python path to settings module, e.g. "myproject.settings.main". If
|
||||||
|
this isn't provided, the DJANGO_SETTINGS_MODULE environment variable
|
||||||
|
will be used.
|
||||||
|
.TP
|
||||||
|
.I \-\-pythonpath=PYTHONPATH
|
||||||
|
Lets you manually add a directory the Python path,
|
||||||
|
e.g. "/home/djangoprojects/myproject".
|
||||||
|
.TP
|
||||||
|
.I \-\-plain
|
||||||
|
Use plain Python, not IPython, for the "shell" command.
|
||||||
|
.TP
|
||||||
|
.I \-\-noinput
|
||||||
|
Do not prompt the user for input.
|
||||||
|
.TP
|
||||||
|
.I \-\-noreload
|
||||||
|
Disable the development server's auto\-reloader.
|
||||||
|
.TP
|
||||||
|
.I \-\-verbosity=VERBOSITY
|
||||||
|
Verbosity level: 0=minimal output, 1=normal output, 2=all output.
|
||||||
|
.TP
|
||||||
|
.I \-\-adminmedia=ADMIN_MEDIA_PATH
|
||||||
|
Specifies the directory from which to serve admin media when using the development server.
|
||||||
|
|
||||||
|
.SH "ENVIRONMENT"
|
||||||
|
.TP
|
||||||
|
.I DJANGO_SETTINGS_MODULE
|
||||||
|
In the absence of the
|
||||||
|
.BI \-\-settings
|
||||||
|
option, this environment variable defines the settings module to be read.
|
||||||
|
It should be in Python-import form, e.g. "myproject.settings".
|
||||||
|
|
||||||
|
.SH "SEE ALSO"
|
||||||
|
Full descriptions of all these options, with examples, as well as documentation
|
||||||
|
for the rest of the Django framework, can be found on the Django site:
|
||||||
|
.sp
|
||||||
|
.I http://www.djangoproject.com/documentation/
|
||||||
|
.sp
|
||||||
|
or in the distributed documentation.
|
||||||
|
.SH "AUTHORS/CREDITS"
|
||||||
|
Originally developed at World Online in Lawrence, Kansas, USA. Refer to the
|
||||||
|
AUTHORS file in the Django distribution for contributors.
|
||||||
|
.sp
|
||||||
|
.SH "LICENSE"
|
||||||
|
New BSD license. For the full license text refer to the LICENSE file in the
|
||||||
|
Django distribution.
|
||||||
|
|
@ -447,6 +447,11 @@ and doesn't give a 404 response).
|
|||||||
|
|
||||||
The admin represents this as an ``<input type="text">`` (a single-line input).
|
The admin represents this as an ``<input type="text">`` (a single-line input).
|
||||||
|
|
||||||
|
``URLField`` takes an optional argument, ``maxlength``, the maximum length (in
|
||||||
|
characters) of the field. The maxlength is enforced at the database level and
|
||||||
|
in Django's validation. If you don't specify ``maxlength``, a default of 200
|
||||||
|
is used.
|
||||||
|
|
||||||
``USStateField``
|
``USStateField``
|
||||||
~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
@ -1877,14 +1882,15 @@ rows. Example::
|
|||||||
row = cursor.fetchone()
|
row = cursor.fetchone()
|
||||||
return row
|
return row
|
||||||
|
|
||||||
``connection`` and ``cursor`` simply use the standard `Python DB-API`_. If
|
``connection`` and ``cursor`` mostly implement the standard `Python DB-API`_
|
||||||
you're not familiar with the Python DB-API, note that the SQL statement in
|
(except when it comes to `transaction handling`_). If you're not familiar with
|
||||||
``cursor.execute()`` uses placeholders, ``"%s"``, rather than adding parameters
|
the Python DB-API, note that the SQL statement in ``cursor.execute()`` uses
|
||||||
directly within the SQL. If you use this technique, the underlying database
|
placeholders, ``"%s"``, rather than adding parameters directly within the SQL.
|
||||||
library will automatically add quotes and escaping to your parameter(s) as
|
If you use this technique, the underlying database library will automatically
|
||||||
necessary. (Also note that Django expects the ``"%s"`` placeholder, *not* the
|
add quotes and escaping to your parameter(s) as necessary. (Also note that
|
||||||
``"?"`` placeholder, which is used by the SQLite Python bindings. This is for
|
Django expects the ``"%s"`` placeholder, *not* the ``"?"`` placeholder, which is
|
||||||
the sake of consistency and sanity.)
|
used by the SQLite Python bindings. This is for the sake of consistency and
|
||||||
|
sanity.)
|
||||||
|
|
||||||
A final note: If all you want to do is a custom ``WHERE`` clause, you can just
|
A final note: If all you want to do is a custom ``WHERE`` clause, you can just
|
||||||
just the ``where``, ``tables`` and ``params`` arguments to the standard lookup
|
just the ``where``, ``tables`` and ``params`` arguments to the standard lookup
|
||||||
@ -1892,6 +1898,7 @@ API. See `Other lookup options`_.
|
|||||||
|
|
||||||
.. _Python DB-API: http://www.python.org/peps/pep-0249.html
|
.. _Python DB-API: http://www.python.org/peps/pep-0249.html
|
||||||
.. _Other lookup options: ../db-api/#extra-params-select-where-tables
|
.. _Other lookup options: ../db-api/#extra-params-select-where-tables
|
||||||
|
.. _transaction handling: ../transactions/
|
||||||
|
|
||||||
Overriding default model methods
|
Overriding default model methods
|
||||||
--------------------------------
|
--------------------------------
|
||||||
|
@ -51,9 +51,17 @@ whereas ``<Location>`` points at places in the URL structure of a Web site.
|
|||||||
``<Directory>`` would be meaningless here.
|
``<Directory>`` would be meaningless here.
|
||||||
|
|
||||||
Also, if you've manually altered your ``PYTHONPATH`` to put your Django project
|
Also, if you've manually altered your ``PYTHONPATH`` to put your Django project
|
||||||
on it, you'll need to tell mod_python::
|
on it, you'll need to tell mod_python:
|
||||||
|
|
||||||
PythonPath "['/path/to/project'] + sys.path"
|
.. parsed-literal::
|
||||||
|
|
||||||
|
<Location "/mysite/">
|
||||||
|
SetHandler python-program
|
||||||
|
PythonHandler django.core.handlers.modpython
|
||||||
|
SetEnv DJANGO_SETTINGS_MODULE mysite.settings
|
||||||
|
PythonDebug On
|
||||||
|
**PythonPath "['/path/to/project'] + sys.path"**
|
||||||
|
</Location>
|
||||||
|
|
||||||
.. caution::
|
.. caution::
|
||||||
|
|
||||||
|
@ -299,12 +299,19 @@ required. In this example, the data dictionary doesn't include a value for the
|
|||||||
In this above example, the ``cleaned_data`` value for ``nick_name`` is set to an
|
In this above example, the ``cleaned_data`` value for ``nick_name`` is set to an
|
||||||
empty string, because ``nick_name`` is ``CharField``, and ``CharField``\s treat
|
empty string, because ``nick_name`` is ``CharField``, and ``CharField``\s treat
|
||||||
empty values as an empty string. Each field type knows what its "blank" value
|
empty values as an empty string. Each field type knows what its "blank" value
|
||||||
is -- e.g., for ``DateField``, it's ``None`` instead of the empty string.
|
is -- e.g., for ``DateField``, it's ``None`` instead of the empty string. For
|
||||||
|
full details on each field's behavior in this case, see the "Empty value" note
|
||||||
|
for each field in the "Built-in ``Field`` classes" section below.
|
||||||
|
|
||||||
|
You can write code to perform validation for particular form fields (based on
|
||||||
|
their name) or for the form as a whole (considering combinations of various
|
||||||
|
fields). More information about this is in the `Custom form and field
|
||||||
|
validation`_ section, below.
|
||||||
|
|
||||||
Behavior of unbound forms
|
Behavior of unbound forms
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
It's meaningless to request "clean" data in a form with no data, but, for the
|
It's meaningless to request "cleaned" data in a form with no data, but, for the
|
||||||
record, here's what happens with unbound forms::
|
record, here's what happens with unbound forms::
|
||||||
|
|
||||||
>>> f = ContactForm()
|
>>> f = ContactForm()
|
||||||
@ -606,8 +613,13 @@ Using forms in views and templates
|
|||||||
----------------------------------
|
----------------------------------
|
||||||
|
|
||||||
Let's put this all together and use the ``ContactForm`` example in a Django
|
Let's put this all together and use the ``ContactForm`` example in a Django
|
||||||
view and template. This example view displays the contact form by default and
|
view and template.
|
||||||
validates/processes it if accessed via a POST request::
|
|
||||||
|
Simple view example
|
||||||
|
~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
This example view displays the contact form by default and validates/processes
|
||||||
|
it if accessed via a POST request::
|
||||||
|
|
||||||
def contact(request):
|
def contact(request):
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
@ -619,12 +631,12 @@ validates/processes it if accessed via a POST request::
|
|||||||
form = ContactForm()
|
form = ContactForm()
|
||||||
return render_to_response('contact.html', {'form': form})
|
return render_to_response('contact.html', {'form': form})
|
||||||
|
|
||||||
Simple template output
|
Simple template example
|
||||||
~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
The template, ``contact.html``, is responsible for displaying the form as HTML.
|
The template in the above view example, ``contact.html``, is responsible for
|
||||||
To do this, we can use the techniques outlined in the "Outputting forms as HTML"
|
displaying the form as HTML. To do this, we can use the techniques outlined in
|
||||||
section above.
|
the "Outputting forms as HTML" section above.
|
||||||
|
|
||||||
The simplest way to display a form's HTML is to use the variable on its own,
|
The simplest way to display a form's HTML is to use the variable on its own,
|
||||||
like this::
|
like this::
|
||||||
@ -677,7 +689,7 @@ The easiest way is to iterate over the form's fields, with
|
|||||||
|
|
||||||
This iteration technique is useful if you want to apply the same HTML
|
This iteration technique is useful if you want to apply the same HTML
|
||||||
formatting to each field, or if you don't know the names of the form fields
|
formatting to each field, or if you don't know the names of the form fields
|
||||||
ahead of time. Note that the fields will be listed in the order in which
|
ahead of time. Note that the fields will be iterated over in the order in which
|
||||||
they're defined in the ``Form`` class.
|
they're defined in the ``Form`` class.
|
||||||
|
|
||||||
Alternatively, you can arrange the form's fields explicitly, by name. Do that
|
Alternatively, you can arrange the form's fields explicitly, by name. Do that
|
||||||
@ -701,7 +713,10 @@ For example::
|
|||||||
Subclassing forms
|
Subclassing forms
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
If you subclass a custom ``Form`` class, the resulting ``Form`` class will
|
If you have multiple ``Form`` classes that share fields, you can use
|
||||||
|
subclassing to remove redundancy.
|
||||||
|
|
||||||
|
When you subclass a custom ``Form`` class, the resulting subclass will
|
||||||
include all fields of the parent class(es), followed by the fields you define
|
include all fields of the parent class(es), followed by the fields you define
|
||||||
in the subclass.
|
in the subclass.
|
||||||
|
|
||||||
@ -1202,6 +1217,114 @@ custom ``Field`` classes. To do this, just create a subclass of
|
|||||||
mentioned above (``required``, ``label``, ``initial``, ``widget``,
|
mentioned above (``required``, ``label``, ``initial``, ``widget``,
|
||||||
``help_text``).
|
``help_text``).
|
||||||
|
|
||||||
|
Custom form and field validation
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
Form validation happens when the data is cleaned. If you want to customise
|
||||||
|
this process, there are various places you can change, each one serving a
|
||||||
|
different purpose. Thee types of cleaning methods are run during form
|
||||||
|
processing. These are normally executed when you call the ``is_valid()``
|
||||||
|
method on a form. There are other things that can kick of cleaning and
|
||||||
|
validation (accessing the ``errors`` attribute or calling ``full_clean()``
|
||||||
|
directly), but normally they won't be needed.
|
||||||
|
|
||||||
|
In general, any cleaning method can raise ``ValidationError`` if there is a
|
||||||
|
problem with the data it is processing, passing the relevant error message to
|
||||||
|
the ``ValidationError`` constructor. If no ``ValidationError`` is raised, the
|
||||||
|
method should return the cleaned (normalised) data as a Python object.
|
||||||
|
|
||||||
|
If you detect multiple errors during a cleaning method and wish to signal all
|
||||||
|
of them to the form submittor, it is possible to pass a list of errors to the
|
||||||
|
``ValidationError`` constructor.
|
||||||
|
|
||||||
|
The three types of cleaning methods are:
|
||||||
|
|
||||||
|
* The ``clean()`` method on a Field subclass. This is responsible
|
||||||
|
for cleaning the data in a way that is generic for that type of field.
|
||||||
|
For example, a FloatField will turn the data into a Python ``float`` or
|
||||||
|
raise a ``ValidationError``.
|
||||||
|
|
||||||
|
* The ``clean_<fieldname>()`` method in a form subclass -- where
|
||||||
|
``<fieldname>`` is replaced with the name of the form field attribute.
|
||||||
|
This method does any cleaning that is specific to that particular
|
||||||
|
attribute, unrelated to the type of field that it is. This method is not
|
||||||
|
passed any parameters. You will need to look up the value of the field
|
||||||
|
in ``self.cleaned_data`` and remember that it will be a Python object
|
||||||
|
at this point, not the original string submitted in the form (it will be
|
||||||
|
in ``cleaned_data`` because the general field ``clean()`` method, above,
|
||||||
|
has already cleaned the data once).
|
||||||
|
|
||||||
|
For example, if you wanted to validate that the contents of a
|
||||||
|
``CharField`` called ``serialnumber`` was unique,
|
||||||
|
``clean_serialnumber()`` would be the right place to do this. You don't
|
||||||
|
need a specific field (it's just a ``CharField``), but you want a
|
||||||
|
formfield-specific piece of validation and, possibly,
|
||||||
|
cleaning/normalizing the data.
|
||||||
|
|
||||||
|
* The Form subclass's ``clean()`` method. This method can perform
|
||||||
|
any validation that requires access to multiple fields from the form at
|
||||||
|
once. This is where you might put in things to check that if field ``A``
|
||||||
|
is supplied, field ``B`` must contain a valid email address and the
|
||||||
|
like. The data that this method returns is the final ``cleaned_data``
|
||||||
|
attribute for the form, so don't forget to return the full list of
|
||||||
|
cleaned data if you override this method (by default, ``Form.clean()``
|
||||||
|
just returns ``self.cleaned_data``).
|
||||||
|
|
||||||
|
Note that any errors raised by your ``Form.clean()`` override will not
|
||||||
|
be associated with any field in particular. They go into a special
|
||||||
|
"field" (called ``__all__``, which you can access via the
|
||||||
|
``non_field_errors()`` method if you need to.
|
||||||
|
|
||||||
|
These methods are run in the order given above, one field at a time. That is,
|
||||||
|
for each field in the form (in the order they are declared in the form
|
||||||
|
definition), the ``Field.clean()`` method (or it's override) is run, then
|
||||||
|
``clean_<fieldname>()``. Finally, once those two methods are run for every
|
||||||
|
field, the ``Form.clean()`` method, or it's override, is executed.
|
||||||
|
|
||||||
|
As mentioned above, any of these methods can raise a ``ValidationError``. For
|
||||||
|
any field, if the ``Field.clean()`` method raises a ``ValidationError``, any
|
||||||
|
field-specific cleaning method is not called. However, the cleaning methods
|
||||||
|
for all remaining fields are still executed.
|
||||||
|
|
||||||
|
The ``clean()`` method for the ``Form`` class or subclass is always run. If
|
||||||
|
that method raises a ``ValidationError``, ``cleaned_data`` will be an empty
|
||||||
|
dictionary.
|
||||||
|
|
||||||
|
The previous paragraph means that if you are overriding ``Form.clean()``, you
|
||||||
|
should iterate through ``self.cleaned_data.items()``, possibly considering the
|
||||||
|
``_errors`` dictionary attribute on the form as well. In this way, you will
|
||||||
|
already know which fields have passed thei individual validation requirements.
|
||||||
|
|
||||||
|
A simple example
|
||||||
|
~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Here's a simple example of a custom field that validates its input is a string
|
||||||
|
containing comma-separated e-mail addresses, with at least one address. We'll
|
||||||
|
keep it simple and assume e-mail validation is contained in a function called
|
||||||
|
``is_valid_email()``. The full class::
|
||||||
|
|
||||||
|
from django import newforms as forms
|
||||||
|
|
||||||
|
class MultiEmailField(forms.Field):
|
||||||
|
def clean(self, value):
|
||||||
|
emails = value.split(',')
|
||||||
|
for email in emails:
|
||||||
|
if not is_valid_email(email):
|
||||||
|
raise forms.ValidationError('%s is not a valid e-mail address.' % email)
|
||||||
|
if not emails:
|
||||||
|
raise forms.ValidationError('Enter at least one e-mail address.')
|
||||||
|
return emails
|
||||||
|
|
||||||
|
Let's alter the ongoing ``ContactForm`` example to demonstrate how you'd use
|
||||||
|
this in a form. Simply use ``MultiEmailField`` instead of ``forms.EmailField``,
|
||||||
|
like so::
|
||||||
|
|
||||||
|
class ContactForm(forms.Form):
|
||||||
|
subject = forms.CharField(max_length=100)
|
||||||
|
message = forms.CharField()
|
||||||
|
senders = MultiEmailField()
|
||||||
|
cc_myself = forms.BooleanField()
|
||||||
|
|
||||||
Generating forms for models
|
Generating forms for models
|
||||||
===========================
|
===========================
|
||||||
|
|
||||||
|
@ -91,9 +91,12 @@ Filters can be "chained." The output of one filter is applied to the next.
|
|||||||
``{{ text|escape|linebreaks }}`` is a common idiom for escaping text contents,
|
``{{ text|escape|linebreaks }}`` is a common idiom for escaping text contents,
|
||||||
then converting line breaks to ``<p>`` tags.
|
then converting line breaks to ``<p>`` tags.
|
||||||
|
|
||||||
Some filters take arguments. A filter argument looks like this:
|
Some filters take arguments. A filter argument looks like this: ``{{
|
||||||
``{{ bio|truncatewords:"30" }}``. This will display the first 30 words of the
|
bio|truncatewords:30 }}``. This will display the first 30 words of the ``bio``
|
||||||
``bio`` variable. Filter arguments always are in double quotes.
|
variable.
|
||||||
|
|
||||||
|
Filter arguments that contain spaces must be quoted; for example, to join a list
|
||||||
|
with commas and spaced you'd use ``{{ list|join:", " }}``.
|
||||||
|
|
||||||
The `Built-in filter reference`_ below describes all the built-in filters.
|
The `Built-in filter reference`_ below describes all the built-in filters.
|
||||||
|
|
||||||
@ -444,7 +447,7 @@ for
|
|||||||
~~~
|
~~~
|
||||||
|
|
||||||
Loop over each item in an array. For example, to display a list of athletes
|
Loop over each item in an array. For example, to display a list of athletes
|
||||||
given ``athlete_list``::
|
provided in ``athlete_list``::
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
{% for athlete in athlete_list %}
|
{% for athlete in athlete_list %}
|
||||||
@ -452,7 +455,25 @@ given ``athlete_list``::
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
You can also loop over a list in reverse by using ``{% for obj in list reversed %}``.
|
You can loop over a list in reverse by using ``{% for obj in list reversed %}``.
|
||||||
|
|
||||||
|
**New in Django development version**
|
||||||
|
If you need to loop over a list of lists, you can unpack the values
|
||||||
|
in eachs sub-list into a set of known names. For example, if your context contains
|
||||||
|
a list of (x,y) coordinates called ``points``, you could use the following
|
||||||
|
to output the list of points::
|
||||||
|
|
||||||
|
{% for x, y in points %}
|
||||||
|
There is a point at {{ x }},{{ y }}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
This can also be useful if you need to access the items in a dictionary.
|
||||||
|
For example, if your context contained a dictionary ``data``, the following
|
||||||
|
would display the keys and values of the dictionary::
|
||||||
|
|
||||||
|
{% for key, value in data.items %}
|
||||||
|
{{ key }}: {{ value }}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
The for loop sets a number of variables available within the loop:
|
The for loop sets a number of variables available within the loop:
|
||||||
|
|
||||||
|
@ -21,3 +21,8 @@ done
|
|||||||
# Make sure we match foo.pyo and foo.pyc along with foo.py (but only once each)
|
# Make sure we match foo.pyo and foo.pyc along with foo.py (but only once each)
|
||||||
sed -e "/\.py[co]$/d" -e "s/\.py$/.py*/" DIRS FILES >INSTALLED_FILES
|
sed -e "/\.py[co]$/d" -e "s/\.py$/.py*/" DIRS FILES >INSTALLED_FILES
|
||||||
|
|
||||||
|
mkdir -p ${RPM_BUILD_ROOT}/%{_mandir}/man1/
|
||||||
|
cp docs/man/* ${RPM_BUILD_ROOT}/%{_mandir}/man1/
|
||||||
|
cat << EOF >> INSTALLED_FILES
|
||||||
|
%doc %{_mandir}/man1/*"
|
||||||
|
EOF
|
||||||
|
@ -327,10 +327,11 @@ def streamTest(format, self):
|
|||||||
string_data = serializers.serialize(format, [obj], indent=2)
|
string_data = serializers.serialize(format, [obj], indent=2)
|
||||||
|
|
||||||
# Check that the two are the same
|
# Check that the two are the same
|
||||||
self.assertEqual(string_data, stream.buffer())
|
self.assertEqual(string_data, stream.getvalue())
|
||||||
stream.close()
|
stream.close()
|
||||||
|
|
||||||
for format in serializers.get_serializer_formats():
|
for format in serializers.get_serializer_formats():
|
||||||
setattr(SerializerTests, 'test_'+format+'_serializer', curry(serializerTest, format))
|
setattr(SerializerTests, 'test_'+format+'_serializer', curry(serializerTest, format))
|
||||||
setattr(SerializerTests, 'test_'+format+'_serializer_fields', curry(fieldsTest, format))
|
setattr(SerializerTests, 'test_'+format+'_serializer_fields', curry(fieldsTest, format))
|
||||||
setattr(SerializerTests, 'test_'+format+'_serializer_stream', curry(fieldsTest, format))
|
if format != 'python':
|
||||||
|
setattr(SerializerTests, 'test_'+format+'_serializer_stream', curry(streamTest, format))
|
||||||
|
@ -289,6 +289,20 @@ class Templates(unittest.TestCase):
|
|||||||
'for-tag-vars02': ("{% for val in values %}{{ forloop.counter0 }}{% endfor %}", {"values": [6, 6, 6]}, "012"),
|
'for-tag-vars02': ("{% for val in values %}{{ forloop.counter0 }}{% endfor %}", {"values": [6, 6, 6]}, "012"),
|
||||||
'for-tag-vars03': ("{% for val in values %}{{ forloop.revcounter }}{% endfor %}", {"values": [6, 6, 6]}, "321"),
|
'for-tag-vars03': ("{% for val in values %}{{ forloop.revcounter }}{% endfor %}", {"values": [6, 6, 6]}, "321"),
|
||||||
'for-tag-vars04': ("{% for val in values %}{{ forloop.revcounter0 }}{% endfor %}", {"values": [6, 6, 6]}, "210"),
|
'for-tag-vars04': ("{% for val in values %}{{ forloop.revcounter0 }}{% endfor %}", {"values": [6, 6, 6]}, "210"),
|
||||||
|
'for-tag-unpack01': ("{% for key,value in items %}{{ key }}:{{ value }}/{% endfor %}", {"items": (('one', 1), ('two', 2))}, "one:1/two:2/"),
|
||||||
|
'for-tag-unpack03': ("{% for key, value in items %}{{ key }}:{{ value }}/{% endfor %}", {"items": (('one', 1), ('two', 2))}, "one:1/two:2/"),
|
||||||
|
'for-tag-unpack04': ("{% for key , value in items %}{{ key }}:{{ value }}/{% endfor %}", {"items": (('one', 1), ('two', 2))}, "one:1/two:2/"),
|
||||||
|
'for-tag-unpack05': ("{% for key ,value in items %}{{ key }}:{{ value }}/{% endfor %}", {"items": (('one', 1), ('two', 2))}, "one:1/two:2/"),
|
||||||
|
'for-tag-unpack06': ("{% for key value in items %}{{ key }}:{{ value }}/{% endfor %}", {"items": (('one', 1), ('two', 2))}, template.TemplateSyntaxError),
|
||||||
|
'for-tag-unpack07': ("{% for key,,value in items %}{{ key }}:{{ value }}/{% endfor %}", {"items": (('one', 1), ('two', 2))}, template.TemplateSyntaxError),
|
||||||
|
'for-tag-unpack08': ("{% for key,value, in items %}{{ key }}:{{ value }}/{% endfor %}", {"items": (('one', 1), ('two', 2))}, template.TemplateSyntaxError),
|
||||||
|
# Ensure that a single loopvar doesn't truncate the list in val.
|
||||||
|
'for-tag-unpack09': ("{% for val in items %}{{ val.0 }}:{{ val.1 }}/{% endfor %}", {"items": (('one', 1), ('two', 2))}, "one:1/two:2/"),
|
||||||
|
# Otherwise, silently truncate if the length of loopvars differs to the length of each set of items.
|
||||||
|
'for-tag-unpack10': ("{% for x,y in items %}{{ x }}:{{ y }}/{% endfor %}", {"items": (('one', 1, 'carrot'), ('two', 2, 'orange'))}, "one:1/two:2/"),
|
||||||
|
'for-tag-unpack11': ("{% for x,y,z in items %}{{ x }}:{{ y }},{{ z }}/{% endfor %}", {"items": (('one', 1), ('two', 2))}, ("one:1,/two:2,/", "one:1,INVALID/two:2,INVALID/")),
|
||||||
|
'for-tag-unpack12': ("{% for x,y,z in items %}{{ x }}:{{ y }},{{ z }}/{% endfor %}", {"items": (('one', 1, 'carrot'), ('two', 2))}, ("one:1,carrot/two:2,/", "one:1,carrot/two:2,INVALID/")),
|
||||||
|
'for-tag-unpack13': ("{% for x,y,z in items %}{{ x }}:{{ y }},{{ z }}/{% endfor %}", {"items": (('one', 1, 'carrot'), ('two', 2, 'cheese'))}, ("one:1,carrot/two:2,cheese/", "one:1,carrot/two:2,cheese/")),
|
||||||
|
|
||||||
### IF TAG ################################################################
|
### IF TAG ################################################################
|
||||||
'if-tag01': ("{% if foo %}yes{% else %}no{% endif %}", {"foo": True}, "yes"),
|
'if-tag01': ("{% if foo %}yes{% else %}no{% endif %}", {"foo": True}, "yes"),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user