Exemple #1
0
def firstof(parser, token):
    """
    Outputs the first variable passed that is not False, without escaping.

    Outputs nothing if all the passed variables are False.

    Sample usage::

        {% firstof var1 var2 var3 %}

    This is equivalent to::

        {% if var1 %}
            {{ var1|safe }}
        {% else %}{% if var2 %}
            {{ var2|safe }}
        {% else %}{% if var3 %}
            {{ var3|safe }}
        {% endif %}{% endif %}{% endif %}

    but obviously much cleaner!

    You can also use a literal string as a fallback value in case all
    passed variables are False::

        {% firstof var1 var2 var3 "fallback value" %}

    If you want to escape the output, use a filter tag::

        {% filter force_escape %}
            {% firstof var1 var2 var3 "fallback value" %}
        {% endfilter %}

    """
    bits = token.split_contents()[1:]
    if len(bits) < 1:
        raise TemplateSyntaxError("'firstof' statement requires at least one argument")
    return FirstOfNode([parser.compile_filter(bit) for bit in bits])
Exemple #2
0
def overridelocale(parser, token):
    """
    Overrides locale for certain code block.

    Example usage::

        {% overridelocale 'en' %}
            <p>
                <a href="/login/">{% trans "Log in" %}</a>
            </p>
        {% endoverridelocale %}
    """
    bits = token.split_contents()

    if not 2 == len(bits):
        raise TemplateSyntaxError("{0} expected at least one variable "
                                  "assignment".format(bits[0]))

    language_code = parser.compile_filter(bits[1])

    nodelist = parser.parse(('endoverridelocale', ))
    parser.delete_first_token()
    return OverrideLocaleNode(language_code, nodelist)
Exemple #3
0
def merge_list(value, list_to_merge):
    """
    The ``merge_list`` filter combines two lists.

    .. code-block:: text

        {% for element in first_list|merge_list:second_list %}
            {{ element }}
        {% endfor %}

    To make the result list persistent use in combination with set tag.

    .. code-block:: text

        {% set new_list=first_list|merge_lists:second_list %}

    """
    if not type(value) == list or not type(list_to_merge) == list:
        raise TemplateSyntaxError(
            'Value and argument for merge_lists filter should be both of type '
            'list. Got "{0}" and "{1}".'.format(value, list_to_merge))

    return value + list_to_merge
    def render(self, context):
        element = self.element.resolve(context)

        options = {}
        for key, value in self.kwargs.items():
            options[key] = value.resolve(context)

        # render inner parts
        children = (node for node in self.nodelist if isinstance(node, FormPartNode))
        _render_parts(context, children)

        attrs = (node for node in self.nodelist if isinstance(node, WidgetAttrNode))
        for attr in attrs:
            attr.render(context)

        # render element
        if isinstance(element, BoundField):
            return Field(element.name).render(context, **options)
        elif hasattr(element, 'render'):
            with context.push(parent=element):
                return element.render(context, **options)
        else:
            raise TemplateSyntaxError("form_render can't render %r" % (element,))
Exemple #5
0
def querystring(parser, token):
    """
    Creates a URL (containing only the querystring [including "?"]) derived
    from the current URL's querystring, by updating it with the provided
    keyword arguments.

    Example (imagine URL is ``/abc/?gender=male&name=Brad``)::

        {% querystring "name"="Ayers" "age"=20 %}
        ?name=Ayers&gender=male&age=20
        {% querystring "name"="Ayers" without "gender" %}
        ?name=Ayers

    """
    bits = token.split_contents()
    tag = bits.pop(0)
    updates = token_kwargs(bits, parser)
    # ``bits`` should now be empty of a=b pairs, it should either be empty, or
    # have ``without`` arguments.
    if bits and bits.pop(0) != "without":
        raise TemplateSyntaxError("Malformed arguments to '%s'" % tag)
    removals = [parser.compile_filter(bit) for bit in bits]
    return QuerystringNode(updates, removals)
Exemple #6
0
def tag_display(parser, token):
    """
    Renders a tag using tag_display template.
    Can add a quote type (single or double), and an extra class parameter
    for the tag template. Can store the html in a variable.

    Usage::

        {% tag_display tag %}
        {% tag_display tag quote_type="double" extra_class="" %}
        {% tag_display tag "simple" extra_class="" as tag_html %}

    """
    bits = token.split_contents()
    if len(bits) < 2:
        raise TemplateSyntaxError("'%s' takes at least 1 arguments." % bits[0])
    tag_name = bits[0]
    tag = bits[1]
    bits = bits[2:]

    args, kwargs, asvar = get_node_extra_arguments(parser, bits, tag_name, 2)

    return TagDisplayNode(tag, args, kwargs, asvar)
Exemple #7
0
def object_display(parser, token):
    """
    Renders the item link with or without its popover, depending on display.
    Can add a css defined color and paste html in a variable.

    Usage::

        {% object_display object display %}
        {% object_display object display color="blue" %}
        {% object_display object "list" "black" as user_popover %}

    """
    bits = token.split_contents()
    if len(bits) < 3:
        raise TemplateSyntaxError("'%s' takes at least 2 arguments." % bits[0])
    tag_name = bits[0]
    obj = bits[1]
    display = bits[2]
    bits = bits[3:]

    args, kwargs, asvar = get_node_extra_arguments(parser, bits, tag_name, 1)

    return ObjectDisplayNode(obj, display, args, kwargs, asvar)
Exemple #8
0
def less_paths(path):

    if os.path.isabs(path):
        full_path = path
    else:
        full_path = os.path.join(STATIC_ROOT, path)

    # logger.info("less_paths: path="+path+", full_path="+full_path)
    if settings.DEBUG and not os.path.exists(full_path):
        # while developing it is more confortable
        # searching for the less files rather then
        # doing collectstatics all the time
        full_path = finders.find(path)

        if full_path is None:
            raise TemplateSyntaxError(
                "Can't find staticfile named: {}".format(path))

    file_name = os.path.split(path)[-1]
    output_dir = os.path.join(LESS_ROOT, LESS_OUTPUT_DIR,
                              os.path.dirname(path))

    return full_path, file_name, output_dir
Exemple #9
0
def get_absolute_uri(parser, token):
    """
    Returns the full uri of an object. Value can be pasted in var.

    Syntax::

        {% get_absolute_uri object request %}

    Example::

        {% get_absolute_uri answer request as my_uri %}
    """
    bits = token.split_contents()
    if len(bits) != 3:
        raise TemplateSyntaxError("'%s' takes 2 arguments." % bits[0])
    tag_name = bits[0]
    obj = bits[1]
    request = bits[2]
    bits = bits[3:]

    args, kwargs, asvar = get_node_extra_arguments(parser, bits, tag_name, 0)

    return URINode(obj, request, args, kwargs, asvar)
Exemple #10
0
def parse_token_contents(parser, token):
    """
    Parse template tag contents
    """
    bits = token.split_contents()
    tag = bits.pop(0)
    args = []
    kwargs = {}
    asvar = None
    if len(bits) >= 2 and bits[-2] == "as":
        asvar = bits[-1]
        bits = bits[:-2]
    for bit in bits:
        match = kwarg_re.match(bit)
        if not match:
            raise TemplateSyntaxError(
                'Malformed arguments to tag "{}"'.format(tag))
        name, value = match.groups()
        if name:
            kwargs[name] = parser.compile_filter(value)
        else:
            args.append(parser.compile_filter(value))
    return {"tag": tag, "args": args, "kwargs": kwargs, "asvar": asvar}
Exemple #11
0
def vote_form(parser, token):
    """
    Renders the vote form.
    Can add redirection paths after success. Can store the html in a variable.

    Usage::

        {% vote_form object vote %}
        {% vote_form object vote next %}
        {% vote_form object vote "/" as form %}

    """
    bits = token.split_contents()
    if len(bits) < 2:
        raise TemplateSyntaxError("'%s' takes at least 2 arguments." % bits[0])
    tag_name = bits[0]
    obj = bits[1]
    vote = bits[2]
    bits = bits[3:]

    args, kwargs, asvar = get_node_extra_arguments(parser, bits, tag_name, 1)

    return VoteFormNode(obj, vote, args, kwargs, asvar)
def do_breadcrumbs(parser, token):
    tag_name, *bits = token.split_contents(
    )  # разбивает исходную строку тега по пробелам
    asvar = None

    if len(bits) >= 2 and bits[
            -2] == 'as':  # если есть более двух аргументов и предпоследний из них равен as
        asvar = bits[
            -1]  # тогда результат тега должен быть сохранен в переменную, выставляем флаг
        bits = bits[:-2]  # отрезаем as и имя переменной

    args = []
    kwargs = {}

    for bit in bits:
        match = kwarg_re.match(
            bit
        )  # проверяет, что аргумент корректный: либо позиционный, либо именованный

        if not match:  # если совпадений не найдено - синтаксис не корректный
            raise TemplateSyntaxError(
                f'Malformed arguments to "{tag_name}" tag.')

        name, value = match.groups()

        # compile_filter возвращает FilterExpression,
        # который разбирает токен как переменную с необязательными фильтрами

        if name:
            kwargs[name] = parser.compile_filter(value)
        else:
            args.append(parser.compile_filter(value))

    nodelist = parser.parse(('endbreadcrumb', ))
    parser.delete_first_token()

    return BreadcrumbNode(nodelist, *args, asvar=asvar, **kwargs)
Exemple #13
0
    def render(self, context):
        try:
            value = self.val_expr.resolve(context)
            max_value = self.max_expr.resolve(context)
            max_width = int(self.max_width.resolve(context))
        except VariableDoesNotExist:
            return ''
        except (ValueError, TypeError):
            raise TemplateSyntaxError("widthratio final argument must be a number")
        try:
            value = float(value)
            max_value = float(max_value)
            ratio = (value / max_value) * max_width
            result = str(int(round(ratio)))
        except ZeroDivisionError:
            return '0'
        except (ValueError, TypeError, OverflowError):
            return ''

        if self.asvar:
            context[self.asvar] = result
            return ''
        else:
            return result
Exemple #14
0
def content_info(parser, token):
    """
    Displays content creation related info: author, creation date...

    Usage ('pic_size' is optional)::

        {% content_info content display %}
        {% content_info content display pic_size %}

        where display can be: "signature", "signature-author", "signature-pic"
        "header"

    """
    bits = token.split_contents()
    if len(bits) < 2:
        raise TemplateSyntaxError("'%s' takes at least 2 arguments." % bits[0])
    tag_name = bits[0]
    content = bits[1]
    display = bits[2]
    bits = bits[3:]

    args, kwargs, asvar = get_node_extra_arguments(parser, bits, tag_name, 1)

    return ContentInfoNode(content, display, args, kwargs, asvar)
Exemple #15
0
def source_display(parser, token):
    """
    Renders the sources of a content object whether it be
    one or several products and/or one or several tags.
    Can add a separator (default is 'text') and paste html in a variable.

    Usage::

        {% source_display content display %}
        {% source_display content "list" as source %}
        {% source_display content "list" sep="," as source %}

    """
    bits = token.split_contents()
    if len(bits) < 3:
        raise TemplateSyntaxError("'%s' takes at least 2 arguments." % bits[0])
    tag_name = bits[0]
    obj = bits[1]
    display = bits[2]
    bits = bits[3:]

    args, kwargs, asvar = get_node_extra_arguments(parser, bits, tag_name, 1)

    return SourceDisplayNode(obj, display, args, kwargs, asvar)
Exemple #16
0
def mdctime(parser, token):
    """ Usage: {% mdctime datetime_var [format_name] [tz_var] %}

        If a tz is to be selected a format name must also be given

        args:
            datetime: a utc datetime object to display
            format_name:  a format name from settings.TIME_FORMATS
                        defaults to settings DEFAULT_TIME_FORMAT
            tz_var:    the tz to cast the time into
                        default to the users tz if she is logged in
                        othewise to settings.DEFAULT_TZ
    """

    args = token.split_contents()[1:]
    if args == [] or len(args) > 3 :
        raise TemplateSyntaxError(
            "Usage: {% mdctime datetime_var [format_name] [tz_var] %}")
    if  len(args) == 1:
        return MDCTNode(args[0])
    if len(args) == 2:
        return MDCTNode(args[0], args[1])
    if len(args) == 3:
        return MDCTNode(args[0], args[1], args[2])
def snippet(parser, token):
    """
    Demarcates replaceable text, outputs the wrapped text or the text of a
    snippet with matching key.

    Examples::

        {% snippet 'greeting' %}Hello world{% endsnippet %}

        {% snippet 'greeting' richtext=True %}<p>Hey!</p>{% endsnippet %}
    """
    nodelist = parser.parse(('endsnippet',))
    parser.delete_first_token()

    try:
        tag_name = token.split_contents()
        bits = token.split_contents()[1:]
    except IndexError:
        raise TemplateSyntaxError("%s tag takes at least one argument" % bits[0])

    key = bits[0]
    options = build_options(bits[1:], tag_name)

    return SnippetNode(nodelist, key, **options)
Exemple #18
0
    def render(self, context):
        """Add the tournament in the context to the arguments, then render as
        usual."""

        # In order to take advantage of the superclass's method, the easiest
        # thing to do is to grab the string we want to insert, and turn it into
        # a (literal) Variable for the superclass. This is a little roundabout,
        # since we're creating a variable only for it to be turned back into
        # the string again, but it's better than copy-pasting the superclass's
        # method itself.
        try:
            tournament_slug = context['tournament'].slug
        except KeyError:
            raise TemplateSyntaxError("tournamenturl can only be used in contexts with a tournament rtf ")
        tournament_slug = Variable("'" + tournament_slug + "'")
        self.args = list(self._args)      # make a copy in case render() gets called multiple times
        self.kwargs = dict(self._kwargs)

        if self.kwargs:
            self.kwargs['tournament_slug'] = tournament_slug
        else:
            self.args.insert(0, tournament_slug)

        return super().render(context)
Exemple #19
0
def do_filter(parser, token):
    """
    Filters the contents of the block through variable filters.

    Filters can also be piped through each other, and they can have
    arguments -- just like in variable syntax.

    Sample usage::

        {% filter force_escape|lower %}
            This text will be HTML-escaped, and will appear in lowercase.
        {% endfilter %}
    """
    _, rest = token.contents.split(None, 1)
    filter_expr = parser.compile_filter("var|%s" % (rest))
    for func, unused in filter_expr.filters:
        if getattr(func, '_decorated_function',
                   func).__name__ in ('escape', 'safe'):
            raise TemplateSyntaxError(
                '"filter %s" is not permitted.  Use the "autoescape" tag instead.'
                % func.__name__)
    nodelist = parser.parse(('endfilter', ))
    parser.delete_first_token()
    return FilterNode(filter_expr, nodelist)
Exemple #20
0
        def simple_assignment_tag(self,
                                  func=None,
                                  takes_context=None,
                                  name=None):
            '''
            Like assignment_tag but when "as" not provided, falls back to simple_tag behavior!
            NOTE: this is based on Django's assignment_tag implementation, modified as needed.

            https://gist.github.com/natevw/f14812604be62c073461
            '''

            # (nvw) imports necessary to match original context

            def dec(func):
                params, varargs, varkw, defaults = getargspec(func)

                # (nvw) added from Django's simple_tag implementation
                class SimpleNode(TagHelperNode):
                    def render(self, context):
                        resolved_args, resolved_kwargs = self.get_resolved_arguments(
                            context)
                        return func(*resolved_args, **resolved_kwargs)

                class AssignmentNode(TagHelperNode):
                    def __init__(self, takes_context, args, kwargs,
                                 target_var):
                        super(AssignmentNode,
                              self).__init__(takes_context, args, kwargs)
                        self.target_var = target_var

                    def render(self, context):
                        resolved_args, resolved_kwargs = self.get_resolved_arguments(
                            context)
                        context[self.target_var] = func(
                            *resolved_args, **resolved_kwargs)
                        return ''

                function_name = (name or getattr(func, '_decorated_function',
                                                 func).__name__)

                def compile_func(parser, token):
                    bits = token.split_contents()[1:]
                    if len(bits) > 2 and bits[-2] == 'as':
                        target_var = bits[-1]
                        bits = bits[:-2]
                        args, kwargs = parse_bits(parser, bits, params,
                                                  varargs, varkw, defaults,
                                                  takes_context, function_name)
                        return AssignmentNode(takes_context, args, kwargs,
                                              target_var)
                    else:
                        args, kwargs = parse_bits(parser, bits, params,
                                                  varargs, varkw, defaults,
                                                  takes_context, function_name)
                        return SimpleNode(takes_context, args, kwargs)

                compile_func.__doc__ = func.__doc__
                self.tag(function_name, compile_func)
                return func

            if func is None:
                # @register.assignment_tag(...)
                return dec
            elif callable(func):
                # @register.assignment_tag
                return dec(func)
            else:
                raise TemplateSyntaxError(
                    "Invalid arguments provided to assignment_tag")
Exemple #21
0
def do_for(parser, token):
    """
    Loops over each item in an array.

    For example, to display a list of athletes given ``athlete_list``::

        <ul>
        {% for athlete in athlete_list %}
            <li>{{ athlete.name }}</li>
        {% endfor %}
        </ul>

    You can loop over a list in reverse by using
    ``{% for obj in list reversed %}``.

    You can also unpack multiple values from a two-dimensional array::

        {% for key,value in dict.items %}
            {{ key }}: {{ value }}
        {% endfor %}

    The ``for`` tag can take an optional ``{% empty %}`` clause that will
    be displayed if the given array is empty or could not be found::

        <ul>
          {% for athlete in athlete_list %}
            <li>{{ athlete.name }}</li>
          {% empty %}
            <li>Sorry, no athletes in this list.</li>
          {% endfor %}
        <ul>

    The above is equivalent to -- but shorter, cleaner, and possibly faster
    than -- the following::

        <ul>
          {% if althete_list %}
            {% for athlete in athlete_list %}
              <li>{{ athlete.name }}</li>
            {% endfor %}
          {% else %}
            <li>Sorry, no athletes in this list.</li>
          {% endif %}
        </ul>

    The for loop sets a number of variables available within the loop:

        ==========================  ================================================
        Variable                    Description
        ==========================  ================================================
        ``forloop.counter``         The current iteration of the loop (1-indexed)
        ``forloop.counter0``        The current iteration of the loop (0-indexed)
        ``forloop.revcounter``      The number of iterations from the end of the
                                    loop (1-indexed)
        ``forloop.revcounter0``     The number of iterations from the end of the
                                    loop (0-indexed)
        ``forloop.first``           True if this is the first time through the loop
        ``forloop.last``            True if this is the last time through the loop
        ``forloop.parentloop``      For nested loops, this is the loop "above" the
                                    current one
        ==========================  ================================================

    """
    bits = token.contents.split()
    if len(bits) < 4:
        raise TemplateSyntaxError("'for' statements should have at least four"
                                  " words: %s" % token.contents)

    is_reversed = bits[-1] == 'reversed'
    in_index = is_reversed and -3 or -2
    if bits[in_index] != 'in':
        raise TemplateSyntaxError("'for' statements should use the format"
                                  " 'for x in y': %s" % token.contents)

    loopvars = re.split(r' *, *', ' '.join(bits[1:in_index]))
    for var in loopvars:
        if not var or ' ' in var:
            raise TemplateSyntaxError("'for' tag received an invalid argument:"
                                      " %s" % token.contents)

    sequence = parser.compile_filter(bits[in_index + 1])
    nodelist_loop = parser.parse((
        'empty',
        'endfor',
    ))
    token = parser.next_token()
    if token.contents == 'empty':
        nodelist_empty = parser.parse(('endfor', ))
        parser.delete_first_token()
    else:
        nodelist_empty = None
    return ForNode(loopvars, sequence, is_reversed, nodelist_loop,
                   nodelist_empty)
Exemple #22
0
def cycle(parser, token):
    """
    Cycles among the given strings each time this tag is encountered.

    Within a loop, cycles among the given strings each time through
    the loop::

        {% for o in some_list %}
            <tr class="{% cycle 'row1' 'row2' %}">
                ...
            </tr>
        {% endfor %}

    Outside of a loop, give the values a unique name the first time you call
    it, then use that name each sucessive time through::

            <tr class="{% cycle 'row1' 'row2' 'row3' as rowcolors %}">...</tr>
            <tr class="{% cycle rowcolors %}">...</tr>
            <tr class="{% cycle rowcolors %}">...</tr>

    You can use any number of values, separated by spaces. Commas can also
    be used to separate values; if a comma is used, the cycle values are
    interpreted as literal strings.

    The optional flag "silent" can be used to prevent the cycle declaration
    from returning any value::

        {% cycle 'row1' 'row2' as rowcolors silent %}{# no value here #}
        {% for o in some_list %}
            <tr class="{% cycle rowcolors %}">{# first value will be "row1" #}
                ...
            </tr>
        {% endfor %}

    """

    # Note: This returns the exact same node on each {% cycle name %} call;
    # that is, the node object returned from {% cycle a b c as name %} and the
    # one returned from {% cycle name %} are the exact same object. This
    # shouldn't cause problems (heh), but if it does, now you know.
    #
    # Ugly hack warning: This stuffs the named template dict into parser so
    # that names are only unique within each template (as opposed to using
    # a global variable, which would make cycle names have to be unique across
    # *all* templates.

    args = token.split_contents()

    if len(args) < 2:
        raise TemplateSyntaxError(
            "'cycle' tag requires at least two arguments")

    if ',' in args[1]:
        # Backwards compatibility: {% cycle a,b %} or {% cycle a,b as foo %}
        # case.
        args[1:2] = ['"%s"' % arg for arg in args[1].split(",")]

    if len(args) == 2:
        # {% cycle foo %} case.
        name = args[1]
        if not hasattr(parser, '_namedCycleNodes'):
            raise TemplateSyntaxError(
                "No named cycles in template. '%s' is not defined" % name)
        if not name in parser._namedCycleNodes:
            raise TemplateSyntaxError("Named cycle '%s' does not exist" % name)
        return parser._namedCycleNodes[name]

    as_form = False

    if len(args) > 4:
        # {% cycle ... as foo [silent] %} case.
        if args[-3] == "as":
            if args[-1] != "silent":
                raise TemplateSyntaxError(
                    "Only 'silent' flag is allowed after cycle's name, not '%s'."
                    % args[-1])
            as_form = True
            silent = True
            args = args[:-1]
        elif args[-2] == "as":
            as_form = True
            silent = False

    if as_form:
        name = args[-1]
        values = [parser.compile_filter(arg) for arg in args[1:-2]]
        node = CycleNode(values, name, silent=silent)
        if not hasattr(parser, '_namedCycleNodes'):
            parser._namedCycleNodes = {}
        parser._namedCycleNodes[name] = node
    else:
        values = [parser.compile_filter(arg) for arg in args[1:]]
        node = CycleNode(values)
    return node
Exemple #23
0
def url(parser, token):
    """
    Returns an absolute URL matching given view with its parameters.

    This is a way to define links that aren't tied to a particular URL
    configuration::

        {% url "path.to.some_view" arg1 arg2 %}

        or

        {% url "path.to.some_view" name1=value1 name2=value2 %}

    The first argument is a path to a view. It can be an absolute Python path
    or just ``app_name.view_name`` without the project name if the view is
    located inside the project.

    Other arguments are space-separated values that will be filled in place of
    positional and keyword arguments in the URL. Don't mix positional and
    keyword arguments.

    All arguments for the URL should be present.

    For example if you have a view ``app_name.client`` taking client's id and
    the corresponding line in a URLconf looks like this::

        ('^client/(\d+)/$', 'app_name.client')

    and this app's URLconf is included into the project's URLconf under some
    path::

        ('^clients/', include('project_name.app_name.urls'))

    then in a template you can create a link for a certain client like this::

        {% url "app_name.client" client.id %}

    The URL will look like ``/clients/client/123/``.

    The first argument can also be a named URL instead of the Python path to
    the view callable. For example if the URLconf entry looks like this::

        url('^client/(\d+)/$', name='client-detail-view')

    then in the template you can use::

        {% url "client-detail-view" client.id %}

    There is even another possible value type for the first argument. It can be
    the name of a template variable that will be evaluated to obtain the view
    name or the URL name, e.g.::

        {% with view_path="app_name.client" %}
        {% url view_path client.id %}
        {% endwith %}

        or,

        {% with url_name="client-detail-view" %}
        {% url url_name client.id %}
        {% endwith %}

    """
    bits = token.split_contents()
    if len(bits) < 2:
        raise TemplateSyntaxError("'%s' takes at least one argument"
                                  " (path to a view)" % bits[0])
    viewname = parser.compile_filter(bits[1])
    args = []
    kwargs = {}
    asvar = None
    bits = bits[2:]
    if len(bits) >= 2 and bits[-2] == 'as':
        asvar = bits[-1]
        bits = bits[:-2]

    if len(bits):
        for bit in bits:
            match = kwarg_re.match(bit)
            if not match:
                raise TemplateSyntaxError("Malformed arguments to url tag")
            name, value = match.groups()
            if name:
                kwargs[name] = parser.compile_filter(value)
            else:
                args.append(parser.compile_filter(value))

    return URLNode(viewname, args, kwargs, asvar)
Exemple #24
0
def regroup(parser, token):
    """
    Regroups a list of alike objects by a common attribute.

    This complex tag is best illustrated by use of an example:  say that
    ``people`` is a list of ``Person`` objects that have ``first_name``,
    ``last_name``, and ``gender`` attributes, and you'd like to display a list
    that looks like:

        * Male:
            * George Bush
            * Bill Clinton
        * Female:
            * Margaret Thatcher
            * Colendeeza Rice
        * Unknown:
            * Pat Smith

    The following snippet of template code would accomplish this dubious task::

        {% regroup people by gender as grouped %}
        <ul>
        {% for group in grouped %}
            <li>{{ group.grouper }}
            <ul>
                {% for item in group.list %}
                <li>{{ item }}</li>
                {% endfor %}
            </ul>
        {% endfor %}
        </ul>

    As you can see, ``{% regroup %}`` populates a variable with a list of
    objects with ``grouper`` and ``list`` attributes.  ``grouper`` contains the
    item that was grouped by; ``list`` contains the list of objects that share
    that ``grouper``.  In this case, ``grouper`` would be ``Male``, ``Female``
    and ``Unknown``, and ``list`` is the list of people with those genders.

    Note that ``{% regroup %}`` does not work when the list to be grouped is not
    sorted by the key you are grouping by!  This means that if your list of
    people was not sorted by gender, you'd need to make sure it is sorted
    before using it, i.e.::

        {% regroup people|dictsort:"gender" by gender as grouped %}

    """
    firstbits = token.contents.split(None, 3)
    if len(firstbits) != 4:
        raise TemplateSyntaxError("'regroup' tag takes five arguments")
    target = parser.compile_filter(firstbits[1])
    if firstbits[2] != 'by':
        raise TemplateSyntaxError(
            "second argument to 'regroup' tag must be 'by'")
    lastbits_reversed = firstbits[3][::-1].split(None, 2)
    if lastbits_reversed[1][::-1] != 'as':
        raise TemplateSyntaxError("next-to-last argument to 'regroup' tag must"
                                  " be 'as'")
    var_name = lastbits_reversed[0][::-1]
    # RegroupNode will take each item in 'target', put it in the context under
    # 'var_name', evaluate 'var_name'.'expression' in the current context, and
    # group by the resulting value. After all items are processed, it will
    # save the final result in the context under 'var_name', thus clearing the
    # temporary values. This hack is necessary because the template engine
    # doesn't provide a context-aware equivalent of Python's getattr.
    expression = parser.compile_filter(var_name +
                                       VARIABLE_ATTRIBUTE_SEPARATOR +
                                       lastbits_reversed[2][::-1])
    return RegroupNode(target, expression, var_name)
Exemple #25
0
 def source_error(self, source, msg):
     e = TemplateSyntaxError(msg)
     e.django_template_source = source
     return e
Exemple #26
0
def url(parser, token):
    """
    Returns an absolute URL matching given view with its parameters.

    This is a way to define links that aren't tied to a particular URL
    configuration::

        {% url path.to.some_view arg1 arg2 %}

        or

        {% url path.to.some_view name1=value1 name2=value2 %}

    The first argument is a path to a view. It can be an absolute python path
    or just ``app_name.view_name`` without the project name if the view is
    located inside the project.  Other arguments are comma-separated values
    that will be filled in place of positional and keyword arguments in the
    URL. All arguments for the URL should be present.

    For example if you have a view ``app_name.client`` taking client's id and
    the corresponding line in a URLconf looks like this::

        ('^client/(\d+)/$', 'app_name.client')

    and this app's URLconf is included into the project's URLconf under some
    path::

        ('^clients/', include('project_name.app_name.urls'))

    then in a template you can create a link for a certain client like this::

        {% url app_name.client client.id %}

    The URL will look like ``/clients/client/123/``.
    """

    import warnings
    warnings.warn(
        'The syntax for the url template tag is changing. Load the `url` tag from the `future` tag library to start using the new behavior.',
        category=PendingDeprecationWarning)

    bits = token.split_contents()
    if len(bits) < 2:
        raise TemplateSyntaxError("'%s' takes at least one argument"
                                  " (path to a view)" % bits[0])
    viewname = bits[1]
    args = []
    kwargs = {}
    asvar = None
    bits = bits[2:]
    if len(bits) >= 2 and bits[-2] == 'as':
        asvar = bits[-1]
        bits = bits[:-2]

    # Backwards compatibility: check for the old comma separated format
    # {% url urlname arg1,arg2 %}
    # Initial check - that the first space separated bit has a comma in it
    if bits and ',' in bits[0]:
        check_old_format = True
        # In order to *really* be old format, there must be a comma
        # in *every* space separated bit, except the last.
        for bit in bits[1:-1]:
            if ',' not in bit:
                # No comma in this bit. Either the comma we found
                # in bit 1 was a false positive (e.g., comma in a string),
                # or there is a syntax problem with missing commas
                check_old_format = False
                break
    else:
        # No comma found - must be new format.
        check_old_format = False

    if check_old_format:
        # Confirm that this is old format by trying to parse the first
        # argument. An exception will be raised if the comma is
        # unexpected (i.e. outside of a static string).
        match = kwarg_re.match(bits[0])
        if match:
            value = match.groups()[1]
            try:
                parser.compile_filter(value)
            except TemplateSyntaxError:
                bits = ''.join(bits).split(',')

    # Now all the bits are parsed into new format,
    # process them as template vars
    if len(bits):
        for bit in bits:
            match = kwarg_re.match(bit)
            if not match:
                raise TemplateSyntaxError("Malformed arguments to url tag")
            name, value = match.groups()
            if name:
                kwargs[name] = parser.compile_filter(value)
            else:
                args.append(parser.compile_filter(value))

    return URLNode(viewname, args, kwargs, asvar, legacy_view_name=True)
Exemple #27
0
def regroup(parser, token):
    """
    Regroups a list of alike objects by a common attribute.

    This complex tag is best illustrated by use of an example:  say that
    ``people`` is a list of ``Person`` objects that have ``first_name``,
    ``last_name``, and ``gender`` attributes, and you'd like to display a list
    that looks like:

        * Male:
            * George Bush
            * Bill Clinton
        * Female:
            * Margaret Thatcher
            * Colendeeza Rice
        * Unknown:
            * Pat Smith

    The following snippet of template code would accomplish this dubious task::

        {% regroup people by gender as grouped %}
        <ul>
        {% for group in grouped %}
            <li>{{ group.grouper }}
            <ul>
                {% for item in group.list %}
                <li>{{ item }}</li>
                {% endfor %}
            </ul>
        {% endfor %}
        </ul>

    As you can see, ``{% regroup %}`` populates a variable with a list of
    objects with ``grouper`` and ``list`` attributes.  ``grouper`` contains the
    item that was grouped by; ``list`` contains the list of objects that share
    that ``grouper``.  In this case, ``grouper`` would be ``Male``, ``Female``
    and ``Unknown``, and ``list`` is the list of people with those genders.

    Note that ``{% regroup %}`` does not work when the list to be grouped is not
    sorted by the key you are grouping by!  This means that if your list of
    people was not sorted by gender, you'd need to make sure it is sorted
    before using it, i.e.::

        {% regroup people|dictsort:"gender" by gender as grouped %}

    """
    firstbits = token.contents.split(None, 3)
    if len(firstbits) != 4:
        raise TemplateSyntaxError("'regroup' tag takes five arguments")
    target = parser.compile_filter(firstbits[1])
    if firstbits[2] != 'by':
        raise TemplateSyntaxError(
            "second argument to 'regroup' tag must be 'by'")
    lastbits_reversed = firstbits[3][::-1].split(None, 2)
    if lastbits_reversed[1][::-1] != 'as':
        raise TemplateSyntaxError("next-to-last argument to 'regroup' tag must"
                                  " be 'as'")

    expression = parser.compile_filter(lastbits_reversed[2][::-1])

    var_name = lastbits_reversed[0][::-1]
    return RegroupNode(target, expression, var_name)
Exemple #28
0
                        temp_lib.filters[name] = lib.filters[name]
                elif name in lib.filters:
                    temp_lib.filters[name] = lib.filters[name]
                else:
                    raise TemplateSyntaxError(
                        "'%s' is not a valid tag or filter in tag library '%s'"
                        % (name, taglib))
            parser.add_library(temp_lib)
    else:
        for taglib in bits[1:]:
            # add the library to the parser
            try:
                lib = get_library(taglib)
                parser.add_library(lib)
            except InvalidTemplateLibrary, e:
                raise TemplateSyntaxError(
                    "'%s' is not a valid tag library: %s" % (taglib, e))
    return LoadNode()


load = register.tag(load)


#@register.tag
def now(parser, token):
    """
    Displays the date, formatted according to the given string.

    Uses the same format as PHP's ``date()`` function; see http://php.net/date
    for all the possible values.

    Sample usage::
Exemple #29
0
 def __mod__(self, other):
     from django.template.base import TemplateSyntaxError
     raise TemplateSyntaxError(
         "Undefined variable or unknown value for: \"%s\"" % other)
Exemple #30
0
    def render(self, context):

        if not hasattr(self, 'base_view_name'):
            self.base_view_name = copy(self.view_name)
        else:
            self.view_name = copy(self.base_view_name)
        view_name = self.view_name.resolve(context)

        ignoreErrors = 'ignoreErrors' in self.kwargs and self.kwargs.pop(
            'ignoreErrors').resolve(context) or False

        group_arg = self.kwargs["group"].resolve(context)
        group_slug = ""
        foreign_portal = None
        portal_id = getattr(self, '_portal_id', None)
        force_local_domain = getattr(self, '_force_local_domain', False)

        try:
            # the portal id if given to the tag can override the group's portal
            self._portal_id = self.kwargs["portal_id"].resolve(context)
            portal_id = self._portal_id
            del self.kwargs["portal_id"]
        except KeyError:
            pass

        try:
            # this will retain the local domain. useful for avoiding POSTs to cross-portal domains and CSRF-failing
            self._force_local_domain = bool(
                self.kwargs["force_local_domain"].resolve(context))
            force_local_domain = self._force_local_domain
            del self.kwargs["force_local_domain"]
        except KeyError:
            pass

        patched_group_slug_arg = None

        # we accept a group object or a group slug
        if issubclass(group_arg.__class__, get_cosinnus_group_model()):
            # determine the portal from the group
            group_slug = group_arg.slug

            # if not explicitly given, learn the portal id from the group
            if not portal_id:
                portal_id = group_arg.portal_id
                if not portal_id == CosinnusPortal.get_current().id:
                    foreign_portal = group_arg.portal

            # we patch the variable given to the tag here, to restore the regular slug-passed-url-resolver functionality
            patched_group_slug_arg = deepcopy(self.kwargs['group'])
            patched_group_slug_arg.token += '.slug'
            patched_group_slug_arg.var.var += '.slug'
            patched_group_slug_arg.var.lookups = list(
                self.kwargs['group'].var.lookups) + ['slug']
        elif not isinstance(group_arg, six.string_types):
            raise TemplateSyntaxError(
                "'group_url' tag requires a group kwarg that is a group or a slug! Have you passed one? (You passed: 'group=%s')"
                % group_arg)
        else:
            group_slug = group_arg

        # make sure we have the foreign portal. we might not have yet retrieved it if we had a portal id explicitly set
        if portal_id and not portal_id == CosinnusPortal.get_current(
        ).id and not foreign_portal:
            foreign_portal = CosinnusPortal.objects.get(id=portal_id)

        try:
            try:
                view_name = group_aware_url_name(view_name, group_slug,
                                                 portal_id)
            except CosinnusGroup.DoesNotExist:
                # ignore errors if the group doesn't exist if it is inactive (return empty link)
                if ignoreErrors or (not group_arg.is_active):
                    return ''

                logger.error(
                    u'Cosinnus__group_url_tag: Could not find group for: group_arg: %s, view_name: %s, group_slug: %s, portal_id: %s'
                    % (str(group_arg), view_name, group_slug, portal_id))
                raise

            self.view_name.var = view_name
            self.view_name.token = "'%s'" % view_name

            # to retain django core code for rendering, we patch this node to look like a proper url node,
            # with a slug argument.
            # and then restore it later, so that the node object can be reused for other group arguments
            # if we didn't do that, this group node's group argument would have been replaced already, and
            # lost to other elements that use the group_url tag in a for-loop, for example
            # (we cannot store anything on the object itself, down that road madness lies)
            if patched_group_slug_arg:
                self.kwargs[
                    'group'], patched_group_slug_arg = patched_group_slug_arg, self.kwargs[
                        'group']

            ret_url = super(GroupURLNode, self).render(context)
            # swap back the patched arg for the original
            if patched_group_slug_arg:
                self.kwargs['group'] = patched_group_slug_arg

            if foreign_portal and not force_local_domain:
                domain = get_domain_for_portal(foreign_portal)
                # attach to either output or given "as" variable
                if self.asvar:
                    context[self.asvar] = domain + context[self.asvar]
                else:
                    ret_url = domain + ret_url

            return ret_url
        except:
            if ignoreErrors:
                return ''
            else:
                raise
Exemple #31
0
 def __mod__(self, other):
     from django.template.base import TemplateSyntaxError
     raise TemplateSyntaxError("Invalid variable : '%s'" % other)