1
0
mirror of https://github.com/django/django.git synced 2025-07-04 09:49:12 +00:00

i18n: merged up to r868

git-svn-id: http://code.djangoproject.com/svn/django/branches/i18n@869 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Georg Bauer 2005-10-14 21:33:45 +00:00
commit 2a2e2fb6aa
27 changed files with 684 additions and 429 deletions

View File

@ -59,7 +59,8 @@ DATABASE_ENGINE = 'postgresql' # 'postgresql', 'mysql', or 'sqlite3'.
DATABASE_NAME = ''
DATABASE_USER = ''
DATABASE_PASSWORD = ''
DATABASE_HOST = '' # Set to empty string for localhost
DATABASE_HOST = '' # Set to empty string for localhost.
DATABASE_PORT = '' # Set to empty string for default.
# Host for sending e-mail.
EMAIL_HOST = 'localhost'

View File

@ -15,6 +15,7 @@ DATABASE_NAME = '' # Or path to database file if using sqlite3.
DATABASE_USER = '' # Not used with sqlite3.
DATABASE_PASSWORD = '' # Not used with sqlite3.
DATABASE_HOST = '' # Set to empty string for localhost. Not used with sqlite3.
DATABASE_PORT = '' # Set to empty string for default. Not used with sqlite3.
SITE_ID = 1

View File

@ -53,10 +53,18 @@ class DatabaseWrapper:
self.queries = []
def cursor(self):
from django.conf.settings import DATABASE_USER, DATABASE_NAME, DATABASE_HOST, DATABASE_PASSWORD, DEBUG
from django.conf.settings import DATABASE_USER, DATABASE_NAME, DATABASE_HOST, DATABASE_PORT, DATABASE_PASSWORD, DEBUG
if self.connection is None:
self.connection = Database.connect(user=DATABASE_USER, db=DATABASE_NAME,
passwd=DATABASE_PASSWORD, host=DATABASE_HOST, conv=django_conversions)
kwargs = {
'user': DATABASE_USER,
'db': DATABASE_NAME,
'passwd': DATABASE_PASSWORD,
'host': DATABASE_HOST,
'conv': django_conversions,
}
if DATABASE_PORT:
kwargs['port'] = DATABASE_PORT
self.connection = Database.connect(**kwargs)
if DEBUG:
return base.CursorDebugWrapper(MysqlDebugWrapper(self.connection.cursor()), self)
return self.connection.cursor()

View File

@ -15,7 +15,7 @@ class DatabaseWrapper:
self.queries = []
def cursor(self):
from django.conf.settings import DATABASE_USER, DATABASE_NAME, DATABASE_HOST, DATABASE_PASSWORD, DEBUG, TIME_ZONE
from django.conf.settings import DATABASE_USER, DATABASE_NAME, DATABASE_HOST, DATABASE_PORT, DATABASE_PASSWORD, DEBUG, TIME_ZONE
if self.connection is None:
if DATABASE_NAME == '':
from django.core.exceptions import ImproperlyConfigured
@ -27,6 +27,8 @@ class DatabaseWrapper:
conn_string += " password=%s" % DATABASE_PASSWORD
if DATABASE_HOST:
conn_string += " host=%s" % DATABASE_HOST
if DATABASE_PORT:
conn_string += " port=%s" % DATABASE_PORT
self.connection = Database.connect(conn_string)
self.connection.set_isolation_level(1) # make transactions transparent to all cursors
cursor = self.connection.cursor()

View File

@ -2,14 +2,13 @@
# of MVC. In other words, these functions/classes introduce controlled coupling
# for convenience's sake.
from django.core import template_loader
from django.core.exceptions import Http404, ObjectDoesNotExist
from django.core.template import Context
from django.core.template import Context, loader
from django.conf.settings import DEBUG, INTERNAL_IPS
from django.utils.httpwrappers import HttpResponse
def render_to_response(*args, **kwargs):
return HttpResponse(template_loader.render_to_string(*args, **kwargs))
return HttpResponse(loader.render_to_string(*args, **kwargs))
load_and_render = render_to_response # For backwards compatibility.
def get_object_or_404(mod, **kwargs):

View File

@ -1,6 +1,5 @@
from django.core import template_loader
from django.core.exceptions import ObjectDoesNotExist
from django.core.template import Context
from django.core.template import Context, loader
from django.models.core import sites
from django.utils import feedgenerator
from django.conf.settings import LANGUAGE_CODE, SETTINGS_MODULE
@ -64,8 +63,8 @@ class FeedConfiguration:
param = None
current_site = sites.get_current()
f = self._get_feed_generator_object(param)
title_template = template_loader.get_template('rss/%s_title' % self.slug)
description_template = template_loader.get_template('rss/%s_description' % self.slug)
title_template = loader.get_template('rss/%s_title' % self.slug)
description_template = loader.get_template('rss/%s_description' % self.slug)
kwargs = self.get_list_kwargs.copy()
if param and self.get_list_kwargs_cb:
kwargs.update(self.get_list_kwargs_cb(param))

View File

@ -1,6 +1,7 @@
"Default variable filters"
import template, re
from django.core.template import register_filter, resolve_variable
import re
import random as random_module
###################
@ -196,7 +197,7 @@ def dictsort(value, arg):
Takes a list of dicts, returns that list sorted by the property given in
the argument.
"""
decorated = [(template.resolve_variable('var.' + arg, {'var' : item}), item) for item in value]
decorated = [(resolve_variable('var.' + arg, {'var' : item}), item) for item in value]
decorated.sort()
return [item[1] for item in decorated]
@ -205,7 +206,7 @@ def dictsortreversed(value, arg):
Takes a list of dicts, returns that list sorted in reverse order by the
property given in the argument.
"""
decorated = [(template.resolve_variable('var.' + arg, {'var' : item}), item) for item in value]
decorated = [(resolve_variable('var.' + arg, {'var' : item}), item) for item in value]
decorated.sort()
decorated.reverse()
return [item[1] for item in decorated]
@ -333,6 +334,12 @@ def default(value, arg):
"If value is unavailable, use given default"
return value or arg
def default_if_none(value, arg):
"If value is None, use given default"
if value is None:
return arg
return value
def divisibleby(value, arg):
"Returns true if the value is devisible by the argument"
return int(value) % int(arg) == 0
@ -408,51 +415,52 @@ def pprint(value, _):
from pprint import pformat
return pformat(value)
# Syntax: template.register_filter(name of filter, callback, has_argument)
template.register_filter('add', add, True)
template.register_filter('addslashes', addslashes, False)
template.register_filter('capfirst', capfirst, False)
template.register_filter('center', center, True)
template.register_filter('cut', cut, True)
template.register_filter('date', date, True)
template.register_filter('default', default, True)
template.register_filter('dictsort', dictsort, True)
template.register_filter('dictsortreversed', dictsortreversed, True)
template.register_filter('divisibleby', divisibleby, True)
template.register_filter('escape', escape, False)
template.register_filter('filesizeformat', filesizeformat, False)
template.register_filter('first', first, False)
template.register_filter('fix_ampersands', fix_ampersands, False)
template.register_filter('floatformat', floatformat, False)
template.register_filter('get_digit', get_digit, True)
template.register_filter('join', join, True)
template.register_filter('length', length, False)
template.register_filter('length_is', length_is, True)
template.register_filter('linebreaks', linebreaks, False)
template.register_filter('linebreaksbr', linebreaksbr, False)
template.register_filter('linenumbers', linenumbers, False)
template.register_filter('ljust', ljust, True)
template.register_filter('lower', lower, False)
template.register_filter('make_list', make_list, False)
template.register_filter('phone2numeric', phone2numeric, False)
template.register_filter('pluralize', pluralize, False)
template.register_filter('pprint', pprint, False)
template.register_filter('removetags', removetags, True)
template.register_filter('random', random, False)
template.register_filter('rjust', rjust, True)
template.register_filter('slice', slice_, True)
template.register_filter('slugify', slugify, False)
template.register_filter('stringformat', stringformat, True)
template.register_filter('striptags', striptags, False)
template.register_filter('time', time, True)
template.register_filter('timesince', timesince, False)
template.register_filter('title', title, False)
template.register_filter('truncatewords', truncatewords, True)
template.register_filter('unordered_list', unordered_list, False)
template.register_filter('upper', upper, False)
template.register_filter('urlencode', urlencode, False)
template.register_filter('urlize', urlize, False)
template.register_filter('urlizetrunc', urlizetrunc, True)
template.register_filter('wordcount', wordcount, False)
template.register_filter('wordwrap', wordwrap, True)
template.register_filter('yesno', yesno, True)
# Syntax: register_filter(name of filter, callback, has_argument)
register_filter('add', add, True)
register_filter('addslashes', addslashes, False)
register_filter('capfirst', capfirst, False)
register_filter('center', center, True)
register_filter('cut', cut, True)
register_filter('date', date, True)
register_filter('default', default, True)
register_filter('default_if_none', default_if_none, True)
register_filter('dictsort', dictsort, True)
register_filter('dictsortreversed', dictsortreversed, True)
register_filter('divisibleby', divisibleby, True)
register_filter('escape', escape, False)
register_filter('filesizeformat', filesizeformat, False)
register_filter('first', first, False)
register_filter('fix_ampersands', fix_ampersands, False)
register_filter('floatformat', floatformat, False)
register_filter('get_digit', get_digit, True)
register_filter('join', join, True)
register_filter('length', length, False)
register_filter('length_is', length_is, True)
register_filter('linebreaks', linebreaks, False)
register_filter('linebreaksbr', linebreaksbr, False)
register_filter('linenumbers', linenumbers, False)
register_filter('ljust', ljust, True)
register_filter('lower', lower, False)
register_filter('make_list', make_list, False)
register_filter('phone2numeric', phone2numeric, False)
register_filter('pluralize', pluralize, False)
register_filter('pprint', pprint, False)
register_filter('removetags', removetags, True)
register_filter('random', random, False)
register_filter('rjust', rjust, True)
register_filter('slice', slice_, True)
register_filter('slugify', slugify, False)
register_filter('stringformat', stringformat, True)
register_filter('striptags', striptags, False)
register_filter('time', time, True)
register_filter('timesince', timesince, False)
register_filter('title', title, False)
register_filter('truncatewords', truncatewords, True)
register_filter('unordered_list', unordered_list, False)
register_filter('upper', upper, False)
register_filter('urlencode', urlencode, False)
register_filter('urlize', urlize, False)
register_filter('urlizetrunc', urlizetrunc, True)
register_filter('wordcount', wordcount, False)
register_filter('wordwrap', wordwrap, True)
register_filter('yesno', yesno, True)

View File

@ -1,16 +1,14 @@
"Default tags used by the template system, available to all templates."
import re
from django.core.template import Node, NodeList, Template, Context, resolve_variable, resolve_variable_with_filters, get_filters_from_token, registered_filters
from django.core.template import TemplateSyntaxError, VariableDoesNotExist, BLOCK_TAG_START, BLOCK_TAG_END, VARIABLE_TAG_START, VARIABLE_TAG_END, register_tag
import sys
import template
from django.utils import translation
class CommentNode(template.Node):
class CommentNode(Node):
def render(self, context):
return ''
class CycleNode(template.Node):
class CycleNode(Node):
def __init__(self, cyclevars):
self.cyclevars = cyclevars
self.cyclevars_len = len(cyclevars)
@ -20,7 +18,7 @@ class CycleNode(template.Node):
self.counter += 1
return self.cyclevars[self.counter % self.cyclevars_len]
class DebugNode(template.Node):
class DebugNode(Node):
def render(self, context):
from pprint import pformat
output = [pformat(val) for val in context]
@ -28,7 +26,7 @@ class DebugNode(template.Node):
output.append(pformat(sys.modules))
return ''.join(output)
class FilterNode(template.Node):
class FilterNode(Node):
def __init__(self, filters, nodelist):
self.filters, self.nodelist = filters, nodelist
@ -36,21 +34,21 @@ class FilterNode(template.Node):
output = self.nodelist.render(context)
# apply filters
for f in self.filters:
output = template.registered_filters[f[0]][0](output, f[1])
output = registered_filters[f[0]][0](output, f[1])
return output
class FirstOfNode(template.Node):
class FirstOfNode(Node):
def __init__(self, vars):
self.vars = vars
def render(self, context):
for var in self.vars:
value = template.resolve_variable(var, context)
value = resolve_variable(var, context)
if value:
return str(value)
return ''
class ForNode(template.Node):
class ForNode(Node):
def __init__(self, loopvar, sequence, reversed, nodelist_loop):
self.loopvar, self.sequence = loopvar, sequence
self.reversed = reversed
@ -76,15 +74,15 @@ class ForNode(template.Node):
return nodes
def render(self, context):
nodelist = template.NodeList()
nodelist = NodeList()
if context.has_key('forloop'):
parentloop = context['forloop']
else:
parentloop = {}
context.push()
try:
values = template.resolve_variable_with_filters(self.sequence, context)
except template.VariableDoesNotExist:
values = resolve_variable_with_filters(self.sequence, context)
except VariableDoesNotExist:
values = []
if values is None:
values = []
@ -114,7 +112,7 @@ class ForNode(template.Node):
context.pop()
return nodelist.render(context)
class IfChangedNode(template.Node):
class IfChangedNode(Node):
def __init__(self, nodelist):
self.nodelist = nodelist
self._last_seen = None
@ -132,7 +130,7 @@ class IfChangedNode(template.Node):
else:
return ''
class IfEqualNode(template.Node):
class IfEqualNode(Node):
def __init__(self, var1, var2, nodelist_true, nodelist_false, negate):
self.var1, self.var2 = var1, var2
self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false
@ -142,13 +140,13 @@ class IfEqualNode(template.Node):
return "<IfEqualNode>"
def render(self, context):
val1 = template.resolve_variable(self.var1, context)
val2 = template.resolve_variable(self.var2, context)
val1 = resolve_variable(self.var1, context)
val2 = resolve_variable(self.var2, context)
if (self.negate and val1 != val2) or (not self.negate and val1 == val2):
return self.nodelist_true.render(context)
return self.nodelist_false.render(context)
class IfNode(template.Node):
class IfNode(Node):
def __init__(self, boolvars, nodelist_true, nodelist_false):
self.boolvars = boolvars
self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false
@ -173,27 +171,27 @@ class IfNode(template.Node):
def render(self, context):
for ifnot, boolvar in self.boolvars:
try:
value = template.resolve_variable_with_filters(boolvar, context)
except template.VariableDoesNotExist:
value = resolve_variable_with_filters(boolvar, context)
except VariableDoesNotExist:
value = None
if (value and not ifnot) or (ifnot and not value):
return self.nodelist_true.render(context)
return self.nodelist_false.render(context)
class RegroupNode(template.Node):
class RegroupNode(Node):
def __init__(self, target_var, expression, var_name):
self.target_var, self.expression = target_var, expression
self.var_name = var_name
def render(self, context):
obj_list = template.resolve_variable_with_filters(self.target_var, context)
obj_list = resolve_variable_with_filters(self.target_var, context)
if obj_list == '': # target_var wasn't found in context; fail silently
context[self.var_name] = []
return ''
output = [] # list of dictionaries in the format {'grouper': 'key', 'list': [list of contents]}
for obj in obj_list:
grouper = template.resolve_variable_with_filters('var.%s' % self.expression, \
template.Context({'var': obj}))
grouper = resolve_variable_with_filters('var.%s' % self.expression, \
Context({'var': obj}))
if output and repr(output[-1]['grouper']) == repr(grouper):
output[-1]['list'].append(obj)
else:
@ -208,7 +206,7 @@ def include_is_allowed(filepath):
return True
return False
class SsiNode(template.Node):
class SsiNode(Node):
def __init__(self, filepath, parsed):
self.filepath, self.parsed = filepath, parsed
@ -223,13 +221,13 @@ class SsiNode(template.Node):
output = ''
if self.parsed:
try:
t = template.Template(output)
t = Template(output)
return t.render(context)
except template.TemplateSyntaxError:
except TemplateSyntaxError:
return '' # Fail silently for invalid included templates.
return output
class LoadNode(template.Node):
class LoadNode(Node):
def __init__(self, taglib):
self.taglib = taglib
@ -247,7 +245,7 @@ class LoadNode(template.Node):
pass # Fail silently for invalid loads.
return ''
class NowNode(template.Node):
class NowNode(Node):
def __init__(self, format_string):
self.format_string = format_string
@ -257,11 +255,11 @@ class NowNode(template.Node):
df = DateFormat(datetime.now())
return df.format(self.format_string)
class TemplateTagNode(template.Node):
mapping = {'openblock': template.BLOCK_TAG_START,
'closeblock': template.BLOCK_TAG_END,
'openvariable': template.VARIABLE_TAG_START,
'closevariable': template.VARIABLE_TAG_END}
class TemplateTagNode(Node):
mapping = {'openblock': BLOCK_TAG_START,
'closeblock': BLOCK_TAG_END,
'openvariable': VARIABLE_TAG_START,
'closevariable': VARIABLE_TAG_END}
def __init__(self, tagtype):
self.tagtype = tagtype
@ -269,7 +267,7 @@ class TemplateTagNode(template.Node):
def render(self, context):
return self.mapping.get(self.tagtype, '')
class WidthRatioNode(template.Node):
class WidthRatioNode(Node):
def __init__(self, val_var, max_var, max_width):
self.val_var = val_var
self.max_var = max_var
@ -277,9 +275,9 @@ class WidthRatioNode(template.Node):
def render(self, context):
try:
value = template.resolve_variable_with_filters(self.val_var, context)
maxvalue = template.resolve_variable_with_filters(self.max_var, context)
except template.VariableDoesNotExist:
value = resolve_variable_with_filters(self.val_var, context)
maxvalue = resolve_variable_with_filters(self.max_var, context)
except VariableDoesNotExist:
return ''
try:
value = float(value)
@ -289,7 +287,7 @@ class WidthRatioNode(template.Node):
return ''
return str(int(round(ratio)))
class I18NNode(template.Node):
class I18NNode(Node):
def __init__(self, cmd):
self.cmd = cmd
@ -304,7 +302,7 @@ class I18NNode(template.Node):
elif s.startswith('"') and s.endswith('"'):
s = s[1:-1]
else:
s = template.resolve_variable_with_filters(s, context)
s = resolve_variable_with_filters(s, context)
return s
def render(self, context):
@ -317,14 +315,24 @@ class I18NNode(template.Node):
elif f == 'gettext_noop':
return translation.gettext_noop(s) % context
else:
raise template.TemplateSyntaxError("i18n only supports _, gettext, gettext_noop and ngettext as functions, not %s" % f)
raise TemplateSyntaxError("i18n only supports _, gettext, gettext_noop and ngettext as functions, not %s" % f)
m = self.ngettext_re.match(self.cmd)
if m:
singular = self._resolve_var(m.group(1), context)
plural = self._resolve_var(m.group(2), context)
var = template.resolve_variable_with_filters(m.group(3), context)
var = resolve_variable_with_filters(m.group(3), context)
return translation.ngettext(singular, plural, var) % context
raise template.TemplateSyntaxError("i18n must be called as {% i18n _('some message') %} or {% i18n ngettext('singular', 'plural', var) %}")
raise TemplateSyntaxError("i18n must be called as {% i18n _('some message') %} or {% i18n ngettext('singular', 'plural', var) %}")
cyclevars = [v for v in args[1].split(",") if v] # split and kill blanks
name = args[3]
node = CycleNode(cyclevars)
if not hasattr(parser, '_namedCycleNodes'):
parser._namedCycleNodes = {}
parser._namedCycleNodes[name] = node
return node
def do_comment(parser, token):
"""
@ -370,7 +378,7 @@ def do_cycle(parser, token):
args = token.contents.split()
if len(args) < 2:
raise template.TemplateSyntaxError("'Cycle' statement requires at least two arguments")
raise TemplateSyntaxError("'Cycle' statement requires at least two arguments")
elif len(args) == 2 and "," in args[1]:
# {% cycle a,b,c %}
@ -381,13 +389,13 @@ def do_cycle(parser, token):
elif len(args) == 2:
name = args[1]
if not parser._namedCycleNodes.has_key(name):
raise template.TemplateSyntaxError("Named cycle '%s' does not exist" % name)
raise TemplateSyntaxError("Named cycle '%s' does not exist" % name)
return parser._namedCycleNodes[name]
elif len(args) == 4:
# {% cycle a,b,c as name %}
if args[2] != 'as':
raise template.TemplateSyntaxError("Second 'cycle' argument must be 'as'")
raise TemplateSyntaxError("Second 'cycle' argument must be 'as'")
cyclevars = [v for v in args[1].split(",") if v] # split and kill blanks
name = args[3]
node = CycleNode(cyclevars)
@ -399,7 +407,7 @@ def do_cycle(parser, token):
return node
else:
raise template.TemplateSyntaxError("Invalid arguments to 'cycle': %s" % args)
raise TemplateSyntaxError("Invalid arguments to 'cycle': %s" % args)
def do_debug(parser, token):
"Print a whole load of debugging information, including the context and imported modules"
@ -419,7 +427,7 @@ def do_filter(parser, token):
{% endfilter %}
"""
_, rest = token.contents.split(None, 1)
_, filters = template.get_filters_from_token('var|%s' % rest)
_, filters = get_filters_from_token('var|%s' % rest)
nodelist = parser.parse(('endfilter',))
parser.delete_first_token()
return FilterNode(filters, nodelist)
@ -448,7 +456,7 @@ def do_firstof(parser, token):
"""
bits = token.contents.split()[1:]
if len(bits) < 1:
raise template.TemplateSyntaxError, "'firstof' statement requires at least one argument"
raise TemplateSyntaxError, "'firstof' statement requires at least one argument"
return FirstOfNode(bits)
@ -487,11 +495,11 @@ def do_for(parser, token):
"""
bits = token.contents.split()
if len(bits) == 5 and bits[4] != 'reversed':
raise template.TemplateSyntaxError, "'for' statements with five words should end in 'reversed': %s" % token.contents
raise TemplateSyntaxError, "'for' statements with five words should end in 'reversed': %s" % token.contents
if len(bits) not in (4, 5):
raise template.TemplateSyntaxError, "'for' statements should have either four or five words: %s" % token.contents
raise TemplateSyntaxError, "'for' statements should have either four or five words: %s" % token.contents
if bits[2] != 'in':
raise template.TemplateSyntaxError, "'for' statement must contain 'in' as the second word: %s" % token.contents
raise TemplateSyntaxError, "'for' statement must contain 'in' as the second word: %s" % token.contents
loopvar = bits[1]
sequence = bits[3]
reversed = (len(bits) == 5)
@ -517,7 +525,7 @@ def do_ifequal(parser, token, negate):
"""
bits = token.contents.split()
if len(bits) != 3:
raise template.TemplateSyntaxError, "%r takes two arguments" % bits[0]
raise TemplateSyntaxError, "%r takes two arguments" % bits[0]
end_tag = 'end' + bits[0]
nodelist_true = parser.parse(('else', end_tag))
token = parser.next_token()
@ -525,7 +533,7 @@ def do_ifequal(parser, token, negate):
nodelist_false = parser.parse((end_tag,))
parser.delete_first_token()
else:
nodelist_false = template.NodeList()
nodelist_false = NodeList()
return IfEqualNode(bits[1], bits[2], nodelist_true, nodelist_false, negate)
def do_if(parser, token):
@ -578,7 +586,7 @@ def do_if(parser, token):
bits = token.contents.split()
del bits[0]
if not bits:
raise template.TemplateSyntaxError, "'if' statement requires at least one argument"
raise TemplateSyntaxError, "'if' statement requires at least one argument"
# bits now looks something like this: ['a', 'or', 'not', 'b', 'or', 'c.d']
boolpairs = ' '.join(bits).split(' or ')
boolvars = []
@ -586,7 +594,7 @@ def do_if(parser, token):
if ' ' in boolpair:
not_, boolvar = boolpair.split()
if not_ != 'not':
raise template.TemplateSyntaxError, "Expected 'not' in if statement"
raise TemplateSyntaxError, "Expected 'not' in if statement"
boolvars.append((True, boolvar))
else:
boolvars.append((False, boolpair))
@ -596,7 +604,7 @@ def do_if(parser, token):
nodelist_false = parser.parse(('endif',))
parser.delete_first_token()
else:
nodelist_false = template.NodeList()
nodelist_false = NodeList()
return IfNode(boolvars, nodelist_true, nodelist_false)
def do_ifchanged(parser, token):
@ -616,7 +624,7 @@ def do_ifchanged(parser, token):
"""
bits = token.contents.split()
if len(bits) != 1:
raise template.TemplateSyntaxError, "'ifchanged' tag takes no arguments"
raise TemplateSyntaxError, "'ifchanged' tag takes no arguments"
nodelist = parser.parse(('endifchanged',))
parser.delete_first_token()
return IfChangedNode(nodelist)
@ -639,12 +647,12 @@ def do_ssi(parser, token):
bits = token.contents.split()
parsed = False
if len(bits) not in (2, 3):
raise template.TemplateSyntaxError, "'ssi' tag takes one argument: the path to the file to be included"
raise TemplateSyntaxError, "'ssi' tag takes one argument: the path to the file to be included"
if len(bits) == 3:
if bits[2] == 'parsed':
parsed = True
else:
raise template.TemplateSyntaxError, "Second (optional) argument to %s tag must be 'parsed'" % bits[0]
raise TemplateSyntaxError, "Second (optional) argument to %s tag must be 'parsed'" % bits[0]
return SsiNode(bits[1], parsed)
def do_load(parser, token):
@ -657,13 +665,13 @@ def do_load(parser, token):
"""
bits = token.contents.split()
if len(bits) != 2:
raise template.TemplateSyntaxError, "'load' statement takes one argument"
raise TemplateSyntaxError, "'load' statement takes one argument"
taglib = bits[1]
# check at compile time that the module can be imported
try:
LoadNode.load_taglib(taglib)
except ImportError:
raise template.TemplateSyntaxError, "'%s' is not a valid tag library" % taglib
raise TemplateSyntaxError, "'%s' is not a valid tag library" % taglib
return LoadNode(taglib)
def do_now(parser, token):
@ -679,7 +687,7 @@ def do_now(parser, token):
"""
bits = token.contents.split('"')
if len(bits) != 3:
raise template.TemplateSyntaxError, "'now' statement takes one argument"
raise TemplateSyntaxError, "'now' statement takes one argument"
format_string = bits[1]
return NowNode(format_string)
@ -731,13 +739,13 @@ def do_regroup(parser, token):
"""
firstbits = token.contents.split(None, 3)
if len(firstbits) != 4:
raise template.TemplateSyntaxError, "'regroup' tag takes five arguments"
raise TemplateSyntaxError, "'regroup' tag takes five arguments"
target_var = firstbits[1]
if firstbits[2] != 'by':
raise template.TemplateSyntaxError, "second argument to 'regroup' tag must be 'by'"
raise TemplateSyntaxError, "second argument to 'regroup' tag must be 'by'"
lastbits_reversed = firstbits[3][::-1].split(None, 2)
if lastbits_reversed[1][::-1] != 'as':
raise template.TemplateSyntaxError, "next-to-last argument to 'regroup' tag must be 'as'"
raise TemplateSyntaxError, "next-to-last argument to 'regroup' tag must be 'as'"
expression = lastbits_reversed[2][::-1]
var_name = lastbits_reversed[0][::-1]
return RegroupNode(target_var, expression, var_name)
@ -762,10 +770,10 @@ def do_templatetag(parser, token):
"""
bits = token.contents.split()
if len(bits) != 2:
raise template.TemplateSyntaxError, "'templatetag' statement takes one argument"
raise TemplateSyntaxError, "'templatetag' statement takes one argument"
tag = bits[1]
if not TemplateTagNode.mapping.has_key(tag):
raise template.TemplateSyntaxError, "Invalid templatetag argument: '%s'. Must be one of: %s" % \
raise TemplateSyntaxError, "Invalid templatetag argument: '%s'. Must be one of: %s" % \
(tag, TemplateTagNode.mapping.keys())
return TemplateTagNode(tag)
@ -784,12 +792,12 @@ def do_widthratio(parser, token):
"""
bits = token.contents.split()
if len(bits) != 4:
raise template.TemplateSyntaxError("widthratio takes three arguments")
raise TemplateSyntaxError("widthratio takes three arguments")
tag, this_value_var, max_value_var, max_width = bits
try:
max_width = int(max_width)
except ValueError:
raise template.TemplateSyntaxError("widthratio final argument must be an integer")
raise TemplateSyntaxError("widthratio final argument must be an integer")
return WidthRatioNode(this_value_var, max_value_var, max_width)
def do_i18n(parser, token):
@ -809,21 +817,20 @@ def do_i18n(parser, token):
return I18NNode(args[1].strip())
template.register_tag('comment', do_comment)
template.register_tag('cycle', do_cycle)
template.register_tag('debug', do_debug)
template.register_tag('filter', do_filter)
template.register_tag('firstof', do_firstof)
template.register_tag('for', do_for)
template.register_tag('ifequal', lambda parser, token: do_ifequal(parser, token, False))
template.register_tag('ifnotequal', lambda parser, token: do_ifequal(parser, token, True))
template.register_tag('if', do_if)
template.register_tag('ifchanged', do_ifchanged)
template.register_tag('regroup', do_regroup)
template.register_tag('ssi', do_ssi)
template.register_tag('load', do_load)
template.register_tag('now', do_now)
template.register_tag('templatetag', do_templatetag)
template.register_tag('widthratio', do_widthratio)
template.register_tag('i18n', do_i18n)
register_tag('comment', do_comment)
register_tag('cycle', do_cycle)
register_tag('debug', do_debug)
register_tag('filter', do_filter)
register_tag('firstof', do_firstof)
register_tag('for', do_for)
register_tag('ifequal', lambda parser, token: do_ifequal(parser, token, False))
register_tag('ifnotequal', lambda parser, token: do_ifequal(parser, token, True))
register_tag('if', do_if)
register_tag('ifchanged', do_ifchanged)
register_tag('regroup', do_regroup)
register_tag('ssi', do_ssi)
register_tag('load', do_load)
register_tag('now', do_now)
register_tag('templatetag', do_templatetag)
register_tag('widthratio', do_widthratio)
register_tag('i18n', do_i18n)

View File

@ -0,0 +1,163 @@
"Wrapper for loading templates from storage of some sort (e.g. files or db)"
from django.core.template import Template, Context, Node, TemplateDoesNotExist, TemplateSyntaxError, resolve_variable_with_filters, register_tag
from django.core.template.loaders.filesystem import load_template_source
class ExtendsError(Exception):
pass
def get_template(template_name):
"""
Returns a compiled Template object for the given template name,
handling template inheritance recursively.
"""
return get_template_from_string(load_template_source(template_name))
def get_template_from_string(source):
"""
Returns a compiled Template object for the given template code,
handling template inheritance recursively.
"""
return Template(source)
def render_to_string(template_name, dictionary=None, context_instance=None):
"""
Loads the given template_name and renders it with the given dictionary as
context. The template_name may be a string to load a single template using
get_template, or it may be a tuple to use select_template to find one of
the templates in the list. Returns a string.
"""
dictionary = dictionary or {}
if isinstance(template_name, (list, tuple)):
t = select_template(template_name)
else:
t = get_template(template_name)
if context_instance:
context_instance.update(dictionary)
else:
context_instance = Context(dictionary)
return t.render(context_instance)
def select_template(template_name_list):
"Given a list of template names, returns the first that can be loaded."
for template_name in template_name_list:
try:
return get_template(template_name)
except TemplateDoesNotExist:
continue
# If we get here, none of the templates could be loaded
raise TemplateDoesNotExist, ', '.join(template_name_list)
class BlockNode(Node):
def __init__(self, name, nodelist, parent=None):
self.name, self.nodelist, self.parent = name, nodelist, parent
def __repr__(self):
return "<Block Node: %s. Contents: %r>" % (self.name, self.nodelist)
def render(self, context):
context.push()
# Save context in case of block.super().
self.context = context
context['block'] = self
result = self.nodelist.render(context)
context.pop()
return result
def super(self):
if self.parent:
return self.parent.render(self.context)
return ''
def add_parent(self, nodelist):
if self.parent:
self.parent.add_parent(nodelist)
else:
self.parent = BlockNode(self.name, nodelist)
class ExtendsNode(Node):
def __init__(self, nodelist, parent_name, parent_name_var, template_dirs=None):
self.nodelist = nodelist
self.parent_name, self.parent_name_var = parent_name, parent_name_var
self.template_dirs = template_dirs
def get_parent(self, context):
if self.parent_name_var:
self.parent_name = resolve_variable_with_filters(self.parent_name_var, context)
parent = self.parent_name
if not parent:
error_msg = "Invalid template name in 'extends' tag: %r." % parent
if self.parent_name_var:
error_msg += " Got this from the %r variable." % self.parent_name_var
raise TemplateSyntaxError, error_msg
try:
return get_template_from_string(load_template_source(parent, self.template_dirs))
except TemplateDoesNotExist:
raise TemplateSyntaxError, "Template %r cannot be extended, because it doesn't exist" % parent
def render(self, context):
compiled_parent = self.get_parent(context)
parent_is_child = isinstance(compiled_parent.nodelist[0], ExtendsNode)
parent_blocks = dict([(n.name, n) for n in compiled_parent.nodelist.get_nodes_by_type(BlockNode)])
for block_node in self.nodelist.get_nodes_by_type(BlockNode):
# Check for a BlockNode with this node's name, and replace it if found.
try:
parent_block = parent_blocks[block_node.name]
except KeyError:
# This BlockNode wasn't found in the parent template, but the
# parent block might be defined in the parent's *parent*, so we
# add this BlockNode to the parent's ExtendsNode nodelist, so
# it'll be checked when the parent node's render() is called.
if parent_is_child:
compiled_parent.nodelist[0].nodelist.append(block_node)
else:
# Keep any existing parents and add a new one. Used by BlockNode.
parent_block.parent = block_node.parent
parent_block.add_parent(parent_block.nodelist)
parent_block.nodelist = block_node.nodelist
return compiled_parent.render(context)
def do_block(parser, token):
"""
Define a block that can be overridden by child templates.
"""
bits = token.contents.split()
if len(bits) != 2:
raise TemplateSyntaxError, "'%s' tag takes only one argument" % bits[0]
block_name = bits[1]
# Keep track of the names of BlockNodes found in this template, so we can
# check for duplication.
try:
if block_name in parser.__loaded_blocks:
raise TemplateSyntaxError, "'%s' tag with name '%s' appears more than once" % (bits[0], block_name)
parser.__loaded_blocks.append(block_name)
except AttributeError: # parser._loaded_blocks isn't a list yet
parser.__loaded_blocks = [block_name]
nodelist = parser.parse(('endblock',))
parser.delete_first_token()
return BlockNode(block_name, nodelist)
def do_extends(parser, token):
"""
Signal that this template extends a parent template.
This tag may be used in two ways: ``{% extends "base" %}`` (with quotes)
uses the literal value "base" as the name of the parent template to extend,
or ``{% entends variable %}`` uses the value of ``variable`` as the name
of the parent template to extend.
"""
bits = token.contents.split()
if len(bits) != 2:
raise TemplateSyntaxError, "'%s' takes one argument" % bits[0]
parent_name, parent_name_var = None, None
if (bits[1].startswith('"') and bits[1].endswith('"')) or (bits[1].startswith("'") and bits[1].endswith("'")):
parent_name = bits[1][1:-1]
else:
parent_name_var = bits[1]
nodelist = parser.parse()
if nodelist.get_nodes_by_type(ExtendsNode):
raise TemplateSyntaxError, "'%s' cannot appear more than once in the same template" % bits[0]
return ExtendsNode(nodelist, parent_name, parent_name_var)
register_tag('block', do_block)
register_tag('extends', do_extends)

View File

View File

@ -1,4 +1,4 @@
# Wrapper for loading templates from files
# Wrapper for loading templates from the filesystem.
from django.conf.settings import TEMPLATE_DIRS, TEMPLATE_FILE_EXTENSION
from django.core.template import TemplateDoesNotExist

View File

@ -1,162 +1,7 @@
"Wrapper for loading templates from storage of some sort (e.g. files or db)"
import template
from template_file import load_template_source
# This module is DEPRECATED!
#
# You should no longer be using django.core.template_loader.
#
# Use django.core.template.loader instead.
class ExtendsError(Exception):
pass
def get_template(template_name):
"""
Returns a compiled template.Template object for the given template name,
handling template inheritance recursively.
"""
return get_template_from_string(load_template_source(template_name))
def get_template_from_string(source):
"""
Returns a compiled template.Template object for the given template code,
handling template inheritance recursively.
"""
return template.Template(source)
def render_to_string(template_name, dictionary=None, context_instance=None):
"""
Loads the given template_name and renders it with the given dictionary as
context. The template_name may be a string to load a single template using
get_template, or it may be a tuple to use select_template to find one of
the templates in the list. Returns a string.
"""
dictionary = dictionary or {}
if isinstance(template_name, (list, tuple)):
t = select_template(template_name)
else:
t = get_template(template_name)
if context_instance:
context_instance.update(dictionary)
else:
context_instance = template.Context(dictionary)
return t.render(context_instance)
def select_template(template_name_list):
"Given a list of template names, returns the first that can be loaded."
for template_name in template_name_list:
try:
return get_template(template_name)
except template.TemplateDoesNotExist:
continue
# If we get here, none of the templates could be loaded
raise template.TemplateDoesNotExist, ', '.join(template_name_list)
class BlockNode(template.Node):
def __init__(self, name, nodelist, parent=None):
self.name, self.nodelist, self.parent = name, nodelist, parent
def __repr__(self):
return "<Block Node: %s. Contents: %r>" % (self.name, self.nodelist)
def render(self, context):
context.push()
# Save context in case of block.super().
self.context = context
context['block'] = self
result = self.nodelist.render(context)
context.pop()
return result
def super(self):
if self.parent:
return self.parent.render(self.context)
return ''
def add_parent(self, nodelist):
if self.parent:
self.parent.add_parent(nodelist)
else:
self.parent = BlockNode(self.name, nodelist)
class ExtendsNode(template.Node):
def __init__(self, nodelist, parent_name, parent_name_var, template_dirs=None):
self.nodelist = nodelist
self.parent_name, self.parent_name_var = parent_name, parent_name_var
self.template_dirs = template_dirs
def get_parent(self, context):
if self.parent_name_var:
self.parent_name = template.resolve_variable_with_filters(self.parent_name_var, context)
parent = self.parent_name
if not parent:
error_msg = "Invalid template name in 'extends' tag: %r." % parent
if self.parent_name_var:
error_msg += " Got this from the %r variable." % self.parent_name_var
raise template.TemplateSyntaxError, error_msg
try:
return get_template_from_string(load_template_source(parent, self.template_dirs))
except template.TemplateDoesNotExist:
raise template.TemplateSyntaxError, "Template %r cannot be extended, because it doesn't exist" % parent
def render(self, context):
compiled_parent = self.get_parent(context)
parent_is_child = isinstance(compiled_parent.nodelist[0], ExtendsNode)
parent_blocks = dict([(n.name, n) for n in compiled_parent.nodelist.get_nodes_by_type(BlockNode)])
for block_node in self.nodelist.get_nodes_by_type(BlockNode):
# Check for a BlockNode with this node's name, and replace it if found.
try:
parent_block = parent_blocks[block_node.name]
except KeyError:
# This BlockNode wasn't found in the parent template, but the
# parent block might be defined in the parent's *parent*, so we
# add this BlockNode to the parent's ExtendsNode nodelist, so
# it'll be checked when the parent node's render() is called.
if parent_is_child:
compiled_parent.nodelist[0].nodelist.append(block_node)
else:
# Keep any existing parents and add a new one. Used by BlockNode.
parent_block.parent = block_node.parent
parent_block.add_parent(parent_block.nodelist)
parent_block.nodelist = block_node.nodelist
return compiled_parent.render(context)
def do_block(parser, token):
"""
Define a block that can be overridden by child templates.
"""
bits = token.contents.split()
if len(bits) != 2:
raise template.TemplateSyntaxError, "'%s' tag takes only one argument" % bits[0]
block_name = bits[1]
# Keep track of the names of BlockNodes found in this template, so we can
# check for duplication.
try:
if block_name in parser.__loaded_blocks:
raise template.TemplateSyntaxError, "'%s' tag with name '%s' appears more than once" % (bits[0], block_name)
parser.__loaded_blocks.append(block_name)
except AttributeError: # parser._loaded_blocks isn't a list yet
parser.__loaded_blocks = [block_name]
nodelist = parser.parse(('endblock',))
parser.delete_first_token()
return BlockNode(block_name, nodelist)
def do_extends(parser, token):
"""
Signal that this template extends a parent template.
This tag may be used in two ways: ``{% extends "base" %}`` (with quotes)
uses the literal value "base" as the name of the parent template to extend,
or ``{% entends variable %}`` uses the value of ``variable`` as the name
of the parent template to extend.
"""
bits = token.contents.split()
if len(bits) != 2:
raise template.TemplateSyntaxError, "'%s' takes one argument" % bits[0]
parent_name, parent_name_var = None, None
if (bits[1].startswith('"') and bits[1].endswith('"')) or (bits[1].startswith("'") and bits[1].endswith("'")):
parent_name = bits[1][1:-1]
else:
parent_name_var = bits[1]
nodelist = parser.parse()
if nodelist.get_nodes_by_type(ExtendsNode):
raise template.TemplateSyntaxError, "'%s' cannot appear more than once in the same template" % bits[0]
return ExtendsNode(nodelist, parent_name, parent_name_var)
template.register_tag('block', do_block)
template.register_tag('extends', do_extends)
from django.core.template.loader import *

View File

@ -1,6 +1,6 @@
from django.utils import httpwrappers
from django.core import template_loader
from django.core.extensions import DjangoContext as Context
from django.core.extensions import DjangoContext
from django.core.extensions import render_to_response
from django.models.auth import users
from django.views.registration import passwords
from django.views.auth.login import logout
@ -96,14 +96,12 @@ class AdminUserRequired:
post_data = encode_post_data(request.POST)
else:
post_data = encode_post_data({})
t = template_loader.get_template(self.get_login_template_name())
c = Context(request, {
return render_to_response(self.get_login_template_name(), {
'title': 'Log in',
'app_path': request.path,
'post_data': post_data,
'error_message': error_message
})
return httpwrappers.HttpResponse(t.render(c))
}, context_instance=DjangoContext(request))
def authenticate_user(self, user, password):
return user.check_password(password) and user.is_staff

View File

@ -4,7 +4,8 @@ from django.conf import settings
from django.models.core import sites
from django.core.extensions import DjangoContext, render_to_response
from django.core.exceptions import Http404, ViewDoesNotExist
from django.core import template, template_loader, defaulttags, defaultfilters, urlresolvers
from django.core import template, template_loader, urlresolvers
from django.core.template import defaulttags, defaultfilters
try:
from django.parts.admin import doc
except ImportError:

View File

@ -1,5 +1,6 @@
from django.core import formfields, template_loader, validators
from django.core import formfields, validators
from django.core import template
from django.core.template import loader
from django.core.extensions import DjangoContext, render_to_response
from django.models.core import sites
from django.conf import settings
@ -49,7 +50,7 @@ class TemplateValidator(formfields.Manipulator):
# so that inheritance works in the site's context, register a new function
# for "extends" that uses the site's TEMPLATE_DIR instead
def new_do_extends(parser, token):
node = template_loader.do_extends(parser, token)
node = loader.do_extends(parser, token)
node.template_dirs = settings_module.TEMPLATE_DIRS
return node
template.register_tag('extends', new_do_extends)
@ -58,10 +59,10 @@ class TemplateValidator(formfields.Manipulator):
# making sure to reset the extends function in any case
error = None
try:
tmpl = template_loader.get_template_from_string(field_data)
tmpl = loader.get_template_from_string(field_data)
tmpl.render(template.Context({}))
except template.TemplateSyntaxError, e:
error = e
template.register_tag('extends', template_loader.do_extends)
template.register_tag('extends', loader.do_extends)
if error:
raise validators.ValidationError, e.args

View File

@ -1,5 +1,5 @@
from django.parts.auth.formfields import AuthenticationForm
from django.core import formfields, template_loader
from django.core import formfields
from django.core.extensions import DjangoContext, render_to_response
from django.models.auth import users
from django.models.core import sites

View File

@ -1,6 +1,5 @@
from django.core import template_loader
from django.core.exceptions import Http404, ObjectDoesNotExist
from django.core.template import Context
from django.core.template import Context, loader
from django.models.core import sites
from django.utils import httpwrappers
@ -56,7 +55,7 @@ def page_not_found(request):
if r == '':
return httpwrappers.HttpResponseGone()
return httpwrappers.HttpResponseRedirect(r.new_path)
t = template_loader.get_template('404')
t = loader.get_template('404')
c = Context()
return httpwrappers.HttpResponseNotFound(t.render(c))
@ -67,6 +66,6 @@ def server_error(request):
Templates: `500`
Context: None
"""
t = template_loader.get_template('500')
t = loader.get_template('500')
c = Context()
return httpwrappers.HttpResponseServerError(t.render(c))

View File

@ -1,5 +1,6 @@
from django.core import formfields, template_loader, validators
from django.core import formfields, validators
from django.core.extensions import DjangoContext, render_to_response
from django.core.template import loader
from django.models.auth import users
from django.views.decorators.auth import login_required
from django.utils.httpwrappers import HttpResponseRedirect
@ -32,7 +33,7 @@ class PasswordResetForm(formfields.Manipulator):
domain = current_site.domain
else:
site_name = domain = domain_override
t = template_loader.get_template('registration/password_reset_email')
t = loader.get_template('registration/password_reset_email')
c = {
'new_password': new_pass,
'email': self.user_cache.email,

View File

@ -0,0 +1,244 @@
===================
Design philosophies
===================
This document explains some of the fundamental philosophies Django's developers
have used in creating the framework. Its goal is to explain the past and guide
the future.
Overall
=======
Loose coupling
--------------
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
absolutely necessary.
For example, the template system knows nothing about Web requests, the database
layer knows nothing about data display and the view system doesn't care which
template system a programmer uses.
.. _`loose coupling and tight cohesion`: http://c2.com/cgi/wiki?CouplingAndCohesion
Less code
---------
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
introspection.
Quick development
-----------------
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
development.
Don't repeat yourself (DRY)
---------------------------
Every distinct concept and/or piece of data should live in one, and only one,
place. Redundancy is bad. Normalization is good.
The framework, within reason, should deduce as much as possible from as little
as possible.
Explicit is better than implicit
--------------------------------
This, a `core Python principle`_, means Django shouldn't do too much "magic."
Magic shouldn't happen unless there's a really good reason for it.
.. _`core Python principle`: http://www.python.org/doc/Humor.html#zen
Consistency
-----------
The framework should be consistent at all levels. Consistency applies to
everything from low-level (the Python coding style used) to high-level (the
"experience" of using Django).
Models
======
Explicit is better than implicit
--------------------------------
Fields shouldn't assume certain behaviors based solely on the name of the
field. This requires too much knowledge of the system and is prone to errors.
Instead, behaviors should be based on keyword arguments and, in some cases, on
the type of the field.
Include all relevant domain logic
---------------------------------
Models should encapsulate every aspect of an "object," following Martin
Fowler's `Active Record`_ design pattern.
This is why model-specific admin options are included in the model itself; data
related to a model should be stored *in* the model.
.. _`Active Record`: http://www.martinfowler.com/eaaCatalog/activeRecord.html
Database API
============
The core goals of the database API are:
SQL efficiency
--------------
It should execute SQL statements as few times as possible, and it should
optimize statements internally.
This is why developers need to call ``save()`` explicitly, rather than the
framework saving things behind the scenes silently.
This is also why the ``select_related`` argument exists. It's an optional
performance booster for the common case of selecting "every related object."
Terse, powerful syntax
----------------------
The database API should allow rich, expressive statements in as little syntax
as possible. It should not rely on importing other modules or helper objects.
Joins should be performed automatically, behind the scenes, when necessary.
Every object should be able to access every related object, systemwide. This
access should work both ways.
Option to drop into raw SQL easily, when needed
-----------------------------------------------
The database API should realize it's a shortcut but not necessarily an
end-all-be-all. The framework should make it easy to write custom SQL -- entire
statements, or just custom ``WHERE`` clauses as custom parameters to API calls.
URL design
==========
Loose coupling
--------------
URLs in a Django app should not be coupled to the underlying Python code. Tying
URLs to Python function names is a Bad And Ugly Thing.
Along these lines, the Django URL system should allow URLs for the same app to
be different in different contexts. For example, one site may put stories at
``/stories/``, while another may use ``/news/``.
Infinite flexibility
--------------------
URLs should be as flexible as possible. Any conceivable URL design should be
allowed.
Encourage best practices
------------------------
The framework should make it just as easy (or even easier) for a developer to
design pretty URLs than ugly ones.
File extensions in Web-page URLs should be avoided.
Definitive URLs
---------------
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
separate pages. Django should make an effort to "normalize" URLs so that
search-engine robots don't get confused.
This is the reasoning behind the ``APPEND_SLASH`` setting.
Template system
===============
Separate logic from presentation
--------------------------------
We see a template system as a tool that controls presentation and
presentation-related logic -- and that's it. The template system shouldn't
support functionality that goes beyond this basic goal.
If we wanted to put everything in templates, we'd be using PHP. Been there,
done that, wised up.
Discourage redundancy
---------------------
The majority of dynamic Web sites use some sort of common sitewide design --
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
code.
This is the philosophy behind template inheritance.
Be decoupled from HTML
----------------------
The template system shouldn't be designed so that it only outputs HTML. It
should be equally good at generating other text-based formats, or just plain
text.
Assume designer competence
--------------------------
The template system shouldn't be designed so that templates necessarily are
displayed nicely in WYSIWYG editors such as Dreamweaver. That is too severe of
a limitation and wouldn't allow the syntax to be as nice as it is. Django
expects template authors are comfortable editing HTML directly.
Treat whitespace obviously
--------------------------
The template system shouldn't do magic things with whitespace. If a template
includes whitespace, the system should treat the whitespace as it treats text
-- just display it.
Don't invent a programming language
-----------------------------------
The template system intentionally doesn't allow the following:
* Assignment to variables
* Advanced logic
The goal is not to invent a programming language. The goal is to offer just
enough programming-esque functionality, such as branching and looping, that is
essential for making presentation-related decisions.
Extensibility
-------------
The template system should recognize that advanced template authors may want
to extend its technology.
This is the philosophy behind custom template tags and filters.
Views
=====
Simplicity
----------
Writing a view should be as simple as writing a Python function. Developers
shouldn't have to instantiate a class when a function will do.
Use request objects
-------------------
Views should have access to a request object -- an object that stores metadata
about the current request. The object should be passed directly to a view
function, rather than the view function having to access the request data from
a global variable. This makes it light, clean and easy to test views by passing
in "fake" request objects.
Loose coupling
--------------
A view shouldn't care about which template system the developer uses -- or even
whether a template system is used at all.

View File

@ -65,9 +65,8 @@ Using the ``AddManipulator``
We'll start with the ``AddManipulator``. Here's a very simple view that takes
POSTed data from the browser and creates a new ``Place`` object::
from django.core import template_loader
from django.core.exceptions import Http404
from django.core.extensions import DjangoContext as Context
from django.core.extensions import render_to_response
from django.utils.httpwrappers import HttpResponse, HttpResponseRedirect
from django.models.places import places
from django.core import formfields
@ -112,13 +111,7 @@ view with a form that submits to this flawed creation view::
# Create a FormWrapper object that the template can use. Ignore
# the last two arguments to FormWrapper for now.
form = formfields.FormWrapper(places.AddManipulator(), {}, {})
# Create a template, context and response.
t = template_loader.get_template('places/naive_create_form')
c = Context(request, {
'form': form
})
return HttpResponse(t.render(c))
return render_to_response('places/naive_create_form', {'form': form})
(This view, as well as all the following ones, has the same imports as in the
first example above.)
@ -169,11 +162,7 @@ creation view that takes validation into account::
# Check for validation errors
errors = manipulator.get_validation_errors(new_data)
if errors:
t = template_loader.get_template('places/errors')
c = Context(request, {
'errors': errors
}
return HttpResponse(t.render(c))
return render_to_response('places/errors', {'errors': errors})
else:
manipulator.do_html2python(request.POST)
new_place = manipulator.save(request.POST)
@ -245,11 +234,7 @@ Below is the finished view::
# Create the FormWrapper, template, context, response.
form = formfields.FormWrapper(manipulator, new_data, errors)
t = template_loader.get_template("places/create_form")
c = Context(request, {
'form': form,
})
return HttpResponse(t.render(c))
return render_to_response('places/create_form', {'form': form})
and here's the ``create_form`` template::
@ -338,12 +323,7 @@ about editing an existing one? It's shockingly similar to creating a new one::
new_data = place.__dict__
form = formfields.FormWrapper(manipulator, new_data, errors)
t = template_loader.get_template("places/edit_form")
c = Context(request, {
'form': form,
'place': place,
})
return HttpResponse(t.render(c))
return render_to_response('places/edit_form', {'form': form, 'place': place})
The only real differences are:
@ -422,11 +402,7 @@ Here's a simple function that might drive the above form::
else:
errors = new_data = {}
form = formfields.FormWrapper(manipulator, new_data, errors)
t = template_loader.get_template("contact_form")
c = Context(request, {
'form': form,
})
return HttpResponse(t.render(c))
return render_to_response('contact_form', {'form': form})
Validators
==========

View File

@ -136,9 +136,7 @@ Here's a typical usage example::
else:
return HttpResponse("Please enable cookies and try again.")
request.session.set_test_cookie()
t = template_loader.get_template("foo/login_form")
c = Context(request)
return HttpResponse(t.render(c))
return render_to_response('foo/login_form')
Using sessions out of views
===========================

View File

@ -569,25 +569,28 @@ Built-in filter reference
-------------------------
``add``
Adds the arg to the value
Adds the arg to the value.
``addslashes``
Adds slashes - useful for passing strings to JavaScript, for example.
Adds slashes. Useful for passing strings to JavaScript, for example.
``capfirst``
Capitalizes the first character of the value
Capitalizes the first character of the value.
``center``
Centers the value in a field of a given width
Centers the value in a field of a given width.
``cut``
Removes all values of arg from the given string
Removes all values of arg from the given string.
``date``
Formats a date according to the given format (same as the ``now`` tag)
Formats a date according to the given format (same as the ``now`` tag).
``default``
If value is unavailable, use given default
If value is unavailable, use given default.
``default_if_none``
If value is ``None``, use given default.
``dictsort``
Takes a list of dicts, returns that list sorted by the property given in the
@ -598,24 +601,24 @@ Built-in filter reference
given in the argument.
``divisibleby``
Returns true if the value is divisible by the argument
Returns true if the value is divisible by the argument.
``escape``
Escapes a string's HTML
Escapes a string's HTML.
``filesizeformat``
Format the value like a 'human-readable' file size (i.e. 13 KB, 4.1 MB, 102
bytes, etc).
``first``
Returns the first item in a list
Returns the first item in a list.
``fix_ampersands``
Replaces ampersands with ``&amp;`` entities
Replaces ampersands with ``&amp;`` entities.
``floatformat``
Displays a floating point number as 34.2 (with one decimal places) - but
only if there's a point to be displayed
only if there's a point to be displayed.
``get_digit``
Given a whole number, returns the requested digit of it, where 1 is the
@ -624,52 +627,52 @@ Built-in filter reference
or if argument is less than 1). Otherwise, output is always an integer.
``join``
Joins a list with a string, like Python's ``str.join(list)``
Joins a list with a string, like Python's ``str.join(list)``.
``length``
Returns the length of the value - useful for lists
Returns the length of the value. Useful for lists.
``length_is``
Returns a boolean of whether the value's length is the argument
Returns a boolean of whether the value's length is the argument.
``linebreaks``
Converts newlines into <p> and <br />s
Converts newlines into <p> and <br />s.
``linebreaksbr``
Converts newlines into <br />s
Converts newlines into <br />s.
``linenumbers``
Displays text with line numbers
Displays text with line numbers.
``ljust``
Left-aligns the value in a field of a given width
Left-aligns the value in a field of a given width.
**Argument:** field size
``lower``
Converts a string into all lowercase
Converts a string into all lowercase.
``make_list``
Returns the value turned into a list. For an integer, it's a list of
digits. For a string, it's a list of characters.
``phone2numeric``
Takes a phone number and converts it in to its numerical equivalent
Takes a phone number and converts it in to its numerical equivalent.
``pluralize``
Returns 's' if the value is not 1, for '1 vote' vs. '2 votes'
Returns 's' if the value is not 1, for '1 vote' vs. '2 votes'.
``pprint``
A wrapper around pprint.pprint -- for debugging, really
A wrapper around pprint.pprint -- for debugging, really.
``random``
Returns a random item from the list
Returns a random item from the list.
``removetags``
Removes a space separated list of [X]HTML tags from the output
Removes a space separated list of [X]HTML tags from the output.
``rjust``
Right-aligns the value in a field of a given width
Right-aligns the value in a field of a given width.
**Argument:** field size
@ -696,19 +699,19 @@ Built-in filter reference
of Python string formatting
``striptags``
Strips all [X]HTML tags
Strips all [X]HTML tags.
``time``
Formats a time according to the given format (same as the ``now`` tag).
``timesince``
Formats a date as the time since that date (i.e. "4 days, 6 hours")
Formats a date as the time since that date (i.e. "4 days, 6 hours").
``title``
Converts a string into titlecase
Converts a string into titlecase.
``truncatewords``
Truncates a string after a certain number of words
Truncates a string after a certain number of words.
**Argument:** Number of words to truncate after
@ -733,26 +736,27 @@ Built-in filter reference
</li>
``upper``
Converts a string into all uppercase
Converts a string into all uppercase.
``urlencode``
Escapes a value for use in a URL
Escapes a value for use in a URL.
``urlize``
Converts URLs in plain text into clickable links
Converts URLs in plain text into clickable links.
``urlizetrunc``
Converts URLs into clickable links, truncating URLs to the given character limit
Converts URLs into clickable links, truncating URLs to the given character
limit.
**Argument:** Length to truncate URLs to.
**Argument:** Length to truncate URLs to
``wordcount``
Returns the number of words
Returns the number of words.
``wordwrap``
Wraps words at specified line length
Wraps words at specified line length.
**Argument:** number of words to wrap the text at.
**Argument:** number of words at which to wrap the text
``yesno``
Given a string mapping values for true, false and (optionally) None,

View File

@ -307,12 +307,12 @@ The Python API
Django has two ways to load templates from files:
``django.core.template_loader.get_template(template_name)``
``django.core.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.core.template.TemplateDoesNotExist``.
``django.core.template_loader.select_template(template_name_list)``
``django.core.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.
@ -398,8 +398,8 @@ Python code, depending on whether you're writing filters or tags.
.. admonition:: Behind the scenes
For a ton of examples, read the source code for Django's default filters
and tags. They're in ``django/core/defaultfilters.py`` and
``django/core/defaulttags.py``, respectively.
and tags. They're in ``django/core/template/defaultfilters.py`` and
``django/core/template/defaulttags.py``, respectively.
Writing custom template filters
-------------------------------
@ -710,4 +710,4 @@ 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 %}``, ``{% ifequal %}`` and ``{% ifchanged %}``. They live in
``django/core/defaulttags.py``.
``django/core/template/defaulttags.py``.

View File

@ -191,14 +191,13 @@ There's a problem here, though: The page's design is hard-coded in the view. If
you want to change the way the page looks, you'll have to edit this Python code.
So let's use Django's template system to separate the design from Python::
from django.core import template_loader
from django.core.template import Context
from django.core.template import Context, loader
from django.models.polls import polls
from django.utils.httpwrappers import HttpResponse
def index(request):
latest_poll_list = polls.get_list(order_by=['-pub_date'], limit=5)
t = template_loader.get_template('polls/index')
t = loader.get_template('polls/index')
c = Context({
'latest_poll_list': latest_poll_list,
})
@ -224,7 +223,7 @@ and feel" section of Tutorial 2.
When you've done that, create a directory ``polls`` in your template directory.
Within that, create a file called ``index.html``. Django requires that
templates have ".html" extension. Note that our
``template_loader.get_template('polls/index')`` code from above maps to
``loader.get_template('polls/index')`` code from above maps to
"[template_directory]/polls/index.html" on the filesystem.
Put the following code in that template::
@ -256,7 +255,7 @@ provides a shortcut. Here's the full ``index()`` view, rewritten::
latest_poll_list = polls.get_list(order_by=['-pub_date'], limit=5)
return render_to_response('polls/index', {'latest_poll_list': latest_poll_list})
Note that we no longer need to import ``template_loader``, ``Context`` or
Note that we no longer need to import ``loader``, ``Context`` or
``HttpResponse``.
The ``render_to_response()`` function takes a template name as its first

View File

@ -197,8 +197,8 @@ objects" and "display a detail page for a particular type of object."
By default, the ``object_detail`` generic view uses a template called
``<app_label>/<module_name>_detail``. In our case, it'll use the template
``"polls/polls_detail"``. Thus, rename your ``polls/detail.html`` template to
``polls/polls_detail.html``, and change the ``template_loader.get_template()``
line in ``vote()``.
``polls/polls_detail.html``, and change the ``render_to_response()`` line in
``vote()``.
Similarly, the ``object_list`` generic view uses a template called
``<app_label>/<module_name>_list``. Thus, rename ``polls/index.html`` to

View File

@ -1,4 +1,5 @@
from django.core import template, template_loader
from django.core import template
from django.core.template import loader
from django.utils.translation import activate, deactivate
# Helper objects for template tests
@ -259,7 +260,7 @@ TEMPLATE_TESTS = {
'i18n14': ('{{ bool|yesno:"ja,nein" }}', {'bool': True}, 'ja'),
}
# This replaces the standard template_loader.
# This replaces the standard template loader.
def test_template_loader(template_name, template_dirs=None):
try:
return TEMPLATE_TESTS[template_name][0]
@ -267,7 +268,7 @@ def test_template_loader(template_name, template_dirs=None):
raise template.TemplateDoesNotExist, template_name
def run_tests(verbosity=0, standalone=False):
template_loader.load_template_source, old_template_loader = test_template_loader, template_loader.load_template_source
loader.load_template_source, old_template_loader = test_template_loader, loader.load_template_source
failed_tests = []
tests = TEMPLATE_TESTS.items()
tests.sort()
@ -275,7 +276,7 @@ def run_tests(verbosity=0, standalone=False):
if 'LANGUAGE_CODE' in vals[1]:
activate('*', vals[1]['LANGUAGE_CODE'])
try:
output = template_loader.get_template(name).render(template.Context(vals[1]))
output = loader.get_template(name).render(template.Context(vals[1]))
except Exception, e:
if e.__class__ == vals[2]:
if verbosity:
@ -294,7 +295,7 @@ def run_tests(verbosity=0, standalone=False):
if verbosity:
print "Template test: %s -- FAILED. Expected %r, got %r" % (name, vals[2], output)
failed_tests.append(name)
template_loader.load_template_source = old_template_loader
loader.load_template_source = old_template_loader
if failed_tests and not standalone:
msg = "Template tests %s failed." % failed_tests