# Call Template._render explicitly so the parser context stays # the same. return compiled_parent._render(context) def do_override(parser, token): """ Signal that this template overrides a parent template. This tag may be used in two ways: ``{% override "base" %}`` (with quotes) uses the literal value "base" as the name of the parent template to extend, or ``{% override variable %}`` uses the value of ``variable`` as either the name of the parent template to override (if it evaluates to a string) or as the parent tempate itelf (if it evaluates to a Template object). """ bits = token.split_contents() if len(bits) != 2: raise TemplateSyntaxError("'%s' takes one argument" % bits[0]) parent_name, parent_name_expr = None, None if bits[1][0] in ('"', "'") and bits[1][-1] == bits[1][0]: parent_name = bits[1][1:-1] else: parent_name_expr = parser.compile_filter(bits[1]) nodelist = parser.parse() if nodelist.get_nodes_by_type(OverrideNode): raise TemplateSyntaxError("'%s' cannot appear more than once in the same template" % bits[0]) return OverrideNode(nodelist, parent_name, parent_name_expr) register.tag('override', do_override)
def get_context(self, context): """ Tests and updates the existing context. :param context: a :class:`~django.template.Context` which is checked via :meth:`~adminlinks.templatetags.utils.context_passes_test`, and the result **always** put into the context. :return: the context, possibly modified with a new layer. :rtype: :class:`~django.template.RequestContext` or other context/ dictionary-like object. """ result = context_passes_test(context) context.update({'should_load_assets': result}) return context register.tag(name='render_adminlinks_css', compile_function=AdminlinksCssShortcut) class AdminlinksJsShortcut(InclusionTag): """ Helper for rendering any JavaScript we want to ship by default, inline or as external scripts:: {% render_adminlinks_js %} """ #: How to call this tag from a template. name = 'render_adminlinks_js' #: The template to use to render the JavaScripts. May be overridden by #: project-level templates.
Force autoescape behaviour for this block. """ args = token.contents.split() if len(args) != 2: raise TemplateSyntaxError( "'autoescape' tag requires exactly one argument.") arg = args[1] if arg not in (u'on', u'off'): raise TemplateSyntaxError( "'autoescape' argument should be 'on' or 'off'") nodelist = parser.parse(('endautoescape', )) parser.delete_first_token() return AutoEscapeControlNode((arg == 'on'), nodelist) autoescape = register.tag(autoescape) #@register.tag def comment(parser, token): """ Ignores everything between ``{% comment %}`` and ``{% endcomment %}``. """ parser.skip_past('endcomment') return CommentNode() comment = register.tag(comment) #@register.tag
otherwise :meth:`~adminlinks.templatetags.adminlinks_buttons.BaseAdminLink.is_valid` is unlikely to be :data:`True` :param obj: the :class:`~django.db.models.Model` instance to link to. Must have a primary key, and :class:`~django.db.models.Options` from which we can retrieve a :attr:`~django.db.models.Field.verbose_name` :param admin_site: name of the admin site to use; defaults to **"admin"** :param querystring: a querystring to include in the link output. Defaults to "_popup=1" :return: the link values. :rtype: dictionary. """ return _add_link_to_context(admin_site, context['request'], obj._meta, 'change', [obj.pk], query=querystring) register.tag(name='render_edit_button', compile_function=Edit) class EditField(BaseAdminLink, InclusionTag): """ An :class:`~classytags.helpers.InclusionTag` to render a link to a customised admin change form for an object, showing only the requested field:: {% render_edit_field_button my_obj "field_name" %} {% render_edit_field_button my_obj "field_name" "my_custom_admin" %} {% render_edit_field_button my_obj "field_name" "my_custom_admin" "a=1&b=2&a=3" %} .. note:: Use of this class requires that the :class:`~django.contrib.admin.ModelAdmin` includes :class:`~adminlinks.admin.AdminlinksMixin` or otherwise creates a
options = {} remaining_bits = bits[2:] while remaining_bits: option = remaining_bits.pop(0) if option in options: raise TemplateSyntaxError('The %r option was specified more ' 'than once.' % option) if option == 'with': value = token_kwargs(remaining_bits, parser, support_legacy=False) if not value: raise TemplateSyntaxError('"with" in %r tag needs at least ' 'one keyword argument.' % bits[0]) elif option == 'only': value = True else: raise TemplateSyntaxError('Unknown argument for %r tag: %r.' % (bits[0], option)) options[option] = value isolated_context = options.get('only', False) namemap = options.get('with', {}) path = bits[1] if path[0] in ('"', "'") and path[-1] == path[0]: return ConstantIncludeNode(path[1:-1], extra_context=namemap, isolated_context=isolated_context) return IncludeNode(parser.compile_filter(bits[1]), extra_context=namemap, isolated_context=isolated_context) register.tag('block', do_block) register.tag('extends', do_extends) register.tag('include', do_include)
class AdminlinksToolbar(InclusionTag): template = 'adminlinks/toolbar.html' options = Options( Flag('with_labels', true_values=['1', 'true', 'yes', 'on'], false_values=['0', 'false', 'no', 'off'], case_sensitive=False, default=True), StringArgument('admin_site', required=False, default='admin'), ) def get_context(self, context, with_labels, admin_site): """ Updates the *existing* context by putting a list of applicable modeladmins into `app_list` assuming the argument `admin_site` resolved into an AdminSite instance. Always returns the existing context. """ site = get_admin_site(admin_site) if context_passes_test(context) and site is not None: modeladmins = get_registered_modeladmins(context['request'], site) context.update({ 'should_display_toolbar': True, 'should_display_apps': with_labels, 'app_list': _resort_modeladmins(modeladmins), }) return context register.tag(name='render_adminlinks_toolbar', compile_function=AdminlinksToolbar)
if bits[in_index] != 'in': raise TemplateSyntaxError("'for' statements should use the format" " 'for x in y': %s" % token.contents) loopvars_list.append([l.strip() for l in ' '.join(bits[:in_index]).split(',')]) for loopvars in loopvars_list: for var in loopvars: if not var or ' ' in var: raise TemplateSyntaxError("'for' tag received an " "invalid argument: %s" % token.contents) sequence_list.append(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_list, sequence_list, is_reversed_list, nodelist_loop, nodelist_empty) do_for = register.tag("for", do_for) def do_for_longest(*args, **kwargs): return do_for(ForNode=ForLongestNode, *args, **kwargs) do_for_longest = register.tag("for_longest", do_for_longest)
from django.template.base import Node, NodeList, Template, Context, Variable from django.template.base import get_library, Library, InvalidTemplateLibrary from django.template.smartif import IfParser, Literal from django.conf import settings from django.utils.encoding import smart_str, smart_unicode from django.utils.safestring import mark_safe from django.template.defaulttags import url as django_url from django.utils import translation register = Library() class UrlLangNode(Node): def __init__(self, urlnode, lang): self.urlnode = urlnode self.lang = lang def render(self, context): url = self.urlnode.render(context) return '/%s%s' %( self.lang, url ) def url_lang(parser, token): url = django_url(parser, token) lang = translation.get_language()[:2] if lang != settings.LANGUAGE_CODE[:2]: urlnode = UrlLangNode(url, lang) return urlnode return url register.tag(url_lang)
#@register.tag def autoescape(parser, token): """ Force autoescape behaviour for this block. """ args = token.contents.split() if len(args) != 2: raise TemplateSyntaxError("'autoescape' tag requires exactly one argument.") arg = args[1] if arg not in (u'on', u'off'): raise TemplateSyntaxError("'autoescape' argument should be 'on' or 'off'") nodelist = parser.parse(('endautoescape',)) parser.delete_first_token() return AutoEscapeControlNode((arg == 'on'), nodelist) autoescape = register.tag(autoescape) #@register.tag def comment(parser, token): """ Ignores everything between ``{% comment %}`` and ``{% endcomment %}``. """ parser.skip_past('endcomment') return CommentNode() comment = register.tag(comment) #@register.tag def cycle(parser, token): """ Cycles among the given strings each time this tag is encountered.
The legacy format of ``{% with person.some_sql_method as total %}`` is still accepted. """ bits = token.split_contents() remaining_bits = bits[1:] extra_context = token_kwargs(remaining_bits, parser, support_legacy=True) if not extra_context: raise TemplateSyntaxError("%r expected at least one variable " "assignment" % bits[0]) if remaining_bits: raise TemplateSyntaxError("%r received an invalid token: %r" % (bits[0], remaining_bits[0])) nodelist = parser.parse(('endwith',)) parser.delete_first_token() return WithNode(None, None, nodelist, extra_context=extra_context) do_with = register.tag('with', do_with) class RangeNode(Node): def __init__(self, num, context_name): self.num, self.context_name = Variable(num), context_name def render(self, context): context[self.context_name] = range(int(self.num.resolve(context))) return "" @register.tag def num_range(parser, token): """ Takes a number and iterates and returns a range (list) that can be iterated through in templates Syntax:
from django.template.base import Library, TextNode register = Library() def do_tag3(parser, token): return TextNode('<app 1 lib 3 tag 3>') register.tag('tag3', do_tag3)
from django.template.base import Library, TextNode register = Library() def do_tag1(parser, token): return TextNode('<app 2 lib 2 tag 1>') def do_tag2(parser, token): return TextNode('<app 2 lib 2 tag 2>') register.tag('tag1', do_tag1) register.tag('tag2', do_tag2)
def __init__(self, form, field_string, dynamic_string): self.form = template.Variable(form) self.field_string = field_string self.dynamic_string = template.Variable(dynamic_string) def render(self, context): try: form = self.form.resolve(context) dynamic_string = self.dynamic_string.resolve(context) key = '%s%d' % (self.field_string, dynamic_string+1) return form[key] except template.VariableDoesNotExist: return '' def get_dynamic_value(parser, token): """ This is the name of the template tag to be called for a dynamic variable. """ try: # split_contents() knows not to split quoted strings. tag_name, form, field_string, dynamic_string = token.split_contents() except ValueError: tag_name = token.contents.split()[0] raise template.TemplateSyntaxError( "%r tag requires exactly three arguments" % tag_name) return DynamicVariableNode(form, field_string, dynamic_string) register.tag(get_dynamic_value)
if option == 'with': value = token_kwargs(remaining_bits, parser, support_legacy=False) if not value: raise TemplateSyntaxError('"with" in %r tag needs at least ' 'one keyword argument.' % bits[0]) elif option == 'only': value = True else: raise TemplateSyntaxError('Unknown argument for %r tag: %r.' % (bits[0], option)) options[option] = value isolated_context = options.get('only', False) namemap = options.get('with', {}) #path = bits[1] pathlist_s = [] for path in pathlist: if path[0] in ('"', "'") and path[-1] == path[0]: pathlist_s.append({'value': path[1:-1], 'type': 'string'}) else: pathlist_s.append({'value': parser.compile_filter(path), 'type': 'var'}) return IncludeNode_v2(pathlist = pathlist_s, extra_context=namemap, isolated_context=isolated_context) # return ConstantIncludeNode(path[1:-1], extra_context=namemap, # isolated_context=isolated_context) #return IncludeNode(parser.compile_filter(bits[1]), extra_context=namemap, # isolated_context=isolated_context) register.tag('extends_v2', do_extends) register.tag('include_v2', do_include)
# чтобы можно было менять год в одном месте (в БД таблица = site_year), # а не на всех страницах сайта по отдельности. from django.db import connection from django.template.base import Library, Node register = Library() class SiteYearNode(Node): def render(self, context): last_year = connection.cursor() last_year.execute(""" SELECT sy.year FROM site_year sy WHERE sy.id = ( SELECT MAX(sy.id) FROM site_year sy ) ; """) # Запрос вернет год с максимальным айдишником, # а так как текущий год добавляется в таблицу ручками, # то и айдишник у этого года будет максимальный, # т.к. id это автоинкрементное поле year_result = last_year.fetchone() return year_result[0] def siteyear_tag(parser, token): return SiteYearNode() siteyear_tag = register.tag(siteyear_tag)