Ticket #1400: templates_r2388.diff

File templates_r2388.diff, 37.7 KB (added by django@…, 10 years ago)

template patch

  • django/contrib/admin/templatetags/admin_list.py

    === django/contrib/admin/templatetags/admin_list.py
    ==================================================================
     
    6565        'ALL_VAR': ALL_VAR,
    6666        '1': 1,
    6767    }
    68 pagination = register.inclusion_tag('admin/pagination')(pagination)
     68pagination = register.inclusion_tag(pagination, 'admin/pagination')
    6969
    7070def result_headers(cl):
    7171    lookup_opts = cl.lookup_opts
     
    185185    return {'cl': cl,
    186186            'result_headers': list(result_headers(cl)),
    187187            'results': list(results(cl))}
    188 result_list = register.inclusion_tag("admin/change_list_results")(result_list)
     188result_list = register.inclusion_tag(result_list, 'admin/change_list_results')
    189189
    190190def date_hierarchy(cl):
    191191    if cl.lookup_opts.admin.date_hierarchy:
     
    245245                    'title': year.year
    246246                } for year in years]
    247247            }
    248 date_hierarchy = register.inclusion_tag('admin/date_hierarchy')(date_hierarchy)
     248date_hierarchy = register.inclusion_tag(date_hierarchy, 'admin/date_hierarchy')
    249249
    250250def search_form(cl):
    251251    return {
     
    253253        'show_result_count': cl.result_count != cl.full_result_count and not cl.opts.one_to_one_field,
    254254        'search_var': SEARCH_VAR
    255255    }
    256 search_form = register.inclusion_tag('admin/search_form')(search_form)
     256search_form = register.inclusion_tag(search_form, 'admin/search_form')
    257257
    258258def filter(cl, spec):
    259259    return {'title': spec.title(), 'choices' : list(spec.choices(cl))}
    260 filter = register.inclusion_tag('admin/filter')(filter)
     260filter = register.inclusion_tag(filter, 'admin/filter')
    261261
    262262def filters(cl):
    263263    return {'cl': cl}
    264 filters = register.inclusion_tag('admin/filters')(filters)
     264filters = register.inclusion_tag(filters, 'admin/filters')
  • django/contrib/admin/templatetags/admin_modify.py

    === django/contrib/admin/templatetags/admin_modify.py
    ==================================================================
     
    2222include_admin_script = register.simple_tag(include_admin_script)
    2323
    2424def submit_row(context):
    25     opts = context['opts']
    26     change = context['change']
    27     is_popup = context['is_popup']
     25    opts = context.get('opts')
     26    change = context.get('change')
     27    is_popup = context.get('is_popup')
    2828    return {
    2929        'onclick_attrib': (opts.get_ordered_objects() and change
    3030                            and 'onclick="submitOrderForm();"' or ''),
     
    3535        'show_save_and_continue': not is_popup,
    3636        'show_save': True
    3737    }
    38 submit_row = register.inclusion_tag('admin/submit_line', takes_context=True)(submit_row)
     38submit_row = register.inclusion_tag(submit_row, 'admin/submit_line', takes_context=True)
    3939
    4040def field_label(bound_field):
    4141    class_names = []
     
    229229        'bound_fields': bound_fields,
    230230        'class_names': " ".join(class_names),
    231231    }
    232 admin_field_line = register.inclusion_tag('admin/field_line', takes_context=True)(admin_field_line)
     232admin_field_line = register.inclusion_tag(admin_field_line, 'admin/field_line', takes_context=True)
  • django/contrib/admin/templatetags/adminapplist.py

    === django/contrib/admin/templatetags/adminapplist.py
    ==================================================================
     
    6161        raise template.TemplateSyntaxError, "First argument to '%s' tag must be 'as'" % tokens[0]
    6262    return AdminApplistNode(tokens[2])
    6363
    64 register.tag('get_admin_app_list', get_admin_app_list)
     64register.tag(get_admin_app_list, name='get_admin_app_list')
  • django/contrib/admin/templatetags/log.py

    === django/contrib/admin/templatetags/log.py
    ==================================================================
     
    5050                raise template.TemplateSyntaxError, "Fourth argument in '%s' must be 'for_user'" % self.tag_name
    5151        return AdminLogNode(limit=tokens[1], varname=tokens[3], user=(len(tokens) > 5 and tokens[5] or None))
    5252
    53 register.tag('get_admin_log', DoGetAdminLog('get_admin_log'))
     53register.tag(DoGetAdminLog('get_admin_log'), name='get_admin_log')
  • django/contrib/admin/views/template.py

    === django/contrib/admin/views/template.py
    ==================================================================
     
    5656            node.template_dirs = settings_module.TEMPLATE_DIRS
    5757            return node
    5858        register = template.Library()
    59         register.tag('extends', new_do_extends)
     59        register.tag(new_do_extends, name='extends')
    6060        template.builtins.append(register)
    6161
    6262        # Now validate the template using the new template dirs
  • django/contrib/comments/templatetags/comments.py

    === django/contrib/comments/templatetags/comments.py
    ==================================================================
     
    315315        return CommentListNode(package, module, var_name, obj_id, tokens[5], self.free, ordering)
    316316
    317317# registration comments
    318 register.tag('get_comment_list', DoGetCommentList(False))
    319 register.tag('comment_form', DoCommentForm(False))
    320 register.tag('get_comment_count', DoCommentCount(False))
     318register.tag(DoGetCommentList(False), name='get_comment_list')
     319register.tag(DoCommentForm(False), name='comment_form')
     320register.tag(DoCommentCount(False), name='get_comment_count')
    321321# free comments
    322 register.tag('get_free_comment_list', DoGetCommentList(True))
    323 register.tag('free_comment_form', DoCommentForm(True))
    324 register.tag('get_free_comment_count', DoCommentCount(True))
     322register.tag(DoGetCommentList(True), name='get_free_comment_list')
     323register.tag(DoCommentForm(True), name='free_comment_form')
     324register.tag(DoCommentCount(True), name='get_free_comment_count')
  • django/template/__init__.py

    === django/template/__init__.py
    ==================================================================
     
    5454>>> t.render(c)
    5555'\n<html>\n\n</html>\n'
    5656"""
     57import keyword
    5758import re
    5859from inspect import getargspec
    5960from django.utils.functional import curry
     
    7677VARIABLE_TAG_END = '}}'
    7778
    7879ALLOWED_VARIABLE_CHARS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_.'
     80BOOLEANS = ['False', 'True']
    7981
    8082# what to report as the origin for templates that come from non-loader sources
    8183# (e.g. strings)
     
    227229            elif token.token_type == TOKEN_VAR:
    228230                if not token.contents:
    229231                    self.empty_variable(token)
    230                 filter_expression = self.compile_filter(token.contents)
     232                filter_expression = self.compile_filter(token.contents, default=settings.TEMPLATE_STRING_IF_INVALID)
    231233                var_node = self.create_variable_node(filter_expression)
    232234                self.extend_nodelist(nodelist, var_node,token)
    233235            elif token.token_type == TOKEN_BLOCK:
     
    309311        self.tags.update(lib.tags)
    310312        self.filters.update(lib.filters)
    311313
    312     def compile_filter(self,token):
     314    def compile_filter(self, token, default=None):
    313315        "Convenient wrapper for FilterExpression"
    314         return FilterExpression(token, self)
     316        return FilterExpression(token, self, default)
    315317
    316318    def find_filter(self, filter_name):
    317319        if self.filters.has_key(filter_name):
     
    496498    This class should never be instantiated outside of the
    497499    get_filters_from_token helper function.
    498500    """
    499     def __init__(self, token, parser):
     501    def __init__(self, token, parser, default=None):
    500502        self.token = token
    501         matches = filter_re.finditer(token)
     503        self.default = default
    502504        var = None
    503505        filters = []
    504506        upto = 0
    505         for match in matches:
     507        for match in filter_re.finditer(token):
    506508            start = match.start()
    507509            if upto != start:
    508510                raise TemplateSyntaxError, "Could not parse some characters: %s|%s|%s"  % \
     
    534536                upto = match.end()
    535537        if upto != len(token):
    536538            raise TemplateSyntaxError, "Could not parse the remainder: %s" % token[upto:]
    537         self.var , self.filters = var, filters
     539        self.var, self.filters = var, filters
    538540
    539541    def resolve(self, context):
    540542        try:
    541543            obj = resolve_variable(self.var, context)
    542544        except VariableDoesNotExist:
    543             obj = settings.TEMPLATE_STRING_IF_INVALID
     545            return self.default
    544546        for func, args in self.filters:
    545547            arg_vals = []
    546548            for lookup, arg in args:
     
    588590    """
    589591    Returns the resolved variable, which may contain attribute syntax, within
    590592    the given context. The variable may be a hard-coded string (if it begins
    591     and ends with single or double quote marks).
     593    and ends with single or double quote marks), a boolean literal, or an
     594    integer or float literal.
    592595
    593596    >>> c = {'article': {'section':'News'}}
    594597    >>> resolve_variable('article.section', c)
     
    604607
    605608    (The example assumes VARIABLE_ATTRIBUTE_SEPARATOR is '.')
    606609    """
    607     if path[0] in '0123456789':
     610    if path[0].isdigit():
    608611        number_type = '.' in path and float or int
    609         try:
    610            current = number_type(path)
    611         except ValueError:
    612            current = settings.TEMPLATE_STRING_IF_INVALID
    613     elif path[0] in ('"', "'") and path[0] == path[-1]:
    614         current = path[1:-1]
    615     else:
    616         current = context
    617         bits = path.split(VARIABLE_ATTRIBUTE_SEPARATOR)
    618         while bits:
    619             try: # dictionary lookup
    620                 current = current[bits[0]]
    621             except (TypeError, AttributeError, KeyError):
    622                 try: # attribute lookup
    623                     current = getattr(current, bits[0])
    624                     if callable(current):
    625                         if getattr(current, 'alters_data', False):
    626                             current = settings.TEMPLATE_STRING_IF_INVALID
    627                         else:
    628                             try: # method call (assuming no args required)
    629                                 current = current()
    630                             except TypeError: # arguments *were* required
    631                                 # GOTCHA: This will also catch any TypeError
    632                                 # raised in the function itself.
    633                                 current = settings.TEMPLATE_STRING_IF_INVALID # invalid method call
    634                             except Exception, e:
    635                                 if getattr(e, 'silent_variable_failure', False):
    636                                     current = settings.TEMPLATE_STRING_IF_INVALID
    637                                 else:
    638                                     raise
    639                 except (TypeError, AttributeError):
    640                     try: # list-index lookup
    641                         current = current[int(bits[0])]
    642                     except (IndexError, ValueError, KeyError):
    643                         raise VariableDoesNotExist, "Failed lookup for key [%s] in %r" % (bits[0], current) # missing attribute
    644             del bits[0]
    645     return current
     612        return number_type(path)
     613    if path in BOOLEANS:
     614        return bool(BOOLEANS.index(path))
     615    if path[0] in ('"', "'"):
     616        if path[0] == path[-1]:
     617            return path[1:-1]
     618        raise VariableDoesNotExist, "Missing quotes in string literal %s" % (path,)
     619    for bit in path.split(VARIABLE_ATTRIBUTE_SEPARATOR):
     620        try: # dictionary lookup
     621            context = context[bit]
     622        except (TypeError, AttributeError, KeyError):
     623            try: # attribute lookup
     624                context = getattr(context, bit)
     625            except (TypeError, AttributeError):
     626                try: # list-index lookup
     627                    context = context[int(bit)]
     628                except (IndexError, ValueError, KeyError):
     629                    raise VariableDoesNotExist, "Failed lookup for key [%s] in %r" % (bit, context) # missing attribute
     630            else:
     631                if callable(context):
     632                    if getattr(context, 'alters_data', False):
     633                        raise VariableDoesNotExist("Failed lookup for key [%s] in %r" % (bit, context))
     634                    try: # method call (assuming no args required)
     635                        context = context()
     636                    except Exception, e:
     637                        if getattr(e, 'silent_variable_failure', False):
     638                            raise VariableDoesNotExist, "Failed lookup for key [%s] in %r" % (bit, context) # missing attribute
     639                        raise
     640    return context
    646641
     642tag_tokens_re = re.compile(r"""
     643(?:\s*)                           # ignore preceeding whitespace
     644(                                 # token group
     645    (?:[A-Za-z_][0-9A-Za-z_]*=)?" # optional name and open double-quote
     646    [^"\\]*                       # normal characters
     647    (?:\\.                        # chew up backslash and following char
     648        (?:|[^"\\])*              # normal characters
     649    )*                            # repeat as needed to chew up the backslashes
     650    "                             # close double-quote
     651|
     652    (?:[A-Za-z_][0-9A-Za-z_]*=)?' # optional name and open single-quote
     653    [^'\\]*                       # normal characters
     654    (?:\\.                        # chew up backslash and following char
     655        (?:|[^'\\])*              # normal characters
     656    )*                            # repeat as needed to chew up the backslashes
     657    '                             # close single-quote
     658|
     659    (?:[A-Za-z_][0-9A-Za-z_]*=)?  # optional name
     660    [^"'\s][^\s]*                 # unquoted token
     661)
     662(?:\s+|$)                         # chew up following ws until next token
     663""", re.VERBOSE)
     664
     665def tokenize_tag_contents(contents):
     666
     667    """ Parse tag contents into (tag_name, args_to_resolve, kwds_to_resolve).
     668    If an argument name is a Python keyword append an underscore.
     669
     670    >>> tokenize_tag_contents("An 'easy' one.")
     671    ('An', ["'easy'", 'one.'], {})
     672    >>> tokenize_tag_contents(r'''Please don't try 'thi\\'s at' named="hom\\"e."''')
     673    ('Please', ["don't", 'try', "'thi\'s at'"], {'named': '"hom\\\\"e."'})
     674    """
     675
     676    bits = []
     677    i, n = 0, len(contents)
     678    while i < n:
     679        m = tag_tokens_re.match(contents, i)
     680        if not m:
     681            raise ValueError("Can't parse string %s at index %s" %(repr(contents), i))
     682        bit = m.group(1)
     683        if bit.startswith('"'):
     684            bit = bit.replace('\\"', '"')
     685        elif bit.startswith("'"):
     686            bit = bit.replace("\\'", "'")
     687        bits.append(bit)
     688        i = m.end()
     689    tag_name = bits[0]
     690    args_to_resolve = []
     691    kwds_to_resolve = {}
     692    for bit in bits[1:]:
     693        if bit[0] in ("'", '"'):
     694            if kwds_to_resolve:
     695                raise SyntaxError("template tag syntax error: non-keyword arguments must come before keyword arguments")
     696            args_to_resolve.append(bit)
     697        else:
     698            try:
     699                name, value = bit.split('=', 1)
     700                if keyword.iskeyword(name):
     701                    name += '_'
     702                kwds_to_resolve[name] = value
     703            except ValueError:
     704                if kwds_to_resolve:
     705                    raise SyntaxError("template tag syntax error: non-keyword arguments must come before keyword arguments")
     706                args_to_resolve.append(bit)
     707    return tag_name, args_to_resolve, kwds_to_resolve
     708
     709def resolve_tag_arguments(context, args_to_resolve, kwds_to_resolve):
     710    resolved_args = [resolve_variable(var, context) for var in args_to_resolve]
     711    resolved_kwds = dict([(name, resolve_variable(var, context)) for name, var in kwds_to_resolve.items()])
     712    return resolved_args, resolved_kwds
     713
    647714class Node:
    648715    def render(self, context):
    649716        "Return the node rendered as a string"
     
    737804            raise
    738805        return self.encode_output(output)
    739806
    740 def generic_tag_compiler(params, defaults, name, node_class, parser, token):
    741     "Returns a template.Node subclass."
    742     bits = token.contents.split()[1:]
    743     bmax = len(params)
    744     def_len = defaults and len(defaults) or 0
    745     bmin = bmax - def_len
    746     if(len(bits) < bmin or len(bits) > bmax):
    747         if bmin == bmax:
    748             message = "%s takes %s arguments" % (name, bmin)
    749         else:
    750             message = "%s takes between %s and %s arguments" % (name, bmin, bmax)
    751         raise TemplateSyntaxError, message
    752     return node_class(bits)
     807class SimpleNode(Node):
     808    def __init__(self, func, takes_context, block_nodelist, args_to_resolve, kwds_to_resolve):
     809        self.func = func
     810        self.takes_context = takes_context
     811        self.block_nodelist = block_nodelist
     812        self.args_to_resolve = args_to_resolve
     813        self.kwds_to_resolve = kwds_to_resolve
    753814
    754 class Library(object):
    755     def __init__(self):
    756         self.filters = {}
    757         self.tags = {}
     815    def render(self, context):
     816        resolved_args, resolved_kwds = resolve_tag_arguments(context, self.args_to_resolve, self.kwds_to_resolve)
     817        if self.block_nodelist:
     818            resolved_args.insert(0, self.block_nodelist)
     819        if self.takes_context:
     820            resolved_args.insert(0, context)
     821        return self.func(*resolved_args, **resolved_kwds) or ''
    758822
    759     def tag(self, name=None, compile_function=None):
    760         if name == None and compile_function == None:
    761             # @register.tag()
    762             return self.tag_function
    763         elif name != None and compile_function == None:
    764             if(callable(name)):
    765                 # @register.tag
    766                 return self.tag_function(name)
    767             else:
    768                 # @register.tag('somename') or @register.tag(name='somename')
    769                 def dec(func):
    770                     return self.tag(name, func)
    771                 return dec
    772         elif name != None and compile_function != None:
    773             # register.tag('somename', somefunc)
    774             self.tags[name] = compile_function
    775             return compile_function
    776         else:
    777             raise InvalidTemplateLibrary, "Unsupported arguments to Library.tag: (%r, %r)", (name, compile_function)
     823class SimpleNodeFactory(object):
     824    def __init__(self, func, takes_context=False, takes_block=False):
     825        self.func = func
     826        self.__doc__ = func.__doc__
     827        self.takes_context = takes_context
     828        self.takes_block = takes_block
    778829
    779     def tag_function(self,func):
    780         self.tags[func.__name__] = func
    781         return func
     830    def __call__(self, parser, token):
     831        tag_name, args_to_resolve, kwds_to_resolve = tokenize_tag_contents(token.contents)
     832        block_nodelist = None
     833        if self.takes_block:
     834            block_nodelist = parser.parse(('end' +  tag_name,))
     835            parser.delete_first_token()
     836        return SimpleNode(self.func, self.takes_context, block_nodelist, args_to_resolve, kwds_to_resolve)
    782837
    783     def filter(self, name=None, filter_func=None):
    784         if name == None and filter_func == None:
    785             # @register.filter()
    786             return self.filter_function
    787         elif filter_func == None:
    788             if(callable(name)):
    789                 # @register.filter
    790                 return self.filter_function(name)
    791             else:
    792                 # @register.filter('somename') or @register.filter(name='somename')
    793                 def dec(func):
    794                     return self.filter(name, func)
    795                 return dec
    796         elif name != None and filter_func != None:
    797             # register.filter('somename', somefunc)
    798             self.filters[name] = filter_func
    799             return filter_func
    800         else:
    801             raise InvalidTemplateLibrary, "Unsupported arguments to Library.filter: (%r, %r, %r)", (name, compile_function, has_arg)
     838class InclusionNode(Node):
     839    def __init__(self, func, template, context_class, takes_context, args_to_resolve, kwds_to_resolve):
     840        self.func = func
     841        self.template = template
     842        self.context_class = context_class
     843        self.takes_context = takes_context
     844        self.args_to_resolve = args_to_resolve
     845        self.kwds_to_resolve = kwds_to_resolve
    802846
    803     def filter_function(self, func):
    804         self.filters[func.__name__] = func
    805         return func
     847    def render(self, context):
     848        resolved_args, resolved_kwds = resolve_tag_arguments(context, self.args_to_resolve, self.kwds_to_resolve)
     849        if self.takes_context:
     850            resolved_args.insert(0, context)
     851        if not getattr(self, 'nodelist', None):
     852            from django.template.loader import get_template
     853            t = get_template(self.template)
     854            self.nodelist = t.nodelist
     855        context = self.context_class(self.func(*resolved_args, **resolved_kwds))
     856        return self.nodelist.render(context)
    806857
    807     def simple_tag(self,func):
    808         (params, xx, xxx, defaults) = getargspec(func)
     858class InclusionNodeFactory(object):
     859    def __init__(self, func, template, context_class=Context, takes_context=False):
     860        self.func = func
     861        self.__doc__ = func.__doc__
     862        self.template = template
     863        self.context_class = context_class
     864        self.takes_context = takes_context
    809865
    810         class SimpleNode(Node):
    811             def __init__(self, vars_to_resolve):
    812                 self.vars_to_resolve = vars_to_resolve
     866    def __call__(self, parser, token):
     867        tag_name, args_to_resolve, kwds_to_resolve = tokenize_tag_contents(token.contents)
     868        return InclusionNode(self.func, self.template, self.context_class, self.takes_context, args_to_resolve, kwds_to_resolve)
    813869
    814             def render(self, context):
    815                 resolved_vars = [resolve_variable(var, context) for var in self.vars_to_resolve]
    816                 return func(*resolved_vars)
     870class Library(object):
     871    def __init__(self):
     872        self.filters = {}
     873        self.tags = {}
    817874
    818         compile_func = curry(generic_tag_compiler, params, defaults, func.__name__, SimpleNode)
    819         compile_func.__doc__ = func.__doc__
    820         self.tag(func.__name__, compile_func)
    821         return func
     875    def tag(self, func=None, name=None):
     876        if callable(func):
     877            self.tags[name or func.__name__] = func
     878            return func
     879        elif func is None:
     880            return curry(self.tag, name=name)
     881        raise InvalidTemplateLibrary("Unsupported argument to Library.tag: (%r)" % (func,))
    822882
    823     def inclusion_tag(self, file_name, context_class=Context, takes_context=False):
    824         def dec(func):
    825             (params, xx, xxx, defaults) = getargspec(func)
    826             if takes_context:
    827                 if params[0] == 'context':
    828                     params = params[1:]
    829                 else:
    830                     raise TemplateSyntaxError, "Any tag function decorated with takes_context=True must have a first argument of 'context'"
     883    def filter(self, func=None, name=None):
     884        if callable(func):
     885            self.filters[name or func.__name__] = func
     886            return func
     887        elif func is None:
     888            return curry(self.filter, name=name)
     889        raise InvalidTemplateLibrary("Unsupported argument to Library.filter: (%r)" % (func,))
    831890
    832             class InclusionNode(Node):
    833                 def __init__(self, vars_to_resolve):
    834                     self.vars_to_resolve = vars_to_resolve
     891    def simple_tag(self, func=None, takes_context=False, takes_block=False, name=None):
     892        if callable(func):
     893            self.tags[name or func.__name__] = SimpleNodeFactory(func, takes_context, takes_block)
     894            return func
     895        elif func is None:
     896            return curry(self.simple_tag, takes_context=takes_context, takes_block=takes_block, name=name)
     897        raise InvalidTemplateLibrary("Unsupported argument to Library.simple_tag: (%r)" % (func,))
    835898
    836                 def render(self, context):
    837                     resolved_vars = [resolve_variable(var, context) for var in self.vars_to_resolve]
    838                     if takes_context:
    839                         args = [context] + resolved_vars
    840                     else:
    841                         args = resolved_vars
    842 
    843                     dict = func(*args)
    844 
    845                     if not getattr(self, 'nodelist', False):
    846                         from django.template.loader import get_template
    847                         t = get_template(file_name)
    848                         self.nodelist = t.nodelist
    849                     return self.nodelist.render(context_class(dict))
    850 
    851             compile_func = curry(generic_tag_compiler, params, defaults, func.__name__, InclusionNode)
    852             compile_func.__doc__ = func.__doc__
    853             self.tag(func.__name__, compile_func)
     899    def inclusion_tag(self, func=None, template=None, context_class=Context, takes_context=False, name=None):
     900        if callable(func):
     901            self.tags[name or func.__name__] = InclusionNodeFactory(func, template, context_class, takes_context)
    854902            return func
    855         return dec
     903        elif func is None:
     904            return curry(self.inclusion_tag, template=template, context_class=context_class, takes_context=takes_context, name=name)
     905        raise InvalidTemplateLibrary("Unsupported argument to Library.inclusion_tag: (%r)" % (func,))
    856906
    857907def get_library(module_name):
    858908    lib = libraries.get(module_name, None)
  • django/template/context.py

    === django/template/context.py
    ==================================================================
     
    3333        for dict in self.dicts:
    3434            if dict.has_key(key):
    3535                return dict[key]
    36         return settings.TEMPLATE_STRING_IF_INVALID
     36        raise KeyError("Context key not found: %s" % key)
    3737
    3838    def __delitem__(self, key):
    3939        "Delete a variable from the current context"
     
    4545                return True
    4646        return False
    4747
    48     def get(self, key, otherwise):
     48    def get(self, key, otherwise=None):
    4949        for dict in self.dicts:
    5050            if dict.has_key(key):
    5151                return dict[key]
  • django/template/defaultfilters.py

    === django/template/defaultfilters.py
    ==================================================================
     
    469469register.filter(removetags)
    470470register.filter(random)
    471471register.filter(rjust)
    472 register.filter('slice', slice_)
     472register.filter(slice_, name='slice')
    473473register.filter(slugify)
    474474register.filter(stringformat)
    475475register.filter(striptags)
  • django/template/defaulttags.py

    === django/template/defaulttags.py
    ==================================================================
     
    4545
    4646    def render(self, context):
    4747        for var in self.vars:
    48             value = resolve_variable(var, context)
     48            try:
     49                value = resolve_variable(var, context)
     50            except VariableDoesNotExist:
     51                continue
    4952            if value:
    5053                return str(value)
    5154        return ''
     
    142145        return "<IfEqualNode>"
    143146
    144147    def render(self, context):
    145         val1 = resolve_variable(self.var1, context)
    146         val2 = resolve_variable(self.var2, context)
     148        try:
     149            val1 = resolve_variable(self.var1, context)
     150        except VariableDoesNotExist:
     151            val1 = None
     152        try:
     153            val2 = resolve_variable(self.var2, context)
     154        except VariableDoesNotExist:
     155            val2 = None
    147156        if (self.negate and val1 != val2) or (not self.negate and val1 == val2):
    148157            return self.nodelist_true.render(context)
    149158        return self.nodelist_false.render(context)
     
    187196
    188197    def render(self, context):
    189198        obj_list = self.target.resolve(context)
    190         if obj_list == '': # target_var wasn't found in context; fail silently
     199        if obj_list is None:
    191200            context[self.var_name] = []
    192201            return ''
    193202        output = [] # list of dictionaries in the format {'grouper': 'key', 'list': [list of contents]}
     
    391400    nodelist = parser.parse(('endfilter',))
    392401    parser.delete_first_token()
    393402    return FilterNode(filter_expr, nodelist)
    394 filter = register.tag("filter", do_filter)
     403filter = register.tag(do_filter, name='filter')
    395404
    396405#@register.tag
    397406def firstof(parser, token):
     
    469478    nodelist_loop = parser.parse(('endfor',))
    470479    parser.delete_first_token()
    471480    return ForNode(loopvar, sequence, reversed, nodelist_loop)
    472 do_for = register.tag("for", do_for)
     481do_for = register.tag(do_for, name='for')
    473482
    474483def do_ifequal(parser, token, negate):
    475484    """
     
    579588    else:
    580589        nodelist_false = NodeList()
    581590    return IfNode(boolvars, nodelist_true, nodelist_false)
    582 do_if = register.tag("if", do_if)
     591do_if = register.tag(do_if, name='if')
    583592
    584593#@register.tag
    585594def ifchanged(parser, token):
  • django/template/loader_tags.py

    === django/template/loader_tags.py
    ==================================================================
     
    167167        return ConstantIncludeNode(path[1:-1])
    168168    return IncludeNode(bits[1])
    169169
    170 register.tag('block', do_block)
    171 register.tag('extends', do_extends)
    172 register.tag('include', do_include)
     170register.tag(do_block, name='block')
     171register.tag(do_extends, name='extends')
     172register.tag(do_include, name='include')
  • django/templatetags/i18n.py

    === django/templatetags/i18n.py
    ==================================================================
     
    215215
    216216    return BlockTranslateNode(extra_context, singular, plural, countervar, counter)
    217217
    218 register.tag('get_available_languages', do_get_available_languages)
    219 register.tag('get_current_language', do_get_current_language)
    220 register.tag('trans', do_translate)
    221 register.tag('blocktrans', do_block_translate)
     218register.tag(do_get_available_languages, name='get_available_languages')
     219register.tag(do_get_current_language, name='get_current_language')
     220register.tag(do_translate, name='trans')
     221register.tag(do_block_translate, name='blocktrans')
  • docs/templates_python.txt

    === docs/templates_python.txt
    ==================================================================
     
    566566Most filters don't take arguments. In this case, just leave the argument out of
    567567your function. Example::
    568568
    569     def lower(value): # Only one argument.
     569    def do_lower(value): # Only one argument.
    570570        "Converts a string into all lowercase"
    571571        return value.lower()
    572572
    573573When you've written your filter definition, you need to register it with
    574574your ``Library`` instance, to make it available to Django's template language::
    575575
    576     register.filter('cut', cut)
    577     register.filter('lower', lower)
     576    register.filter(cut)
     577    register.filter(do_lower, name='lower')
    578578
    579 The ``Library.filter()`` method takes two arguments:
     579The ``Library.filter()`` method takes the following arguments:
    580580
    581     1. The name of the filter -- a string.
    582     2. The compilation function -- a Python function (not the name of the
     581    1. The filter function -- a Python function (not the name of the
    583582       function as a string).
     583    2. An optional alternative name for the filter -- a string).  By default
     584       it is the same as the function name.
    584585
    585586If you're using Python 2.4 or above, you can use ``register.filter()`` as a
    586587decorator instead::
    587588
    588     @register.filter(name='cut')
     589    @register.filter
    589590    def cut(value, arg):
    590591        return value.replace(arg, '')
    591592
    592     @register.filter
    593     def lower(value):
     593    @register.filter(name=lower)
     594    def do_lower(value):
    594595        return value.lower()
    595596
    596 If you leave off the ``name`` argument, as in the second example above, Django
    597 will use the function's name as the filter name.
     597If you use the filter decorator without the ``name`` argument, as in the first
     598example above, Django will use the function's name as the filter name.
    598599
    599600Writing custom template tags
    600601----------------------------
     
    714715Finally, register the tag with your module's ``Library`` instance, as explained
    715716in "Writing custom template filters" above. Example::
    716717
    717     register.tag('current_time', do_current_time)
     718    register.tag(do_current_time, name='current_time')
    718719
    719720The ``tag()`` method takes two arguments:
    720721
    721     1. The name of the template tag -- a string. If this is left out, the
    722        name of the compilation function will be used.
    723     2. The compilation function -- a Python function (not the name of the
     722    1. The tag function -- a Python function (not the name of the
    724723       function as a string).
     724    2. An optional alternative name for the template tag -- a string. If this
     725       is left out, the name of the tag function will be used.
    725726
    726727As with filter registration, it is also possible to use this as a decorator, in
    727728Python 2.4 and above::
  • tests/othertests/templates.py

    === tests/othertests/templates.py
    ==================================================================
     
    11from django.conf import settings
     2settings.TEMPLATE_STRING_IF_INVALID = "[undefined]"
    23
    3 
    44from django import template
    55from django.template import loader
    66from django.utils.translation import activate, deactivate, install
     
    2222def do_echo(parser, token):
    2323    return EchoNode(token.contents.split()[1:])
    2424
    25 register.tag("echo", do_echo)
     25register.tag(do_echo, name='echo')
    2626
    2727template.libraries['django.templatetags.testtags'] = register
    2828
     
    7272    'basic-syntax03': ("{{ first }} --- {{ second }}", {"first" : 1, "second" : 2}, "1 --- 2"),
    7373
    7474    # Fail silently when a variable is not found in the current context
    75     'basic-syntax04': ("as{{ missing }}df", {}, "asdf"),
     75    'basic-syntax04': ("as{{ missing }}df", {}, "as%sdf" % settings.TEMPLATE_STRING_IF_INVALID),
    7676
    7777    # A variable may not contain more than one word
    7878    'basic-syntax06': ("{{ multi word variable }}", {}, template.TemplateSyntaxError),
     
    8888    'basic-syntax10': ("{{ var.otherclass.method }}", {"var": SomeClass()}, "OtherClass.method"),
    8989
    9090    # Fail silently when a variable's attribute isn't found
    91     'basic-syntax11': ("{{ var.blech }}", {"var": SomeClass()}, ""),
     91    'basic-syntax11': ("{{ var.blech }}", {"var": SomeClass()}, "%s" % settings.TEMPLATE_STRING_IF_INVALID),
    9292
    9393    # Raise TemplateSyntaxError when trying to access a variable beginning with an underscore
    9494    'basic-syntax12': ("{{ var.__dict__ }}", {"var": SomeClass()}, template.TemplateSyntaxError),
     
    104104    'basic-syntax18': ("{{ foo.bar }}", {"foo" : {"bar" : "baz"}}, "baz"),
    105105
    106106    # Fail silently when a variable's dictionary key isn't found
    107     'basic-syntax19': ("{{ foo.spam }}", {"foo" : {"bar" : "baz"}}, ""),
     107    'basic-syntax19': ("{{ foo.spam }}", {"foo" : {"bar" : "baz"}}, "%s" % settings.TEMPLATE_STRING_IF_INVALID),
    108108
    109109    # Fail silently when accessing a non-simple method
    110     'basic-syntax20': ("{{ var.method2 }}", {"var": SomeClass()}, ""),
     110    'basic-syntax20': ("{{ var.method2 }}", {"var": SomeClass()}, "%s" % settings.TEMPLATE_STRING_IF_INVALID),
    111111
    112112    # Basic filter usage
    113113    'basic-syntax21': ("{{ var|upper }}", {"var": "Django is the greatest!"}, "DJANGO IS THE GREATEST!"),
     
    146146    'basic-syntax32': (r'{{ var|yesno:"yup,nup,mup" }} {{ var|yesno }}', {"var": True}, 'yup yes'),
    147147
    148148    # Fail silently for methods that raise an exception with a "silent_variable_failure" attribute
    149     'basic-syntax33': (r'1{{ var.method3 }}2', {"var": SomeClass()}, "12"),
     149    'basic-syntax33': (r'1{{ var.method3 }}2', {"var": SomeClass()}, "1%s2" % settings.TEMPLATE_STRING_IF_INVALID),
    150150
    151151    # In methods that raise an exception without a "silent_variable_attribute" set to True,
    152152    # the exception propogates
  • tests/othertests/tokenize_tag_contents.py

    === tests/othertests/tokenize_tag_contents.py
    ==================================================================
     
     1"""
     2# positional argument
     3>>> tok('tag arg1')
     4('tag', ['arg1'], {})
     5
     6# single-quoted positional argument
     7>>> tok("tag 'arg1 with spaces'")
     8('tag', ["'arg1 with spaces'"], {})
     9
     10# double-quoted positional argument
     11>>> tok('tag "arg1 with spaces"')
     12('tag', ['"arg1 with spaces"'], {})
     13
     14# named argument
     15>>> tok('tag name1=arg1')
     16('tag', [], {'name1': 'arg1'})
     17
     18# single-quoted named argument
     19>>> tok("tag name1='arg1 with spaces'")
     20('tag', [], {'name1': "'arg1 with spaces'"})
     21
     22# double-quoted named argument
     23>>> tok('tag name1="arg1 with spaces"')
     24('tag', [], {'name1': '"arg1 with spaces"'})
     25
     26# positional argument and named argument
     27>>> tok('tag arg1 name1=arg2')
     28('tag', ['arg1'], {'name1': 'arg2'})
     29
     30# mixed arguments
     31>>> tok('tag arg1 "arg2 with spaces" name1=arg3 name2="arg4 with spaces"')
     32('tag', ['arg1', '"arg2 with spaces"'], {'name2': '"arg4 with spaces"', 'name1': 'arg3'})
     33
     34# double quotes in single-quoted string
     35>>> tok("tag 'arg1 \\"with quotes\\"'")
     36('tag', ['\\'arg1 "with quotes"\\''], {})
     37
     38# single quotes in double-quoted string
     39>>> tok('tag "arg1 \\'with quotes\\'"')
     40('tag', ['"arg1 \\'with quotes\\'"'], {})
     41
     42# single quotes in single-quoted string
     43>>> tok("tag 'arg1 \\\\'with quotes\\\\''")
     44('tag', ["'arg1 'with quotes''"], {})
     45
     46# double quotes in double-quoted string
     47>>> tok('tag "arg1 \\\\"with quotes\\\\""')
     48('tag', ['"arg1 "with quotes""'], {})
     49
     50# positional argument after named argument not allowed
     51>>> tok('tag name1=arg1 arg2')
     52Traceback (most recent call last):
     53...
     54SyntaxError: template tag syntax error: non-keyword arguments must come before keyword arguments
     55
     56"""
     57
     58from django.template import tokenize_tag_contents as tok
     59
     60if __name__ == "__main__":
     61    import doctest
     62    doctest.testmod()
Back to Top