Ticket #2016: fix2016.patch

File fix2016.patch, 7.0 KB (added by Matthias Kestenholz, 14 years ago)
  • django/template/__init__.py

    commit bb81dd7ed59a6ec1f493e255b9dbbe7afa1dee53
    Author: Matthias Kestenholz <mk@spinlock.ch>
    Date:   Thu Oct 7 13:09:17 2010 +0200
    
        WIP
    
    diff --git a/django/template/__init__.py b/django/template/__init__.py
    index c316786..75e81c4 100644
    a b class VariableNode(Node):  
    848848            return ''
    849849        return _render_value_in_context(output, context)
    850850
    851 def generic_tag_compiler(params, defaults, name, node_class, parser, token):
    852     "Returns a template.Node subclass."
    853     bits = token.split_contents()[1:]
     851def match_number_of_arguments(bits, params, defaults, name):
    854852    bmax = len(params)
    855853    def_len = defaults and len(defaults) or 0
    856854    bmin = bmax - def_len
    def generic_tag_compiler(params, defaults, name, node_class, parser, token):  
    860858        else:
    861859            message = "%s takes between %s and %s arguments" % (name, bmin, bmax)
    862860        raise TemplateSyntaxError(message)
     861
     862def generic_tag_compiler(params, defaults, name, node_class, parser, token):
     863    "Returns a template.Node subclass."
     864    bits = token.split_contents()[1:]
     865    match_number_of_arguments(bits, params, defaults, name)
    863866    return node_class(bits)
    864867
    865868class Library(object):
    class Library(object):  
    931934        self.tag(getattr(func, "_decorated_function", func).__name__, compile_func)
    932935        return func
    933936
     937    def object_tag(self, func):
     938        params, xx, xxx, defaults = getargspec(func)
     939
     940        class ObjectNode(Node):
     941            def __init__(self, vars_to_resolve, var_name):
     942                self.vars_to_resolve = map(Variable, vars_to_resolve)
     943                self.var_name = var_name
     944
     945            def render(self, context):
     946                resolved_vars = [var.resolve(context) for var in self.vars_to_resolve]
     947                obj = func(*resolved_vars)
     948                context[self.var_name] = obj
     949                return ''
     950
     951        def object_tag_compiler(params, defaults, name, node_class, parser, token):
     952            bits = token.split_contents()[1:]
     953
     954            if len(bits) < 2 or bits[-2] != 'as':
     955                raise TemplateSyntaxError("the next to last argument to %s must be 'as'" % name)
     956
     957            var_name, bits = bits[-1], bits[:-2]
     958            match_number_of_arguments(bits, params, defaults, name)
     959
     960            return node_class(bits, var_name)
     961
     962        compile_func = curry(object_tag_compiler, params, defaults, getattr(func, "_decorated_function", func).__name__, ObjectNode)
     963        compile_func.__doc__ = func.__doc__
     964
     965        self.tag(getattr(func, "_decorated_function", func).__name__, compile_func)
     966
     967        return func
     968
    934969    def inclusion_tag(self, file_name, context_class=Context, takes_context=False):
    935970        def dec(func):
    936971            params, xx, xxx, defaults = getargspec(func)
  • docs/howto/custom-template-tags.txt

    diff --git a/docs/howto/custom-template-tags.txt b/docs/howto/custom-template-tags.txt
    index c4d2315..43c8812 100644
    a b class, like so::  
    858858The difference here is that ``do_current_time()`` grabs the format string and
    859859the variable name, passing both to ``CurrentTimeNode3``.
    860860
     861Shortcut for loading objects into template variables
     862~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     863
     864.. versionadded: 1.2
     865
     866If you only need to retrieve and store an object in a template variable, it
     867might seem cumbersome to write both a renderer and a compilation function
     868for such an easy task.
     869
     870That is why Django provides yet another shortcut -- ``object_tag`` -- which
     871makes it easy to write tags that loads objects into template variables.
     872
     873Its use is very similar to ``simple_tag`` in the way that it takes care of
     874all the argument parsing for you, and only requires a single return value --
     875the object you'd like to insert into the template variable.
     876
     877Example::
     878
     879    def get_latest_polls(max_num):
     880        return Poll.objects.order_by('-pub_date')[:max_num]
     881
     882    register.object_tag(get_latest_polls)
     883
     884Or if you wish to use the Python 2.4 decorator syntax::
     885
     886    @register.object_tag
     887    def get_latest_polls(max_num):
     888        return Poll.objects.order_by('-pub_date')[:max_num]
     889
     890This tag returns the latest ``Poll``-objects, sorted by descending order, and
     891limited by the value of ``max_num``. Its use in a template would look like
     892this:
     893
     894.. code-block:: html+django
     895
     896    {% get_latest_polls 5 as latest_polls %}
     897
     898Which would retrieve the 5 latest polls and store them inside a template
     899variable named "latest_polls".
     900
     901Note that the following syntax is *mandatory* for all object_tag's:
     902
     903.. code-block:: html+django
     904
     905    {% tag_name [args] as <var_name> %}
     906
     907Where ``args`` is the arguments for the templatetag ``tag_name``, and
     908``var_name`` is the name of the template variable in which the returned object
     909should be stored.
     910
    861911Parsing until another block tag
    862912~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    863913
  • new file tests/regressiontests/templates/object_tag.py

    diff --git a/tests/regressiontests/templates/object_tag.py b/tests/regressiontests/templates/object_tag.py
    new file mode 100644
    index 0000000..5f67b9e
    - +  
     1object_tag_tests = """
     2>>> t = template.Template('{% load custom %}{% get_meaning_of_life as answer %}{{ answer }}')
     3>>> t.render(template.Context())
     4u"42"
     5>>> t = template.Template('{% load custom %}{% get_mascot_with "awesomeness" "magical powers" as pony %}{{ pony }}')
     6>>> t.render(template.Context())
     7u"This mascot is filled with awesomeness and magical powers"
     8>>> t = template.Template('{% load custom %}{% count "e" word as num %}{{ num }}')
     9>>> t.render(template.Context({'word': 'beefcake'}))
     10u"3"
     11"""
  • tests/regressiontests/templates/templatetags/custom.py

    diff --git a/tests/regressiontests/templates/templatetags/custom.py b/tests/regressiontests/templates/templatetags/custom.py
    index fdf8d10..bbb8c08 100644
    a b trim = stringfilter(trim)  
    99
    1010register.filter(trim)
    1111
     12def get_meaning_of_life():
     13    return 42
     14register.object_tag(get_meaning_of_life)
     15
     16def get_mascot_with(power_one, power_two):
     17    return 'This mascot is filled with %s and %s' % (power_one, power_two)
     18register.object_tag(get_mascot_with)
     19
     20def count(char, word):
     21    return word.count(char)
     22register.object_tag(count)
  • tests/regressiontests/templates/tests.py

    diff --git a/tests/regressiontests/templates/tests.py b/tests/regressiontests/templates/tests.py
    index 9e2d175..1a36e2d 100644
    a b from parser import token_parsing, filter_parsing, variable_parsing  
    2727from unicode import unicode_tests
    2828from nodelist import NodelistTest
    2929from smartif import *
     30from object_tag import object_tag_tests
    3031
    3132try:
    3233    from loaders import *
    __test__ = {  
    4344    'filter_parsing': filter_parsing,
    4445    'variable_parsing': variable_parsing,
    4546    'custom_filters': custom_filters,
     47    'object_tag': object_tag_tests,
    4648}
    4749
    4850#################################
Back to Top