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:
commit
2a2e2fb6aa
@ -59,7 +59,8 @@ DATABASE_ENGINE = 'postgresql' # 'postgresql', 'mysql', or 'sqlite3'.
|
|||||||
DATABASE_NAME = ''
|
DATABASE_NAME = ''
|
||||||
DATABASE_USER = ''
|
DATABASE_USER = ''
|
||||||
DATABASE_PASSWORD = ''
|
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.
|
# Host for sending e-mail.
|
||||||
EMAIL_HOST = 'localhost'
|
EMAIL_HOST = 'localhost'
|
||||||
|
@ -15,6 +15,7 @@ DATABASE_NAME = '' # Or path to database file if using sqlite3.
|
|||||||
DATABASE_USER = '' # Not used with sqlite3.
|
DATABASE_USER = '' # Not used with sqlite3.
|
||||||
DATABASE_PASSWORD = '' # Not used with sqlite3.
|
DATABASE_PASSWORD = '' # Not used with sqlite3.
|
||||||
DATABASE_HOST = '' # Set to empty string for localhost. 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
|
SITE_ID = 1
|
||||||
|
|
||||||
|
@ -53,10 +53,18 @@ class DatabaseWrapper:
|
|||||||
self.queries = []
|
self.queries = []
|
||||||
|
|
||||||
def cursor(self):
|
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:
|
if self.connection is None:
|
||||||
self.connection = Database.connect(user=DATABASE_USER, db=DATABASE_NAME,
|
kwargs = {
|
||||||
passwd=DATABASE_PASSWORD, host=DATABASE_HOST, conv=django_conversions)
|
'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:
|
if DEBUG:
|
||||||
return base.CursorDebugWrapper(MysqlDebugWrapper(self.connection.cursor()), self)
|
return base.CursorDebugWrapper(MysqlDebugWrapper(self.connection.cursor()), self)
|
||||||
return self.connection.cursor()
|
return self.connection.cursor()
|
||||||
|
@ -15,7 +15,7 @@ class DatabaseWrapper:
|
|||||||
self.queries = []
|
self.queries = []
|
||||||
|
|
||||||
def cursor(self):
|
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 self.connection is None:
|
||||||
if DATABASE_NAME == '':
|
if DATABASE_NAME == '':
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
@ -27,6 +27,8 @@ class DatabaseWrapper:
|
|||||||
conn_string += " password=%s" % DATABASE_PASSWORD
|
conn_string += " password=%s" % DATABASE_PASSWORD
|
||||||
if DATABASE_HOST:
|
if DATABASE_HOST:
|
||||||
conn_string += " host=%s" % 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 = Database.connect(conn_string)
|
||||||
self.connection.set_isolation_level(1) # make transactions transparent to all cursors
|
self.connection.set_isolation_level(1) # make transactions transparent to all cursors
|
||||||
cursor = self.connection.cursor()
|
cursor = self.connection.cursor()
|
||||||
|
@ -2,14 +2,13 @@
|
|||||||
# of MVC. In other words, these functions/classes introduce controlled coupling
|
# of MVC. In other words, these functions/classes introduce controlled coupling
|
||||||
# for convenience's sake.
|
# for convenience's sake.
|
||||||
|
|
||||||
from django.core import template_loader
|
|
||||||
from django.core.exceptions import Http404, ObjectDoesNotExist
|
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.conf.settings import DEBUG, INTERNAL_IPS
|
||||||
from django.utils.httpwrappers import HttpResponse
|
from django.utils.httpwrappers import HttpResponse
|
||||||
|
|
||||||
def render_to_response(*args, **kwargs):
|
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.
|
load_and_render = render_to_response # For backwards compatibility.
|
||||||
|
|
||||||
def get_object_or_404(mod, **kwargs):
|
def get_object_or_404(mod, **kwargs):
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
from django.core import template_loader
|
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
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.models.core import sites
|
||||||
from django.utils import feedgenerator
|
from django.utils import feedgenerator
|
||||||
from django.conf.settings import LANGUAGE_CODE, SETTINGS_MODULE
|
from django.conf.settings import LANGUAGE_CODE, SETTINGS_MODULE
|
||||||
@ -64,8 +63,8 @@ class FeedConfiguration:
|
|||||||
param = None
|
param = None
|
||||||
current_site = sites.get_current()
|
current_site = sites.get_current()
|
||||||
f = self._get_feed_generator_object(param)
|
f = self._get_feed_generator_object(param)
|
||||||
title_template = template_loader.get_template('rss/%s_title' % self.slug)
|
title_template = loader.get_template('rss/%s_title' % self.slug)
|
||||||
description_template = template_loader.get_template('rss/%s_description' % self.slug)
|
description_template = loader.get_template('rss/%s_description' % self.slug)
|
||||||
kwargs = self.get_list_kwargs.copy()
|
kwargs = self.get_list_kwargs.copy()
|
||||||
if param and self.get_list_kwargs_cb:
|
if param and self.get_list_kwargs_cb:
|
||||||
kwargs.update(self.get_list_kwargs_cb(param))
|
kwargs.update(self.get_list_kwargs_cb(param))
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
"Default variable filters"
|
"Default variable filters"
|
||||||
|
|
||||||
import template, re
|
from django.core.template import register_filter, resolve_variable
|
||||||
|
import re
|
||||||
import random as random_module
|
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
|
Takes a list of dicts, returns that list sorted by the property given in
|
||||||
the argument.
|
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.sort()
|
||||||
return [item[1] for item in decorated]
|
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
|
Takes a list of dicts, returns that list sorted in reverse order by the
|
||||||
property given in the argument.
|
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.sort()
|
||||||
decorated.reverse()
|
decorated.reverse()
|
||||||
return [item[1] for item in decorated]
|
return [item[1] for item in decorated]
|
||||||
@ -333,6 +334,12 @@ def default(value, arg):
|
|||||||
"If value is unavailable, use given default"
|
"If value is unavailable, use given default"
|
||||||
return value or arg
|
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):
|
def divisibleby(value, arg):
|
||||||
"Returns true if the value is devisible by the argument"
|
"Returns true if the value is devisible by the argument"
|
||||||
return int(value) % int(arg) == 0
|
return int(value) % int(arg) == 0
|
||||||
@ -408,51 +415,52 @@ def pprint(value, _):
|
|||||||
from pprint import pformat
|
from pprint import pformat
|
||||||
return pformat(value)
|
return pformat(value)
|
||||||
|
|
||||||
# Syntax: template.register_filter(name of filter, callback, has_argument)
|
# Syntax: register_filter(name of filter, callback, has_argument)
|
||||||
template.register_filter('add', add, True)
|
register_filter('add', add, True)
|
||||||
template.register_filter('addslashes', addslashes, False)
|
register_filter('addslashes', addslashes, False)
|
||||||
template.register_filter('capfirst', capfirst, False)
|
register_filter('capfirst', capfirst, False)
|
||||||
template.register_filter('center', center, True)
|
register_filter('center', center, True)
|
||||||
template.register_filter('cut', cut, True)
|
register_filter('cut', cut, True)
|
||||||
template.register_filter('date', date, True)
|
register_filter('date', date, True)
|
||||||
template.register_filter('default', default, True)
|
register_filter('default', default, True)
|
||||||
template.register_filter('dictsort', dictsort, True)
|
register_filter('default_if_none', default_if_none, True)
|
||||||
template.register_filter('dictsortreversed', dictsortreversed, True)
|
register_filter('dictsort', dictsort, True)
|
||||||
template.register_filter('divisibleby', divisibleby, True)
|
register_filter('dictsortreversed', dictsortreversed, True)
|
||||||
template.register_filter('escape', escape, False)
|
register_filter('divisibleby', divisibleby, True)
|
||||||
template.register_filter('filesizeformat', filesizeformat, False)
|
register_filter('escape', escape, False)
|
||||||
template.register_filter('first', first, False)
|
register_filter('filesizeformat', filesizeformat, False)
|
||||||
template.register_filter('fix_ampersands', fix_ampersands, False)
|
register_filter('first', first, False)
|
||||||
template.register_filter('floatformat', floatformat, False)
|
register_filter('fix_ampersands', fix_ampersands, False)
|
||||||
template.register_filter('get_digit', get_digit, True)
|
register_filter('floatformat', floatformat, False)
|
||||||
template.register_filter('join', join, True)
|
register_filter('get_digit', get_digit, True)
|
||||||
template.register_filter('length', length, False)
|
register_filter('join', join, True)
|
||||||
template.register_filter('length_is', length_is, True)
|
register_filter('length', length, False)
|
||||||
template.register_filter('linebreaks', linebreaks, False)
|
register_filter('length_is', length_is, True)
|
||||||
template.register_filter('linebreaksbr', linebreaksbr, False)
|
register_filter('linebreaks', linebreaks, False)
|
||||||
template.register_filter('linenumbers', linenumbers, False)
|
register_filter('linebreaksbr', linebreaksbr, False)
|
||||||
template.register_filter('ljust', ljust, True)
|
register_filter('linenumbers', linenumbers, False)
|
||||||
template.register_filter('lower', lower, False)
|
register_filter('ljust', ljust, True)
|
||||||
template.register_filter('make_list', make_list, False)
|
register_filter('lower', lower, False)
|
||||||
template.register_filter('phone2numeric', phone2numeric, False)
|
register_filter('make_list', make_list, False)
|
||||||
template.register_filter('pluralize', pluralize, False)
|
register_filter('phone2numeric', phone2numeric, False)
|
||||||
template.register_filter('pprint', pprint, False)
|
register_filter('pluralize', pluralize, False)
|
||||||
template.register_filter('removetags', removetags, True)
|
register_filter('pprint', pprint, False)
|
||||||
template.register_filter('random', random, False)
|
register_filter('removetags', removetags, True)
|
||||||
template.register_filter('rjust', rjust, True)
|
register_filter('random', random, False)
|
||||||
template.register_filter('slice', slice_, True)
|
register_filter('rjust', rjust, True)
|
||||||
template.register_filter('slugify', slugify, False)
|
register_filter('slice', slice_, True)
|
||||||
template.register_filter('stringformat', stringformat, True)
|
register_filter('slugify', slugify, False)
|
||||||
template.register_filter('striptags', striptags, False)
|
register_filter('stringformat', stringformat, True)
|
||||||
template.register_filter('time', time, True)
|
register_filter('striptags', striptags, False)
|
||||||
template.register_filter('timesince', timesince, False)
|
register_filter('time', time, True)
|
||||||
template.register_filter('title', title, False)
|
register_filter('timesince', timesince, False)
|
||||||
template.register_filter('truncatewords', truncatewords, True)
|
register_filter('title', title, False)
|
||||||
template.register_filter('unordered_list', unordered_list, False)
|
register_filter('truncatewords', truncatewords, True)
|
||||||
template.register_filter('upper', upper, False)
|
register_filter('unordered_list', unordered_list, False)
|
||||||
template.register_filter('urlencode', urlencode, False)
|
register_filter('upper', upper, False)
|
||||||
template.register_filter('urlize', urlize, False)
|
register_filter('urlencode', urlencode, False)
|
||||||
template.register_filter('urlizetrunc', urlizetrunc, True)
|
register_filter('urlize', urlize, False)
|
||||||
template.register_filter('wordcount', wordcount, False)
|
register_filter('urlizetrunc', urlizetrunc, True)
|
||||||
template.register_filter('wordwrap', wordwrap, True)
|
register_filter('wordcount', wordcount, False)
|
||||||
template.register_filter('yesno', yesno, True)
|
register_filter('wordwrap', wordwrap, True)
|
||||||
|
register_filter('yesno', yesno, True)
|
@ -1,16 +1,14 @@
|
|||||||
"Default tags used by the template system, available to all templates."
|
"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 sys
|
||||||
import template
|
|
||||||
|
|
||||||
from django.utils import translation
|
class CommentNode(Node):
|
||||||
|
|
||||||
class CommentNode(template.Node):
|
|
||||||
def render(self, context):
|
def render(self, context):
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
class CycleNode(template.Node):
|
class CycleNode(Node):
|
||||||
def __init__(self, cyclevars):
|
def __init__(self, cyclevars):
|
||||||
self.cyclevars = cyclevars
|
self.cyclevars = cyclevars
|
||||||
self.cyclevars_len = len(cyclevars)
|
self.cyclevars_len = len(cyclevars)
|
||||||
@ -20,7 +18,7 @@ class CycleNode(template.Node):
|
|||||||
self.counter += 1
|
self.counter += 1
|
||||||
return self.cyclevars[self.counter % self.cyclevars_len]
|
return self.cyclevars[self.counter % self.cyclevars_len]
|
||||||
|
|
||||||
class DebugNode(template.Node):
|
class DebugNode(Node):
|
||||||
def render(self, context):
|
def render(self, context):
|
||||||
from pprint import pformat
|
from pprint import pformat
|
||||||
output = [pformat(val) for val in context]
|
output = [pformat(val) for val in context]
|
||||||
@ -28,7 +26,7 @@ class DebugNode(template.Node):
|
|||||||
output.append(pformat(sys.modules))
|
output.append(pformat(sys.modules))
|
||||||
return ''.join(output)
|
return ''.join(output)
|
||||||
|
|
||||||
class FilterNode(template.Node):
|
class FilterNode(Node):
|
||||||
def __init__(self, filters, nodelist):
|
def __init__(self, filters, nodelist):
|
||||||
self.filters, self.nodelist = filters, nodelist
|
self.filters, self.nodelist = filters, nodelist
|
||||||
|
|
||||||
@ -36,21 +34,21 @@ class FilterNode(template.Node):
|
|||||||
output = self.nodelist.render(context)
|
output = self.nodelist.render(context)
|
||||||
# apply filters
|
# apply filters
|
||||||
for f in self.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
|
return output
|
||||||
|
|
||||||
class FirstOfNode(template.Node):
|
class FirstOfNode(Node):
|
||||||
def __init__(self, vars):
|
def __init__(self, vars):
|
||||||
self.vars = vars
|
self.vars = vars
|
||||||
|
|
||||||
def render(self, context):
|
def render(self, context):
|
||||||
for var in self.vars:
|
for var in self.vars:
|
||||||
value = template.resolve_variable(var, context)
|
value = resolve_variable(var, context)
|
||||||
if value:
|
if value:
|
||||||
return str(value)
|
return str(value)
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
class ForNode(template.Node):
|
class ForNode(Node):
|
||||||
def __init__(self, loopvar, sequence, reversed, nodelist_loop):
|
def __init__(self, loopvar, sequence, reversed, nodelist_loop):
|
||||||
self.loopvar, self.sequence = loopvar, sequence
|
self.loopvar, self.sequence = loopvar, sequence
|
||||||
self.reversed = reversed
|
self.reversed = reversed
|
||||||
@ -76,15 +74,15 @@ class ForNode(template.Node):
|
|||||||
return nodes
|
return nodes
|
||||||
|
|
||||||
def render(self, context):
|
def render(self, context):
|
||||||
nodelist = template.NodeList()
|
nodelist = NodeList()
|
||||||
if context.has_key('forloop'):
|
if context.has_key('forloop'):
|
||||||
parentloop = context['forloop']
|
parentloop = context['forloop']
|
||||||
else:
|
else:
|
||||||
parentloop = {}
|
parentloop = {}
|
||||||
context.push()
|
context.push()
|
||||||
try:
|
try:
|
||||||
values = template.resolve_variable_with_filters(self.sequence, context)
|
values = resolve_variable_with_filters(self.sequence, context)
|
||||||
except template.VariableDoesNotExist:
|
except VariableDoesNotExist:
|
||||||
values = []
|
values = []
|
||||||
if values is None:
|
if values is None:
|
||||||
values = []
|
values = []
|
||||||
@ -114,7 +112,7 @@ class ForNode(template.Node):
|
|||||||
context.pop()
|
context.pop()
|
||||||
return nodelist.render(context)
|
return nodelist.render(context)
|
||||||
|
|
||||||
class IfChangedNode(template.Node):
|
class IfChangedNode(Node):
|
||||||
def __init__(self, nodelist):
|
def __init__(self, nodelist):
|
||||||
self.nodelist = nodelist
|
self.nodelist = nodelist
|
||||||
self._last_seen = None
|
self._last_seen = None
|
||||||
@ -132,7 +130,7 @@ class IfChangedNode(template.Node):
|
|||||||
else:
|
else:
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
class IfEqualNode(template.Node):
|
class IfEqualNode(Node):
|
||||||
def __init__(self, var1, var2, nodelist_true, nodelist_false, negate):
|
def __init__(self, var1, var2, nodelist_true, nodelist_false, negate):
|
||||||
self.var1, self.var2 = var1, var2
|
self.var1, self.var2 = var1, var2
|
||||||
self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false
|
self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false
|
||||||
@ -142,13 +140,13 @@ class IfEqualNode(template.Node):
|
|||||||
return "<IfEqualNode>"
|
return "<IfEqualNode>"
|
||||||
|
|
||||||
def render(self, context):
|
def render(self, context):
|
||||||
val1 = template.resolve_variable(self.var1, context)
|
val1 = resolve_variable(self.var1, context)
|
||||||
val2 = template.resolve_variable(self.var2, context)
|
val2 = resolve_variable(self.var2, context)
|
||||||
if (self.negate and val1 != val2) or (not self.negate and val1 == val2):
|
if (self.negate and val1 != val2) or (not self.negate and val1 == val2):
|
||||||
return self.nodelist_true.render(context)
|
return self.nodelist_true.render(context)
|
||||||
return self.nodelist_false.render(context)
|
return self.nodelist_false.render(context)
|
||||||
|
|
||||||
class IfNode(template.Node):
|
class IfNode(Node):
|
||||||
def __init__(self, boolvars, nodelist_true, nodelist_false):
|
def __init__(self, boolvars, nodelist_true, nodelist_false):
|
||||||
self.boolvars = boolvars
|
self.boolvars = boolvars
|
||||||
self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false
|
self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false
|
||||||
@ -173,27 +171,27 @@ class IfNode(template.Node):
|
|||||||
def render(self, context):
|
def render(self, context):
|
||||||
for ifnot, boolvar in self.boolvars:
|
for ifnot, boolvar in self.boolvars:
|
||||||
try:
|
try:
|
||||||
value = template.resolve_variable_with_filters(boolvar, context)
|
value = resolve_variable_with_filters(boolvar, context)
|
||||||
except template.VariableDoesNotExist:
|
except VariableDoesNotExist:
|
||||||
value = None
|
value = None
|
||||||
if (value and not ifnot) or (ifnot and not value):
|
if (value and not ifnot) or (ifnot and not value):
|
||||||
return self.nodelist_true.render(context)
|
return self.nodelist_true.render(context)
|
||||||
return self.nodelist_false.render(context)
|
return self.nodelist_false.render(context)
|
||||||
|
|
||||||
class RegroupNode(template.Node):
|
class RegroupNode(Node):
|
||||||
def __init__(self, target_var, expression, var_name):
|
def __init__(self, target_var, expression, var_name):
|
||||||
self.target_var, self.expression = target_var, expression
|
self.target_var, self.expression = target_var, expression
|
||||||
self.var_name = var_name
|
self.var_name = var_name
|
||||||
|
|
||||||
def render(self, context):
|
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
|
if obj_list == '': # target_var wasn't found in context; fail silently
|
||||||
context[self.var_name] = []
|
context[self.var_name] = []
|
||||||
return ''
|
return ''
|
||||||
output = [] # list of dictionaries in the format {'grouper': 'key', 'list': [list of contents]}
|
output = [] # list of dictionaries in the format {'grouper': 'key', 'list': [list of contents]}
|
||||||
for obj in obj_list:
|
for obj in obj_list:
|
||||||
grouper = template.resolve_variable_with_filters('var.%s' % self.expression, \
|
grouper = resolve_variable_with_filters('var.%s' % self.expression, \
|
||||||
template.Context({'var': obj}))
|
Context({'var': obj}))
|
||||||
if output and repr(output[-1]['grouper']) == repr(grouper):
|
if output and repr(output[-1]['grouper']) == repr(grouper):
|
||||||
output[-1]['list'].append(obj)
|
output[-1]['list'].append(obj)
|
||||||
else:
|
else:
|
||||||
@ -208,7 +206,7 @@ def include_is_allowed(filepath):
|
|||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
class SsiNode(template.Node):
|
class SsiNode(Node):
|
||||||
def __init__(self, filepath, parsed):
|
def __init__(self, filepath, parsed):
|
||||||
self.filepath, self.parsed = filepath, parsed
|
self.filepath, self.parsed = filepath, parsed
|
||||||
|
|
||||||
@ -223,13 +221,13 @@ class SsiNode(template.Node):
|
|||||||
output = ''
|
output = ''
|
||||||
if self.parsed:
|
if self.parsed:
|
||||||
try:
|
try:
|
||||||
t = template.Template(output)
|
t = Template(output)
|
||||||
return t.render(context)
|
return t.render(context)
|
||||||
except template.TemplateSyntaxError:
|
except TemplateSyntaxError:
|
||||||
return '' # Fail silently for invalid included templates.
|
return '' # Fail silently for invalid included templates.
|
||||||
return output
|
return output
|
||||||
|
|
||||||
class LoadNode(template.Node):
|
class LoadNode(Node):
|
||||||
def __init__(self, taglib):
|
def __init__(self, taglib):
|
||||||
self.taglib = taglib
|
self.taglib = taglib
|
||||||
|
|
||||||
@ -247,7 +245,7 @@ class LoadNode(template.Node):
|
|||||||
pass # Fail silently for invalid loads.
|
pass # Fail silently for invalid loads.
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
class NowNode(template.Node):
|
class NowNode(Node):
|
||||||
def __init__(self, format_string):
|
def __init__(self, format_string):
|
||||||
self.format_string = format_string
|
self.format_string = format_string
|
||||||
|
|
||||||
@ -257,11 +255,11 @@ class NowNode(template.Node):
|
|||||||
df = DateFormat(datetime.now())
|
df = DateFormat(datetime.now())
|
||||||
return df.format(self.format_string)
|
return df.format(self.format_string)
|
||||||
|
|
||||||
class TemplateTagNode(template.Node):
|
class TemplateTagNode(Node):
|
||||||
mapping = {'openblock': template.BLOCK_TAG_START,
|
mapping = {'openblock': BLOCK_TAG_START,
|
||||||
'closeblock': template.BLOCK_TAG_END,
|
'closeblock': BLOCK_TAG_END,
|
||||||
'openvariable': template.VARIABLE_TAG_START,
|
'openvariable': VARIABLE_TAG_START,
|
||||||
'closevariable': template.VARIABLE_TAG_END}
|
'closevariable': VARIABLE_TAG_END}
|
||||||
|
|
||||||
def __init__(self, tagtype):
|
def __init__(self, tagtype):
|
||||||
self.tagtype = tagtype
|
self.tagtype = tagtype
|
||||||
@ -269,7 +267,7 @@ class TemplateTagNode(template.Node):
|
|||||||
def render(self, context):
|
def render(self, context):
|
||||||
return self.mapping.get(self.tagtype, '')
|
return self.mapping.get(self.tagtype, '')
|
||||||
|
|
||||||
class WidthRatioNode(template.Node):
|
class WidthRatioNode(Node):
|
||||||
def __init__(self, val_var, max_var, max_width):
|
def __init__(self, val_var, max_var, max_width):
|
||||||
self.val_var = val_var
|
self.val_var = val_var
|
||||||
self.max_var = max_var
|
self.max_var = max_var
|
||||||
@ -277,9 +275,9 @@ class WidthRatioNode(template.Node):
|
|||||||
|
|
||||||
def render(self, context):
|
def render(self, context):
|
||||||
try:
|
try:
|
||||||
value = template.resolve_variable_with_filters(self.val_var, context)
|
value = resolve_variable_with_filters(self.val_var, context)
|
||||||
maxvalue = template.resolve_variable_with_filters(self.max_var, context)
|
maxvalue = resolve_variable_with_filters(self.max_var, context)
|
||||||
except template.VariableDoesNotExist:
|
except VariableDoesNotExist:
|
||||||
return ''
|
return ''
|
||||||
try:
|
try:
|
||||||
value = float(value)
|
value = float(value)
|
||||||
@ -289,7 +287,7 @@ class WidthRatioNode(template.Node):
|
|||||||
return ''
|
return ''
|
||||||
return str(int(round(ratio)))
|
return str(int(round(ratio)))
|
||||||
|
|
||||||
class I18NNode(template.Node):
|
class I18NNode(Node):
|
||||||
|
|
||||||
def __init__(self, cmd):
|
def __init__(self, cmd):
|
||||||
self.cmd = cmd
|
self.cmd = cmd
|
||||||
@ -304,7 +302,7 @@ class I18NNode(template.Node):
|
|||||||
elif s.startswith('"') and s.endswith('"'):
|
elif s.startswith('"') and s.endswith('"'):
|
||||||
s = s[1:-1]
|
s = s[1:-1]
|
||||||
else:
|
else:
|
||||||
s = template.resolve_variable_with_filters(s, context)
|
s = resolve_variable_with_filters(s, context)
|
||||||
return s
|
return s
|
||||||
|
|
||||||
def render(self, context):
|
def render(self, context):
|
||||||
@ -317,14 +315,24 @@ class I18NNode(template.Node):
|
|||||||
elif f == 'gettext_noop':
|
elif f == 'gettext_noop':
|
||||||
return translation.gettext_noop(s) % context
|
return translation.gettext_noop(s) % context
|
||||||
else:
|
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)
|
m = self.ngettext_re.match(self.cmd)
|
||||||
if m:
|
if m:
|
||||||
singular = self._resolve_var(m.group(1), context)
|
singular = self._resolve_var(m.group(1), context)
|
||||||
plural = self._resolve_var(m.group(2), 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
|
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):
|
def do_comment(parser, token):
|
||||||
"""
|
"""
|
||||||
@ -370,7 +378,7 @@ def do_cycle(parser, token):
|
|||||||
|
|
||||||
args = token.contents.split()
|
args = token.contents.split()
|
||||||
if len(args) < 2:
|
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]:
|
elif len(args) == 2 and "," in args[1]:
|
||||||
# {% cycle a,b,c %}
|
# {% cycle a,b,c %}
|
||||||
@ -381,13 +389,13 @@ def do_cycle(parser, token):
|
|||||||
elif len(args) == 2:
|
elif len(args) == 2:
|
||||||
name = args[1]
|
name = args[1]
|
||||||
if not parser._namedCycleNodes.has_key(name):
|
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]
|
return parser._namedCycleNodes[name]
|
||||||
|
|
||||||
elif len(args) == 4:
|
elif len(args) == 4:
|
||||||
# {% cycle a,b,c as name %}
|
# {% cycle a,b,c as name %}
|
||||||
if args[2] != 'as':
|
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
|
cyclevars = [v for v in args[1].split(",") if v] # split and kill blanks
|
||||||
name = args[3]
|
name = args[3]
|
||||||
node = CycleNode(cyclevars)
|
node = CycleNode(cyclevars)
|
||||||
@ -399,7 +407,7 @@ def do_cycle(parser, token):
|
|||||||
return node
|
return node
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise template.TemplateSyntaxError("Invalid arguments to 'cycle': %s" % args)
|
raise TemplateSyntaxError("Invalid arguments to 'cycle': %s" % args)
|
||||||
|
|
||||||
def do_debug(parser, token):
|
def do_debug(parser, token):
|
||||||
"Print a whole load of debugging information, including the context and imported modules"
|
"Print a whole load of debugging information, including the context and imported modules"
|
||||||
@ -419,7 +427,7 @@ def do_filter(parser, token):
|
|||||||
{% endfilter %}
|
{% endfilter %}
|
||||||
"""
|
"""
|
||||||
_, rest = token.contents.split(None, 1)
|
_, 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',))
|
nodelist = parser.parse(('endfilter',))
|
||||||
parser.delete_first_token()
|
parser.delete_first_token()
|
||||||
return FilterNode(filters, nodelist)
|
return FilterNode(filters, nodelist)
|
||||||
@ -448,7 +456,7 @@ def do_firstof(parser, token):
|
|||||||
"""
|
"""
|
||||||
bits = token.contents.split()[1:]
|
bits = token.contents.split()[1:]
|
||||||
if len(bits) < 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)
|
return FirstOfNode(bits)
|
||||||
|
|
||||||
|
|
||||||
@ -487,11 +495,11 @@ def do_for(parser, token):
|
|||||||
"""
|
"""
|
||||||
bits = token.contents.split()
|
bits = token.contents.split()
|
||||||
if len(bits) == 5 and bits[4] != 'reversed':
|
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):
|
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':
|
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]
|
loopvar = bits[1]
|
||||||
sequence = bits[3]
|
sequence = bits[3]
|
||||||
reversed = (len(bits) == 5)
|
reversed = (len(bits) == 5)
|
||||||
@ -517,7 +525,7 @@ def do_ifequal(parser, token, negate):
|
|||||||
"""
|
"""
|
||||||
bits = token.contents.split()
|
bits = token.contents.split()
|
||||||
if len(bits) != 3:
|
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]
|
end_tag = 'end' + bits[0]
|
||||||
nodelist_true = parser.parse(('else', end_tag))
|
nodelist_true = parser.parse(('else', end_tag))
|
||||||
token = parser.next_token()
|
token = parser.next_token()
|
||||||
@ -525,7 +533,7 @@ def do_ifequal(parser, token, negate):
|
|||||||
nodelist_false = parser.parse((end_tag,))
|
nodelist_false = parser.parse((end_tag,))
|
||||||
parser.delete_first_token()
|
parser.delete_first_token()
|
||||||
else:
|
else:
|
||||||
nodelist_false = template.NodeList()
|
nodelist_false = NodeList()
|
||||||
return IfEqualNode(bits[1], bits[2], nodelist_true, nodelist_false, negate)
|
return IfEqualNode(bits[1], bits[2], nodelist_true, nodelist_false, negate)
|
||||||
|
|
||||||
def do_if(parser, token):
|
def do_if(parser, token):
|
||||||
@ -578,7 +586,7 @@ def do_if(parser, token):
|
|||||||
bits = token.contents.split()
|
bits = token.contents.split()
|
||||||
del bits[0]
|
del bits[0]
|
||||||
if not bits:
|
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']
|
# bits now looks something like this: ['a', 'or', 'not', 'b', 'or', 'c.d']
|
||||||
boolpairs = ' '.join(bits).split(' or ')
|
boolpairs = ' '.join(bits).split(' or ')
|
||||||
boolvars = []
|
boolvars = []
|
||||||
@ -586,7 +594,7 @@ def do_if(parser, token):
|
|||||||
if ' ' in boolpair:
|
if ' ' in boolpair:
|
||||||
not_, boolvar = boolpair.split()
|
not_, boolvar = boolpair.split()
|
||||||
if not_ != 'not':
|
if not_ != 'not':
|
||||||
raise template.TemplateSyntaxError, "Expected 'not' in if statement"
|
raise TemplateSyntaxError, "Expected 'not' in if statement"
|
||||||
boolvars.append((True, boolvar))
|
boolvars.append((True, boolvar))
|
||||||
else:
|
else:
|
||||||
boolvars.append((False, boolpair))
|
boolvars.append((False, boolpair))
|
||||||
@ -596,7 +604,7 @@ def do_if(parser, token):
|
|||||||
nodelist_false = parser.parse(('endif',))
|
nodelist_false = parser.parse(('endif',))
|
||||||
parser.delete_first_token()
|
parser.delete_first_token()
|
||||||
else:
|
else:
|
||||||
nodelist_false = template.NodeList()
|
nodelist_false = NodeList()
|
||||||
return IfNode(boolvars, nodelist_true, nodelist_false)
|
return IfNode(boolvars, nodelist_true, nodelist_false)
|
||||||
|
|
||||||
def do_ifchanged(parser, token):
|
def do_ifchanged(parser, token):
|
||||||
@ -616,7 +624,7 @@ def do_ifchanged(parser, token):
|
|||||||
"""
|
"""
|
||||||
bits = token.contents.split()
|
bits = token.contents.split()
|
||||||
if len(bits) != 1:
|
if len(bits) != 1:
|
||||||
raise template.TemplateSyntaxError, "'ifchanged' tag takes no arguments"
|
raise TemplateSyntaxError, "'ifchanged' tag takes no arguments"
|
||||||
nodelist = parser.parse(('endifchanged',))
|
nodelist = parser.parse(('endifchanged',))
|
||||||
parser.delete_first_token()
|
parser.delete_first_token()
|
||||||
return IfChangedNode(nodelist)
|
return IfChangedNode(nodelist)
|
||||||
@ -639,12 +647,12 @@ def do_ssi(parser, token):
|
|||||||
bits = token.contents.split()
|
bits = token.contents.split()
|
||||||
parsed = False
|
parsed = False
|
||||||
if len(bits) not in (2, 3):
|
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 len(bits) == 3:
|
||||||
if bits[2] == 'parsed':
|
if bits[2] == 'parsed':
|
||||||
parsed = True
|
parsed = True
|
||||||
else:
|
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)
|
return SsiNode(bits[1], parsed)
|
||||||
|
|
||||||
def do_load(parser, token):
|
def do_load(parser, token):
|
||||||
@ -657,13 +665,13 @@ def do_load(parser, token):
|
|||||||
"""
|
"""
|
||||||
bits = token.contents.split()
|
bits = token.contents.split()
|
||||||
if len(bits) != 2:
|
if len(bits) != 2:
|
||||||
raise template.TemplateSyntaxError, "'load' statement takes one argument"
|
raise TemplateSyntaxError, "'load' statement takes one argument"
|
||||||
taglib = bits[1]
|
taglib = bits[1]
|
||||||
# check at compile time that the module can be imported
|
# check at compile time that the module can be imported
|
||||||
try:
|
try:
|
||||||
LoadNode.load_taglib(taglib)
|
LoadNode.load_taglib(taglib)
|
||||||
except ImportError:
|
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)
|
return LoadNode(taglib)
|
||||||
|
|
||||||
def do_now(parser, token):
|
def do_now(parser, token):
|
||||||
@ -679,7 +687,7 @@ def do_now(parser, token):
|
|||||||
"""
|
"""
|
||||||
bits = token.contents.split('"')
|
bits = token.contents.split('"')
|
||||||
if len(bits) != 3:
|
if len(bits) != 3:
|
||||||
raise template.TemplateSyntaxError, "'now' statement takes one argument"
|
raise TemplateSyntaxError, "'now' statement takes one argument"
|
||||||
format_string = bits[1]
|
format_string = bits[1]
|
||||||
return NowNode(format_string)
|
return NowNode(format_string)
|
||||||
|
|
||||||
@ -731,13 +739,13 @@ def do_regroup(parser, token):
|
|||||||
"""
|
"""
|
||||||
firstbits = token.contents.split(None, 3)
|
firstbits = token.contents.split(None, 3)
|
||||||
if len(firstbits) != 4:
|
if len(firstbits) != 4:
|
||||||
raise template.TemplateSyntaxError, "'regroup' tag takes five arguments"
|
raise TemplateSyntaxError, "'regroup' tag takes five arguments"
|
||||||
target_var = firstbits[1]
|
target_var = firstbits[1]
|
||||||
if firstbits[2] != 'by':
|
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)
|
lastbits_reversed = firstbits[3][::-1].split(None, 2)
|
||||||
if lastbits_reversed[1][::-1] != 'as':
|
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]
|
expression = lastbits_reversed[2][::-1]
|
||||||
var_name = lastbits_reversed[0][::-1]
|
var_name = lastbits_reversed[0][::-1]
|
||||||
return RegroupNode(target_var, expression, var_name)
|
return RegroupNode(target_var, expression, var_name)
|
||||||
@ -762,10 +770,10 @@ def do_templatetag(parser, token):
|
|||||||
"""
|
"""
|
||||||
bits = token.contents.split()
|
bits = token.contents.split()
|
||||||
if len(bits) != 2:
|
if len(bits) != 2:
|
||||||
raise template.TemplateSyntaxError, "'templatetag' statement takes one argument"
|
raise TemplateSyntaxError, "'templatetag' statement takes one argument"
|
||||||
tag = bits[1]
|
tag = bits[1]
|
||||||
if not TemplateTagNode.mapping.has_key(tag):
|
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())
|
(tag, TemplateTagNode.mapping.keys())
|
||||||
return TemplateTagNode(tag)
|
return TemplateTagNode(tag)
|
||||||
|
|
||||||
@ -784,12 +792,12 @@ def do_widthratio(parser, token):
|
|||||||
"""
|
"""
|
||||||
bits = token.contents.split()
|
bits = token.contents.split()
|
||||||
if len(bits) != 4:
|
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
|
tag, this_value_var, max_value_var, max_width = bits
|
||||||
try:
|
try:
|
||||||
max_width = int(max_width)
|
max_width = int(max_width)
|
||||||
except ValueError:
|
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)
|
return WidthRatioNode(this_value_var, max_value_var, max_width)
|
||||||
|
|
||||||
def do_i18n(parser, token):
|
def do_i18n(parser, token):
|
||||||
@ -809,21 +817,20 @@ def do_i18n(parser, token):
|
|||||||
|
|
||||||
return I18NNode(args[1].strip())
|
return I18NNode(args[1].strip())
|
||||||
|
|
||||||
template.register_tag('comment', do_comment)
|
register_tag('comment', do_comment)
|
||||||
template.register_tag('cycle', do_cycle)
|
register_tag('cycle', do_cycle)
|
||||||
template.register_tag('debug', do_debug)
|
register_tag('debug', do_debug)
|
||||||
template.register_tag('filter', do_filter)
|
register_tag('filter', do_filter)
|
||||||
template.register_tag('firstof', do_firstof)
|
register_tag('firstof', do_firstof)
|
||||||
template.register_tag('for', do_for)
|
register_tag('for', do_for)
|
||||||
template.register_tag('ifequal', lambda parser, token: do_ifequal(parser, token, False))
|
register_tag('ifequal', lambda parser, token: do_ifequal(parser, token, False))
|
||||||
template.register_tag('ifnotequal', lambda parser, token: do_ifequal(parser, token, True))
|
register_tag('ifnotequal', lambda parser, token: do_ifequal(parser, token, True))
|
||||||
template.register_tag('if', do_if)
|
register_tag('if', do_if)
|
||||||
template.register_tag('ifchanged', do_ifchanged)
|
register_tag('ifchanged', do_ifchanged)
|
||||||
template.register_tag('regroup', do_regroup)
|
register_tag('regroup', do_regroup)
|
||||||
template.register_tag('ssi', do_ssi)
|
register_tag('ssi', do_ssi)
|
||||||
template.register_tag('load', do_load)
|
register_tag('load', do_load)
|
||||||
template.register_tag('now', do_now)
|
register_tag('now', do_now)
|
||||||
template.register_tag('templatetag', do_templatetag)
|
register_tag('templatetag', do_templatetag)
|
||||||
template.register_tag('widthratio', do_widthratio)
|
register_tag('widthratio', do_widthratio)
|
||||||
template.register_tag('i18n', do_i18n)
|
register_tag('i18n', do_i18n)
|
||||||
|
|
163
django/core/template/loader.py
Normal file
163
django/core/template/loader.py
Normal 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)
|
0
django/core/template/loaders/__init__.py
Normal file
0
django/core/template/loaders/__init__.py
Normal 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.conf.settings import TEMPLATE_DIRS, TEMPLATE_FILE_EXTENSION
|
||||||
from django.core.template import TemplateDoesNotExist
|
from django.core.template import TemplateDoesNotExist
|
@ -1,162 +1,7 @@
|
|||||||
"Wrapper for loading templates from storage of some sort (e.g. files or db)"
|
# This module is DEPRECATED!
|
||||||
import template
|
#
|
||||||
from template_file import load_template_source
|
# You should no longer be using django.core.template_loader.
|
||||||
|
#
|
||||||
|
# Use django.core.template.loader instead.
|
||||||
|
|
||||||
class ExtendsError(Exception):
|
from django.core.template.loader import *
|
||||||
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)
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
from django.utils import httpwrappers
|
from django.utils import httpwrappers
|
||||||
from django.core import template_loader
|
from django.core.extensions import DjangoContext
|
||||||
from django.core.extensions import DjangoContext as Context
|
from django.core.extensions import render_to_response
|
||||||
from django.models.auth import users
|
from django.models.auth import users
|
||||||
from django.views.registration import passwords
|
from django.views.registration import passwords
|
||||||
from django.views.auth.login import logout
|
from django.views.auth.login import logout
|
||||||
@ -96,14 +96,12 @@ class AdminUserRequired:
|
|||||||
post_data = encode_post_data(request.POST)
|
post_data = encode_post_data(request.POST)
|
||||||
else:
|
else:
|
||||||
post_data = encode_post_data({})
|
post_data = encode_post_data({})
|
||||||
t = template_loader.get_template(self.get_login_template_name())
|
return render_to_response(self.get_login_template_name(), {
|
||||||
c = Context(request, {
|
|
||||||
'title': 'Log in',
|
'title': 'Log in',
|
||||||
'app_path': request.path,
|
'app_path': request.path,
|
||||||
'post_data': post_data,
|
'post_data': post_data,
|
||||||
'error_message': error_message
|
'error_message': error_message
|
||||||
})
|
}, context_instance=DjangoContext(request))
|
||||||
return httpwrappers.HttpResponse(t.render(c))
|
|
||||||
|
|
||||||
def authenticate_user(self, user, password):
|
def authenticate_user(self, user, password):
|
||||||
return user.check_password(password) and user.is_staff
|
return user.check_password(password) and user.is_staff
|
||||||
|
@ -4,7 +4,8 @@ from django.conf import settings
|
|||||||
from django.models.core import sites
|
from django.models.core import sites
|
||||||
from django.core.extensions import DjangoContext, render_to_response
|
from django.core.extensions import DjangoContext, render_to_response
|
||||||
from django.core.exceptions import Http404, ViewDoesNotExist
|
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:
|
try:
|
||||||
from django.parts.admin import doc
|
from django.parts.admin import doc
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
@ -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 import template
|
||||||
|
from django.core.template import loader
|
||||||
from django.core.extensions import DjangoContext, render_to_response
|
from django.core.extensions import DjangoContext, render_to_response
|
||||||
from django.models.core import sites
|
from django.models.core import sites
|
||||||
from django.conf import settings
|
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
|
# so that inheritance works in the site's context, register a new function
|
||||||
# for "extends" that uses the site's TEMPLATE_DIR instead
|
# for "extends" that uses the site's TEMPLATE_DIR instead
|
||||||
def new_do_extends(parser, token):
|
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
|
node.template_dirs = settings_module.TEMPLATE_DIRS
|
||||||
return node
|
return node
|
||||||
template.register_tag('extends', new_do_extends)
|
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
|
# making sure to reset the extends function in any case
|
||||||
error = None
|
error = None
|
||||||
try:
|
try:
|
||||||
tmpl = template_loader.get_template_from_string(field_data)
|
tmpl = loader.get_template_from_string(field_data)
|
||||||
tmpl.render(template.Context({}))
|
tmpl.render(template.Context({}))
|
||||||
except template.TemplateSyntaxError, e:
|
except template.TemplateSyntaxError, e:
|
||||||
error = e
|
error = e
|
||||||
template.register_tag('extends', template_loader.do_extends)
|
template.register_tag('extends', loader.do_extends)
|
||||||
if error:
|
if error:
|
||||||
raise validators.ValidationError, e.args
|
raise validators.ValidationError, e.args
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
from django.parts.auth.formfields import AuthenticationForm
|
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.core.extensions import DjangoContext, render_to_response
|
||||||
from django.models.auth import users
|
from django.models.auth import users
|
||||||
from django.models.core import sites
|
from django.models.core import sites
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
from django.core import template_loader
|
|
||||||
from django.core.exceptions import Http404, ObjectDoesNotExist
|
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.models.core import sites
|
||||||
from django.utils import httpwrappers
|
from django.utils import httpwrappers
|
||||||
|
|
||||||
@ -56,7 +55,7 @@ def page_not_found(request):
|
|||||||
if r == '':
|
if r == '':
|
||||||
return httpwrappers.HttpResponseGone()
|
return httpwrappers.HttpResponseGone()
|
||||||
return httpwrappers.HttpResponseRedirect(r.new_path)
|
return httpwrappers.HttpResponseRedirect(r.new_path)
|
||||||
t = template_loader.get_template('404')
|
t = loader.get_template('404')
|
||||||
c = Context()
|
c = Context()
|
||||||
return httpwrappers.HttpResponseNotFound(t.render(c))
|
return httpwrappers.HttpResponseNotFound(t.render(c))
|
||||||
|
|
||||||
@ -67,6 +66,6 @@ def server_error(request):
|
|||||||
Templates: `500`
|
Templates: `500`
|
||||||
Context: None
|
Context: None
|
||||||
"""
|
"""
|
||||||
t = template_loader.get_template('500')
|
t = loader.get_template('500')
|
||||||
c = Context()
|
c = Context()
|
||||||
return httpwrappers.HttpResponseServerError(t.render(c))
|
return httpwrappers.HttpResponseServerError(t.render(c))
|
||||||
|
@ -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.extensions import DjangoContext, render_to_response
|
||||||
|
from django.core.template import loader
|
||||||
from django.models.auth import users
|
from django.models.auth import users
|
||||||
from django.views.decorators.auth import login_required
|
from django.views.decorators.auth import login_required
|
||||||
from django.utils.httpwrappers import HttpResponseRedirect
|
from django.utils.httpwrappers import HttpResponseRedirect
|
||||||
@ -32,7 +33,7 @@ class PasswordResetForm(formfields.Manipulator):
|
|||||||
domain = current_site.domain
|
domain = current_site.domain
|
||||||
else:
|
else:
|
||||||
site_name = domain = domain_override
|
site_name = domain = domain_override
|
||||||
t = template_loader.get_template('registration/password_reset_email')
|
t = loader.get_template('registration/password_reset_email')
|
||||||
c = {
|
c = {
|
||||||
'new_password': new_pass,
|
'new_password': new_pass,
|
||||||
'email': self.user_cache.email,
|
'email': self.user_cache.email,
|
||||||
|
244
docs/design_philosophies.txt
Normal file
244
docs/design_philosophies.txt
Normal 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.
|
@ -65,9 +65,8 @@ Using the ``AddManipulator``
|
|||||||
We'll start with the ``AddManipulator``. Here's a very simple view that takes
|
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::
|
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.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.utils.httpwrappers import HttpResponse, HttpResponseRedirect
|
||||||
from django.models.places import places
|
from django.models.places import places
|
||||||
from django.core import formfields
|
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
|
# Create a FormWrapper object that the template can use. Ignore
|
||||||
# the last two arguments to FormWrapper for now.
|
# the last two arguments to FormWrapper for now.
|
||||||
form = formfields.FormWrapper(places.AddManipulator(), {}, {})
|
form = formfields.FormWrapper(places.AddManipulator(), {}, {})
|
||||||
|
return render_to_response('places/naive_create_form', {'form': form})
|
||||||
# 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))
|
|
||||||
|
|
||||||
(This view, as well as all the following ones, has the same imports as in the
|
(This view, as well as all the following ones, has the same imports as in the
|
||||||
first example above.)
|
first example above.)
|
||||||
@ -169,11 +162,7 @@ creation view that takes validation into account::
|
|||||||
# Check for validation errors
|
# Check for validation errors
|
||||||
errors = manipulator.get_validation_errors(new_data)
|
errors = manipulator.get_validation_errors(new_data)
|
||||||
if errors:
|
if errors:
|
||||||
t = template_loader.get_template('places/errors')
|
return render_to_response('places/errors', {'errors': errors})
|
||||||
c = Context(request, {
|
|
||||||
'errors': errors
|
|
||||||
}
|
|
||||||
return HttpResponse(t.render(c))
|
|
||||||
else:
|
else:
|
||||||
manipulator.do_html2python(request.POST)
|
manipulator.do_html2python(request.POST)
|
||||||
new_place = manipulator.save(request.POST)
|
new_place = manipulator.save(request.POST)
|
||||||
@ -245,11 +234,7 @@ Below is the finished view::
|
|||||||
|
|
||||||
# Create the FormWrapper, template, context, response.
|
# Create the FormWrapper, template, context, response.
|
||||||
form = formfields.FormWrapper(manipulator, new_data, errors)
|
form = formfields.FormWrapper(manipulator, new_data, errors)
|
||||||
t = template_loader.get_template("places/create_form")
|
return render_to_response('places/create_form', {'form': form})
|
||||||
c = Context(request, {
|
|
||||||
'form': form,
|
|
||||||
})
|
|
||||||
return HttpResponse(t.render(c))
|
|
||||||
|
|
||||||
and here's the ``create_form`` template::
|
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__
|
new_data = place.__dict__
|
||||||
|
|
||||||
form = formfields.FormWrapper(manipulator, new_data, errors)
|
form = formfields.FormWrapper(manipulator, new_data, errors)
|
||||||
t = template_loader.get_template("places/edit_form")
|
return render_to_response('places/edit_form', {'form': form, 'place': place})
|
||||||
c = Context(request, {
|
|
||||||
'form': form,
|
|
||||||
'place': place,
|
|
||||||
})
|
|
||||||
return HttpResponse(t.render(c))
|
|
||||||
|
|
||||||
The only real differences are:
|
The only real differences are:
|
||||||
|
|
||||||
@ -422,11 +402,7 @@ Here's a simple function that might drive the above form::
|
|||||||
else:
|
else:
|
||||||
errors = new_data = {}
|
errors = new_data = {}
|
||||||
form = formfields.FormWrapper(manipulator, new_data, errors)
|
form = formfields.FormWrapper(manipulator, new_data, errors)
|
||||||
t = template_loader.get_template("contact_form")
|
return render_to_response('contact_form', {'form': form})
|
||||||
c = Context(request, {
|
|
||||||
'form': form,
|
|
||||||
})
|
|
||||||
return HttpResponse(t.render(c))
|
|
||||||
|
|
||||||
Validators
|
Validators
|
||||||
==========
|
==========
|
||||||
|
@ -136,9 +136,7 @@ Here's a typical usage example::
|
|||||||
else:
|
else:
|
||||||
return HttpResponse("Please enable cookies and try again.")
|
return HttpResponse("Please enable cookies and try again.")
|
||||||
request.session.set_test_cookie()
|
request.session.set_test_cookie()
|
||||||
t = template_loader.get_template("foo/login_form")
|
return render_to_response('foo/login_form')
|
||||||
c = Context(request)
|
|
||||||
return HttpResponse(t.render(c))
|
|
||||||
|
|
||||||
Using sessions out of views
|
Using sessions out of views
|
||||||
===========================
|
===========================
|
||||||
|
@ -569,25 +569,28 @@ Built-in filter reference
|
|||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
``add``
|
``add``
|
||||||
Adds the arg to the value
|
Adds the arg to the value.
|
||||||
|
|
||||||
``addslashes``
|
``addslashes``
|
||||||
Adds slashes - useful for passing strings to JavaScript, for example.
|
Adds slashes. Useful for passing strings to JavaScript, for example.
|
||||||
|
|
||||||
``capfirst``
|
``capfirst``
|
||||||
Capitalizes the first character of the value
|
Capitalizes the first character of the value.
|
||||||
|
|
||||||
``center``
|
``center``
|
||||||
Centers the value in a field of a given width
|
Centers the value in a field of a given width.
|
||||||
|
|
||||||
``cut``
|
``cut``
|
||||||
Removes all values of arg from the given string
|
Removes all values of arg from the given string.
|
||||||
|
|
||||||
``date``
|
``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``
|
``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``
|
``dictsort``
|
||||||
Takes a list of dicts, returns that list sorted by the property given in the
|
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.
|
given in the argument.
|
||||||
|
|
||||||
``divisibleby``
|
``divisibleby``
|
||||||
Returns true if the value is divisible by the argument
|
Returns true if the value is divisible by the argument.
|
||||||
|
|
||||||
``escape``
|
``escape``
|
||||||
Escapes a string's HTML
|
Escapes a string's HTML.
|
||||||
|
|
||||||
``filesizeformat``
|
``filesizeformat``
|
||||||
Format the value like a 'human-readable' file size (i.e. 13 KB, 4.1 MB, 102
|
Format the value like a 'human-readable' file size (i.e. 13 KB, 4.1 MB, 102
|
||||||
bytes, etc).
|
bytes, etc).
|
||||||
|
|
||||||
``first``
|
``first``
|
||||||
Returns the first item in a list
|
Returns the first item in a list.
|
||||||
|
|
||||||
``fix_ampersands``
|
``fix_ampersands``
|
||||||
Replaces ampersands with ``&`` entities
|
Replaces ampersands with ``&`` entities.
|
||||||
|
|
||||||
``floatformat``
|
``floatformat``
|
||||||
Displays a floating point number as 34.2 (with one decimal places) - but
|
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``
|
``get_digit``
|
||||||
Given a whole number, returns the requested digit of it, where 1 is the
|
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.
|
or if argument is less than 1). Otherwise, output is always an integer.
|
||||||
|
|
||||||
``join``
|
``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``
|
``length``
|
||||||
Returns the length of the value - useful for lists
|
Returns the length of the value. Useful for lists.
|
||||||
|
|
||||||
``length_is``
|
``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``
|
``linebreaks``
|
||||||
Converts newlines into <p> and <br />s
|
Converts newlines into <p> and <br />s.
|
||||||
|
|
||||||
``linebreaksbr``
|
``linebreaksbr``
|
||||||
Converts newlines into <br />s
|
Converts newlines into <br />s.
|
||||||
|
|
||||||
``linenumbers``
|
``linenumbers``
|
||||||
Displays text with line numbers
|
Displays text with line numbers.
|
||||||
|
|
||||||
``ljust``
|
``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
|
**Argument:** field size
|
||||||
|
|
||||||
``lower``
|
``lower``
|
||||||
Converts a string into all lowercase
|
Converts a string into all lowercase.
|
||||||
|
|
||||||
``make_list``
|
``make_list``
|
||||||
Returns the value turned into a list. For an integer, it's a list of
|
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.
|
digits. For a string, it's a list of characters.
|
||||||
|
|
||||||
``phone2numeric``
|
``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``
|
``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``
|
``pprint``
|
||||||
A wrapper around pprint.pprint -- for debugging, really
|
A wrapper around pprint.pprint -- for debugging, really.
|
||||||
|
|
||||||
``random``
|
``random``
|
||||||
Returns a random item from the list
|
Returns a random item from the list.
|
||||||
|
|
||||||
``removetags``
|
``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``
|
``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
|
**Argument:** field size
|
||||||
|
|
||||||
@ -696,19 +699,19 @@ Built-in filter reference
|
|||||||
of Python string formatting
|
of Python string formatting
|
||||||
|
|
||||||
``striptags``
|
``striptags``
|
||||||
Strips all [X]HTML tags
|
Strips all [X]HTML tags.
|
||||||
|
|
||||||
``time``
|
``time``
|
||||||
Formats a time according to the given format (same as the ``now`` tag).
|
Formats a time according to the given format (same as the ``now`` tag).
|
||||||
|
|
||||||
``timesince``
|
``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``
|
``title``
|
||||||
Converts a string into titlecase
|
Converts a string into titlecase.
|
||||||
|
|
||||||
``truncatewords``
|
``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
|
**Argument:** Number of words to truncate after
|
||||||
|
|
||||||
@ -733,26 +736,27 @@ Built-in filter reference
|
|||||||
</li>
|
</li>
|
||||||
|
|
||||||
``upper``
|
``upper``
|
||||||
Converts a string into all uppercase
|
Converts a string into all uppercase.
|
||||||
|
|
||||||
``urlencode``
|
``urlencode``
|
||||||
Escapes a value for use in a URL
|
Escapes a value for use in a URL.
|
||||||
|
|
||||||
``urlize``
|
``urlize``
|
||||||
Converts URLs in plain text into clickable links
|
Converts URLs in plain text into clickable links.
|
||||||
|
|
||||||
``urlizetrunc``
|
``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``
|
``wordcount``
|
||||||
Returns the number of words
|
Returns the number of words.
|
||||||
|
|
||||||
``wordwrap``
|
``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``
|
``yesno``
|
||||||
Given a string mapping values for true, false and (optionally) None,
|
Given a string mapping values for true, false and (optionally) None,
|
||||||
|
@ -307,12 +307,12 @@ The Python API
|
|||||||
|
|
||||||
Django has two ways to load templates from files:
|
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
|
``get_template`` returns the compiled template (a ``Template`` object) for
|
||||||
the template with the given name. If the template doesn't exist, it raises
|
the template with the given name. If the template doesn't exist, it raises
|
||||||
``django.core.template.TemplateDoesNotExist``.
|
``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
|
``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.
|
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
|
.. admonition:: Behind the scenes
|
||||||
|
|
||||||
For a ton of examples, read the source code for Django's default filters
|
For a ton of examples, read the source code for Django's default filters
|
||||||
and tags. They're in ``django/core/defaultfilters.py`` and
|
and tags. They're in ``django/core/template/defaultfilters.py`` and
|
||||||
``django/core/defaulttags.py``, respectively.
|
``django/core/template/defaulttags.py``, respectively.
|
||||||
|
|
||||||
Writing custom template filters
|
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 more examples of complex rendering, see the source code for ``{% if %}``,
|
||||||
``{% for %}``, ``{% ifequal %}`` and ``{% ifchanged %}``. They live in
|
``{% for %}``, ``{% ifequal %}`` and ``{% ifchanged %}``. They live in
|
||||||
``django/core/defaulttags.py``.
|
``django/core/template/defaulttags.py``.
|
||||||
|
@ -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.
|
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::
|
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, loader
|
||||||
from django.core.template import Context
|
|
||||||
from django.models.polls import polls
|
from django.models.polls import polls
|
||||||
from django.utils.httpwrappers import HttpResponse
|
from django.utils.httpwrappers import HttpResponse
|
||||||
|
|
||||||
def index(request):
|
def index(request):
|
||||||
latest_poll_list = polls.get_list(order_by=['-pub_date'], limit=5)
|
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({
|
c = Context({
|
||||||
'latest_poll_list': latest_poll_list,
|
'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.
|
When you've done that, create a directory ``polls`` in your template directory.
|
||||||
Within that, create a file called ``index.html``. Django requires that
|
Within that, create a file called ``index.html``. Django requires that
|
||||||
templates have ".html" extension. Note that our
|
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.
|
"[template_directory]/polls/index.html" on the filesystem.
|
||||||
|
|
||||||
Put the following code in that template::
|
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)
|
latest_poll_list = polls.get_list(order_by=['-pub_date'], limit=5)
|
||||||
return render_to_response('polls/index', {'latest_poll_list': latest_poll_list})
|
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``.
|
``HttpResponse``.
|
||||||
|
|
||||||
The ``render_to_response()`` function takes a template name as its first
|
The ``render_to_response()`` function takes a template name as its first
|
||||||
|
@ -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
|
By default, the ``object_detail`` generic view uses a template called
|
||||||
``<app_label>/<module_name>_detail``. In our case, it'll use the template
|
``<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"``. Thus, rename your ``polls/detail.html`` template to
|
||||||
``polls/polls_detail.html``, and change the ``template_loader.get_template()``
|
``polls/polls_detail.html``, and change the ``render_to_response()`` line in
|
||||||
line in ``vote()``.
|
``vote()``.
|
||||||
|
|
||||||
Similarly, the ``object_list`` generic view uses a template called
|
Similarly, the ``object_list`` generic view uses a template called
|
||||||
``<app_label>/<module_name>_list``. Thus, rename ``polls/index.html`` to
|
``<app_label>/<module_name>_list``. Thus, rename ``polls/index.html`` to
|
||||||
|
@ -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
|
from django.utils.translation import activate, deactivate
|
||||||
|
|
||||||
# Helper objects for template tests
|
# Helper objects for template tests
|
||||||
@ -259,7 +260,7 @@ TEMPLATE_TESTS = {
|
|||||||
'i18n14': ('{{ bool|yesno:"ja,nein" }}', {'bool': True}, 'ja'),
|
'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):
|
def test_template_loader(template_name, template_dirs=None):
|
||||||
try:
|
try:
|
||||||
return TEMPLATE_TESTS[template_name][0]
|
return TEMPLATE_TESTS[template_name][0]
|
||||||
@ -267,7 +268,7 @@ def test_template_loader(template_name, template_dirs=None):
|
|||||||
raise template.TemplateDoesNotExist, template_name
|
raise template.TemplateDoesNotExist, template_name
|
||||||
|
|
||||||
def run_tests(verbosity=0, standalone=False):
|
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 = []
|
failed_tests = []
|
||||||
tests = TEMPLATE_TESTS.items()
|
tests = TEMPLATE_TESTS.items()
|
||||||
tests.sort()
|
tests.sort()
|
||||||
@ -275,7 +276,7 @@ def run_tests(verbosity=0, standalone=False):
|
|||||||
if 'LANGUAGE_CODE' in vals[1]:
|
if 'LANGUAGE_CODE' in vals[1]:
|
||||||
activate('*', vals[1]['LANGUAGE_CODE'])
|
activate('*', vals[1]['LANGUAGE_CODE'])
|
||||||
try:
|
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:
|
except Exception, e:
|
||||||
if e.__class__ == vals[2]:
|
if e.__class__ == vals[2]:
|
||||||
if verbosity:
|
if verbosity:
|
||||||
@ -294,7 +295,7 @@ def run_tests(verbosity=0, standalone=False):
|
|||||||
if verbosity:
|
if verbosity:
|
||||||
print "Template test: %s -- FAILED. Expected %r, got %r" % (name, vals[2], output)
|
print "Template test: %s -- FAILED. Expected %r, got %r" % (name, vals[2], output)
|
||||||
failed_tests.append(name)
|
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:
|
if failed_tests and not standalone:
|
||||||
msg = "Template tests %s failed." % failed_tests
|
msg = "Template tests %s failed." % failed_tests
|
||||||
|
Loading…
x
Reference in New Issue
Block a user