def __init__(self, object_expr=None, name=None): if object_expr is None and name is None: raise template.TemplateSyntaxError("Like nodes must be given either a literal object.") self.object_expr = object_expr self.name = template.Variable(name)
def _strip_quotes(arg): if not (arg[0] == arg[-1] and arg[0] in ('"', "'")): raise template.TemplateSyntaxError("Argument %s should be in quotes" % arg) return arg[1:-1]
def get_pages(parser, token): """Add to context the list of page links. Usage: .. code-block:: html+django {% get_pages %} This is mostly used for Digg-style pagination. This call inserts in the template context a *pages* variable, as a sequence of page links. You can use *pages* in different ways: - just print *pages.get_rendered* and you will get Digg-style pagination displayed: .. code-block:: html+django {{ pages.get_rendered }} - display pages count: .. code-block:: html+django {{ pages|length }} - check if the page list contains more than one page: .. code-block:: html+django {{ pages.paginated }} {# the following is equivalent #} {{ pages|length > 1 }} - get a specific page: .. code-block:: html+django {# the current selected page #} {{ pages.current }} {# the first page #} {{ pages.first }} {# the last page #} {{ pages.last }} {# the previous page (or nothing if you are on first page) #} {{ pages.previous }} {# the next page (or nothing if you are in last page) #} {{ pages.next }} {# the third page #} {{ pages.3 }} {# this means page.1 is the same as page.first #} {# the 1-based index of the first item on the current page #} {{ pages.current_start_index }} {# the 1-based index of the last item on the current page #} {{ pages.current_end_index }} {# the total number of objects, across all pages #} {{ pages.total_count }} {# the first page represented as an arrow #} {{ pages.first_as_arrow }} {# the last page represented as an arrow #} {{ pages.last_as_arrow }} - iterate over *pages* to get all pages: .. code-block:: html+django {% for page in pages %} {# display page link #} {{ page.render_link}} {# the page url (beginning with "?") #} {{ page.url }} {# the page path #} {{ page.path }} {# the page number #} {{ page.number }} {# a string representing the page (commonly the page number) #} {{ page.label }} {# check if the page is the current one #} {{ page.is_current }} {# check if the page is the first one #} {{ page.is_first }} {# check if the page is the last one #} {{ page.is_last }} {% endfor %} You can change the variable name, e.g.: .. code-block:: html+django {% get_pages as page_links %} Must be called after ``{% paginate objects %}``. """ # Validate args. try: tag_name, args = token.contents.split(None, 1) except ValueError: var_name = 'pages' else: args = args.split() if len(args) == 2 and args[0] == 'as': var_name = args[1] else: msg = 'Invalid arguments for %r tag' % tag_name raise template.TemplateSyntaxError(msg) # Call the node. return GetPagesNode(var_name)
def auto_display(parser, token): """ This tag returns an HTML element. Arguments:: relation -- One object from the 'relations' template context object. prefix -- A keyword argument who's value is used as a prefix to the element id and name attributes. option -- A keyword argument who's value is in the 'dynamicColumns' context. The entire 'dynamicColumns' context can be supplied or just the object for this relation. display -- A keyword argument. If 'True' use <span> for all tags else 'False' use the default tag types. Assume data structures below for examples:: {'dynamicColumns': { 'book': [ [0, 'Choose a value'], [2, 'HTML5 Pocket Reference'], [1, 'SQL Pocket Guide'], [3, 'Raspberry Pi Hacks'] ] } } {'relations': { '1': { 'name': 'Project ID', 'required': false, 'relation': null, 'location': 'top-container', 'value_type': 0, 'order': 3, 'value': '12345' }, } Usage Examples:: {% auto_display relation %} {% auto_display relation prefix=test- %} {% auto_display relation options=books %} {% auto_display relation options=books display=True %} {% auto_display relation prefix=test- options=dynamicColumns %} """ tokens = token.split_contents() size = len(tokens) kwargs = {'prefix': '', 'options': None, 'display': 'False'} keywords = list(six.viewkeys(kwargs)) keywords.sort() if size == 2: tag_name, relation = tokens kwargs = {} elif size == 3: tag_name, relation, value1 = tokens kwargs.update( {k: v for k, d, v in [v.partition('=') for v in (value1, )]}) elif size == 4: tag_name, relation, value1, value2 = tokens kwargs.update( {k: v for k, d, v in [v.partition('=') for v in (value1, value2)]}) elif size == 5: tag_name, relation, value1, value2, value3 = tokens kwargs.update({ k: v for k, d, v in [v.partition('=') for v in (value1, value2, value3)] }) else: msg = ("Invalid number of arguments should be 1 - 4, " "found: {}").format(size - 1) raise template.TemplateSyntaxError(msg) if size > 2 and not all([key in keywords for key in kwargs]): msg = "Invalid keyword name, should be one of {}".format(keywords) raise template.TemplateSyntaxError(msg) return AutoDisplayNode(tag_name, relation, **kwargs)
contents = token.contents.split() token_name, token_args = contents[0], contents[1:] if token_name == 'case': tests = map(parser.compile_filter, token_args) case = (tests, nodelist) got_case = True else: # The {% else %} tag case = (None, nodelist) got_else = True cases.append(case) token = parser.next_token() if not got_case: raise template.TemplateSyntaxError("'%s' must have at least one 'case'." % tag_name) return SwitchNode(variable, cases) class SwitchNode(Node): def __init__(self, variable, cases): self.variable = variable self.cases = cases def __repr__(self): return "<Switch node>" def __iter__(self): for tests, nodelist in self.cases: for node in nodelist: yield node
def assign_vars(p_name, p_var): try: var[p_name] = p_var except KeyError: raise template.TemplateSyntaxError(error_msg)
def __init__(self, varname=None, path=None): if path is None: raise template.TemplateSyntaxError( "Static template nodes must be given a path to return.") self.path = path self.varname = varname
def do_permission(parser, token): """ permission tags for templates. At first, you must load custome tags from templatetags by {% load permission %}, and then use like following examples. A single block tags for check permission and display the context between them. :: {% permission 'right name' %} something want to be hidden if user does not have right {% endpermission %} A block tags with 'otherwise' that just like 'if-else' to choose which context to be displayed :: {% permission variable_from_request_context %} something want to be hidden if user does not have right {% otherwise %} show some warning tips or just leave it empty. {% endpermission %} """ context = token.split_contents() if len(context) < 2: raise template.TemplateSyntaxError( "%r tag requires one right name at least" % token.contents.split()[0]) rights = context[1:] nodelist = [parser.parse(('otherwise', 'endpermission'))] token = parser.next_token() # {% otherwise %} if token.contents == 'otherwise': nodelist.append(parser.parse(('endpermission', ))) token = parser.next_token() # {% endpermission %} assert token.contents == 'endpermission' opt = 'and' if len(rights) == 1: filter_rights = rights else: l = len(rights) i = 0 filter_rights = list() while i < l: token = rights[i] if token in ('or', 'and'): opt = token else: filter_rights.append(token) i += 1 return PermissionNode(filter_rights, nodelist, opt)
def render(self, context): explanation = _resolve_variable(self.explanation, context) label, identifier = self.resolve_label_and_identifier(context) user = _resolve_variable(self.user, context) instance = _resolve_variable(self.instance, context) field_template = get_template(_resolve_variable( self.field_template, context)).template if not isinstance(identifier, basestring)\ or not _identifier_regex.match(identifier): raise template.TemplateSyntaxError( 'expected a string with the format "object_name.property" ' 'to follow "from" %s' % identifier) model_name_or_object_name, field_name = dotted_split(identifier, 2, maxsplit=1) model = self.get_model(context, model_name_or_object_name, instance) object_name = to_object_name(model_name_or_object_name) identifier = "%s.%s" % (object_name, field_name) def _field_value(model, field_name, data_type): udf_field_name = field_name.replace('udf:', '') val = None if field_name in [f.name for f in model._meta.get_fields()]: try: val = getattr(model, field_name) except (ObjectDoesNotExist, AttributeError): pass elif _is_udf(model, udf_field_name): if udf_field_name in model.udfs: val = model.udfs[udf_field_name] # multichoices place a json serialized data-value # on the dom element and client-side javascript # processes it into a view table and edit widget if data_type == 'multichoice': val = json.dumps(val) elif data_type == 'multichoice': val = '[]' else: raise ValueError('Could not find field: %s' % field_name) return val if is_json_field_reference(field_name): field_value = get_attr_from_json_field(model, field_name) choices = None is_visible = is_editable = True data_type = "string" else: add_blank = (ADD_BLANK_ALWAYS if self.treat_multichoice_as_choice else ADD_BLANK_IF_CHOICE_FIELD) data_type, label, explanation, choices = field_type_label_choices( model, field_name, label, explanation=explanation, add_blank=add_blank) field_value = _field_value(model, field_name, data_type) if user is not None and hasattr(model, 'field_is_visible'): is_visible = model.field_is_visible(user, field_name) is_editable = model.field_is_editable(user, field_name) else: # This tag can be used without specifying a user. In that case # we assume that the content is visible and upstream code is # responsible for only showing the content to the appropriate # user is_visible = True is_editable = True digits = units = '' if hasattr(model, 'instance'): digits = get_digits_if_formattable( model.instance, object_name, field_name) units = get_units_if_convertible( model.instance, object_name, field_name) if units != '': units = get_unit_abbreviation(units) if data_type == 'foreign_key': # rendered clientside display_val = '' elif field_value is None: display_val = None elif data_type in ['date', 'datetime']: fmt = (model.instance.short_date_format if model.instance else settings.SHORT_DATE_FORMAT) display_val = dateformat.format(field_value, fmt) elif is_convertible_or_formattable(object_name, field_name): display_val = format_value( model.instance, object_name, field_name, field_value) if units != '': display_val += (' %s' % units) elif data_type == 'bool': display_val = _('Yes') if field_value else _('No') elif data_type == 'multichoice': # this is rendered clientside from data attributes so # there's no meaningful intermediate value to send # without rendering the same markup server-side. display_val = None elif choices: display_vals = [choice['display_value'] for choice in choices if choice['value'] == field_value] display_val = display_vals[0] if display_vals else field_value else: display_val = unicode(field_value) context['field'] = { 'label': label, 'explanation': explanation, 'identifier': identifier, 'value': field_value, 'display_value': display_val, 'units': units, 'digits': digits, 'data_type': data_type, 'is_visible': is_visible, 'is_editable': is_editable, 'choices': choices, } self.get_additional_context( context['field'], model, field_name, context.get('q', '')) return field_template.render(context)
def do_get_articles_most_commented(parser, token): bits = token.split_contents() if len(bits) != 3: raise template.TemplateSyntaxError( "'get_articles_most_commented' tag takes exactly 3 arguments") return MostCommentedNode(bits[2])
def do_filter_url(parser, token): """ Outputs a URL based on the filter chain, with optional additions/removals of filters. The first argument is required and can be either an existing FilterChain or a Schema. {% filter_url filter_chain %} {% filter_url schema %} To remove a NewsitemFilter from the url, specify the key with a leading "-". {% filter_url filter_chain -key_to_remove %} {% filter_url filter_chain -"key_to_remove" %} {% filter_url filter_chain -key1 -key2 ... %} To add NewsitemFilters to the url, specify the key with a leading "+", followed by args to use for constructing a NewsitemFilter. {% filter_url filter_chain +"key" value %} {% filter_url filter_chain +key value1 value 2 ... %} {% filter_url filter_chain +key1 "arg1a" "arg1b" +key2 "arg2a" ... %} You can even mix and match additions and removals: {% filter_url filter_chain -key1 +key2 arg2 -key3 +key4 arg4 ... %} """ bits = token.split_contents() additions, removals = [], [] try: filterchain_var = bits[1] except IndexError: raise template.TemplateSyntaxError( 'Missing required filterchain argument') # TODO: This probably fails for removals of hard-coded strings that contain spaces. bits = bits[2:] clear = False while bits: bit = bits.pop(0) if bit.startswith('-'): key = bit[1:] if not len(key): raise template.TemplateSyntaxError('Invalid argument: %r' % bit) if key == 'all': removals = [] clear = True else: removals.append(key) elif bit.startswith('+'): key = bit[1:] if not len(key): raise template.TemplateSyntaxError('Invalid argument: %r' % bit) values = [] while bits: # Consume all remaining args until the next addition/removal. if bits[0][0] in ('+', '-'): break values.append(bits.pop(0)) # if not len(values): # raise template.TemplateSyntaxError('Invalid argument: %r' % bit) additions.append((key, values)) else: raise template.TemplateSyntaxError('Invalid argument: %r' % bit) return FilterUrlNode(filterchain_var, additions, removals, clear=clear)
def do_get_articles_latest(parser, token): bits = token.split_contents() if len(bits) != 4: raise template.TemplateSyntaxError( "'get_last_articles' tag takes exactly 4 arguments") return ArticlesLatestNode(bits[2], bits[3])
def do_get_first_paragraph(parser, token): bits = token.split_contents() if len(bits) != 4: raise template.TemplateSyntaxError( "'get_first_paragraph' tag takes exactly 4 arguments") return FirstParagraphNode(bits[2], bits[3])
def primary_group_avatar_object(parser, token): split = token.split_contents() if len(split) == 4: return GroupAvatarObjectNode(split[1], split[3]) else: raise template.TemplateSyntaxError('%r tag takes three arguments.' % split[0])
def handle_token(cls, parser, token): bits = token.split_contents() if len(bits) == 3 and bits[1] == "as": return cls(bits[2]) else: raise template.TemplateSyntaxError("%r takes 'as var'" % bits[0])
def dateAdvance(parse, token): try: tag_name, fromat_string = token.split_contents() except ValueError: raise template.TemplateSyntaxError('invalid args') return DateNode(fromat_string[1:-1])
def do_recover_tweets(parser, token): try: tag_name = token.split_contents() except ValueError: raise template.TemplateSyntaxError('%r tag requires zero arguments' % token.contents.split()[0]) return RecoverTweetsNode()
def error(): raise template.TemplateSyntaxError( fnctl + "accepts the syntax: {%%" + fnctl + " [start,] stop[, step] as context_name %%}," + " where 'start', 'stop' and 'step' must all be integers.")
def __init__(self, varname=None, name=None): if name is None: raise template.TemplateSyntaxError( "Prefix nodes must be given a name to return.") self.varname = varname self.name = name
def facebook_configured(parser, token): bits = token.split_contents() if len(bits) != 3: raise template.TemplateSyntaxError('%s takes one arg' % bits[0]) return FacebookConfiguredNode(bits[2])
def cropped_thumbnail(context, instance, ratiofieldname, **kwargs): ''' Syntax: {% cropped_thumbnail instancename "ratiofieldname" [scale=0.1|width=100|height=200|max_size="100x200"] [upscale=True] %} ''' ratiofield = instance._meta.get_field(ratiofieldname) image = getattr(instance, ratiofield.image_field) # get imagefield if ratiofield.image_fk_field: # image is ForeignKey # get the imagefield image = getattr(image, ratiofield.image_fk_field) if not image: return box = getattr(instance, ratiofieldname) if ratiofield.free_crop: if not box: size = (image.width, image.height) else: box_values = list(map(int, box.split(','))) size = (box_values[2] - box_values[0], box_values[3] - box_values[1]) else: size = (int(ratiofield.width), int(ratiofield.height)) if sum(k in kwargs for k in VALID_OPTIONS) > 1: raise template.TemplateSyntaxError( 'Only one size modifier is allowed.') if 'scale' in kwargs: width = size[0] * kwargs['scale'] height = size[1] * kwargs['scale'] elif 'width' in kwargs: width = kwargs['width'] height = size[1] * width / size[0] elif 'height' in kwargs: height = kwargs['height'] width = height * size[0] / size[1] elif 'max_size' in kwargs: try: max_width, max_height = list( map(int, kwargs['max_size'].split('x'))) except (ValueError, AttributeError): raise template.TemplateSyntaxError("max_size must match INTxINT") width, height = size # recalculate height if needed if max_width < width: height = height * max_width / width width = max_width # recalculate width if needed if max_height < height: width = max_height * width / height height = max_height if any(k in kwargs for k in VALID_OPTIONS): # adjust size based on given modifier size = (int(width), int(height)) if ratiofield.adapt_rotation: if (image.height > image.width) != (size[1] > size[0]): # box needs rotation size = (size[1], size[0]) thumbnailer = get_thumbnailer(image) thumbnail_options = { 'size': size, 'box': box, 'crop': True, 'detail': kwargs.pop('detail', True), 'upscale': kwargs.pop('upscale', False) } # remove all cropping kwargs for k in VALID_OPTIONS: kwargs.pop(k, None) # pass remaining arguments to easy_thumbnail thumbnail_options.update(kwargs) return thumbnailer.get_thumbnail(thumbnail_options).url
def set_comment_remove_variable(parser, token): args = token.split_contents() if not len(args) in [4, 6]: raise template.TemplateSyntaxError("Not the right amount of args") return RemoveCommentNode(args[2], args[3], args[5])
def google_static_map(parser, token): try: tag_name, event, width, height, zoom = token.split_contents() except ValueError: raise template.TemplateSyntaxError('google_static_map requires an event, width, height and zoom level') return GoogleStaticMapNode(event, width, height, zoom)
def stripe_payment(parser, token): try: tag, int_obj = token.split_contents() except ValueError: raise template.TemplateSyntaxError("%r was expecting a single argument" %token.split_contents()[0]) return StripeNode(int_obj)
def do_switch(parser, token): """ The ``{% switch %}`` tag compares a variable against one or more values in ``{% case %}`` tags, and outputs the contents of the matching block. An optional ``{% else %}`` tag sets off the default output if no matches could be found:: {% switch result_count %} {% case 0 %} There are no search results. {% case 1 %} There is one search result. {% else %} Jackpot! Your search found {{ result_count }} results. {% endswitch %} Each ``{% case %}`` tag can take multiple values to compare the variable against:: {% switch username %} {% case "Jim" "Bob" "Joe" %} Me old mate {{ username }}! How ya doin? {% else %} Hello {{ username }} {% endswitch %} """ bits = token.contents.split() tag_name = bits[0] if len(bits) != 2: raise template.TemplateSyntaxError("'%s' tag requires one argument" % tag_name) variable = parser.compile_filter(bits[1]) class BlockTagList(object): # This is a bit of a hack, as it embeds knowledge of the behaviour # of Parser.parse() relating to the "parse_until" argument. def __init__(self, *names): self.names = set(names) def __contains__(self, token_contents): name = token_contents.split()[0] return name in self.names # Skip over everything before the first {% case %} tag parser.parse(BlockTagList('case', 'endswitch')) cases = [] token = parser.next_token() got_case = False got_else = False while token.contents != 'endswitch': nodelist = parser.parse(BlockTagList('case', 'else', 'endswitch')) if got_else: raise template.TemplateSyntaxError("'else' must be last tag in '%s'." % tag_name) contents = token.contents.split() token_name, token_args = contents[0], contents[1:] if token_name == 'case': tests = map(parser.compile_filter, token_args) case = (tests, nodelist) got_case = True else: # The {% else %} tag case = (None, nodelist) got_else = True cases.append(case) token = parser.next_token()
def compiler(parser, token): args, kwargs, alias = parse_token(parser, token) if not alias: raise template.TemplateSyntaxError("Alias not provided for assignment_tag") return CompatibilityNode(takes_context, func, args, kwargs, alias)
def show_current_number(parser, token): """Show the current page number, or insert it in the context. This tag can for example be useful to change the page title according to the current page number. To just show current page number: .. code-block:: html+django {% show_current_number %} If you use multiple paginations in the same page, you can get the page number for a specific pagination using the querystring key, e.g.: .. code-block:: html+django {% show_current_number using mykey %} The default page when no querystring is specified is 1. If you changed it in the `paginate`_ template tag, you have to call ``show_current_number`` according to your choice, e.g.: .. code-block:: html+django {% show_current_number starting from page 3 %} This can be also achieved using a template variable you passed to the context, e.g.: .. code-block:: html+django {% show_current_number starting from page page_number %} You can of course mix it all (the order of arguments is important): .. code-block:: html+django {% show_current_number starting from page 3 using mykey %} If you want to insert the current page number in the context, without actually displaying it in the template, use the *as* argument, i.e.: .. code-block:: html+django {% show_current_number as page_number %} {% show_current_number starting from page 3 using mykey as page_number %} """ # Validate args. try: tag_name, args = token.contents.split(None, 1) except ValueError: key = None number = None tag_name = token.contents[0] var_name = None else: # Use a regexp to catch args. match = SHOW_CURRENT_NUMBER_EXPRESSION.match(args) if match is None: msg = 'Invalid arguments for %r tag' % tag_name raise template.TemplateSyntaxError(msg) # Retrieve objects. groupdict = match.groupdict() key = groupdict['key'] number = groupdict['number'] var_name = groupdict['var_name'] # Call the node. return ShowCurrentNumberNode(number, key, var_name)
def compiler(parser, token): args, kwargs, alias = parse_token(parser, token) if alias: raise template.TemplateSyntaxError("Alias not allowed for simple_tag") return CompatibilityNode(takes_context, func, args, kwargs, alias)
def paginate(parser, token, paginator_class=None): """Paginate objects. Usage: .. code-block:: html+django {% paginate entries %} After this call, the *entries* variable in the template context is replaced by only the entries of the current page. You can also keep your *entries* original variable (usually a queryset) and add to the context another name that refers to entries of the current page, e.g.: .. code-block:: html+django {% paginate entries as page_entries %} The *as* argument is also useful when a nested context variable is provided as queryset. In this case, and only in this case, the resulting variable name is mandatory, e.g.: .. code-block:: html+django {% paginate entries.all as entries %} The number of paginated entries is taken from settings, but you can override the default locally, e.g.: .. code-block:: html+django {% paginate 20 entries %} Of course you can mix it all: .. code-block:: html+django {% paginate 20 entries as paginated_entries %} By default, the first page is displayed the first time you load the page, but you can change this, e.g.: .. code-block:: html+django {% paginate entries starting from page 3 %} When changing the default page, it is also possible to reference the last page (or the second last page, and so on) by using negative indexes, e.g: .. code-block:: html+django {% paginate entries starting from page -1 %} This can be also achieved using a template variable that was passed to the context, e.g.: .. code-block:: html+django {% paginate entries starting from page page_number %} If the passed page number does not exist, the first page is displayed. If you have multiple paginations in the same page, you can change the querydict key for the single pagination, e.g.: .. code-block:: html+django {% paginate entries using article_page %} In this case *article_page* is intended to be a context variable, but you can hardcode the key using quotes, e.g.: .. code-block:: html+django {% paginate entries using 'articles_at_page' %} Again, you can mix it all (the order of arguments is important): .. code-block:: html+django {% paginate 20 entries starting from page 3 using page_key as paginated_entries %} Additionally you can pass a path to be used for the pagination: .. code-block:: html+django {% paginate 20 entries using page_key with pagination_url as paginated_entries %} This way you can easily create views acting as API endpoints, and point your Ajax calls to that API. In this case *pagination_url* is considered a context variable, but it is also possible to hardcode the URL, e.g.: .. code-block:: html+django {% paginate 20 entries with "/mypage/" %} If you want the first page to contain a different number of items than subsequent pages, you can separate the two values with a comma, e.g. if you want 3 items on the first page and 10 on other pages: .. code-block:: html+django {% paginate 3,10 entries %} You must use this tag before calling the {% show_more %} one. """ # Validate arguments. try: tag_name, tag_args = token.contents.split(None, 1) except ValueError: msg = '%r tag requires arguments' % token.contents.split()[0] raise template.TemplateSyntaxError(msg) # Use a regexp to catch args. match = PAGINATE_EXPRESSION.match(tag_args) if match is None: msg = 'Invalid arguments for %r tag' % tag_name raise template.TemplateSyntaxError(msg) # Retrieve objects. kwargs = match.groupdict() objects = kwargs.pop('objects') # The variable name must be present if a nested context variable is passed. if '.' in objects and kwargs['var_name'] is None: msg = ( '%(tag)r tag requires a variable name `as` argumnent if the ' 'queryset is provided as a nested context variable (%(objects)s). ' 'You must either pass a direct queryset (e.g. taking advantage ' 'of the `with` template tag) or provide a new variable name to ' 'store the resulting queryset (e.g. `%(tag)s %(objects)s as ' 'objects`).') % { 'tag': tag_name, 'objects': objects } raise template.TemplateSyntaxError(msg) # Call the node. return PaginateNode(paginator_class, objects, **kwargs)
def filmod(value, arg): try: return int(value) % int(arg) except ValueError: raise template.TemplateSyntaxError('mod requires integer arguments')