Skip to content

Instantly share code, notes, and snippets.

@bmihelac
Created September 17, 2014 13:15
Show Gist options
  • Save bmihelac/e02178389e743a69516d to your computer and use it in GitHub Desktop.
Save bmihelac/e02178389e743a69516d to your computer and use it in GitHub Desktop.
Inclusion template tag with block.
<div class="panel {{ class_name }}">
<div class="panel-heading">
<h3 class="panel-title">{{ title }}</h3>
</div>
<div class="panel-body">
{{ content }}
</div>
</div>
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from functools import partial
from inspect import getargspec
from django.template.loader import get_template
from django.template import Context
from django.template.base import (
TagHelperNode,
TemplateSyntaxError,
parse_bits,
)
def tag_compiler(parser, token, params, varargs, varkw, defaults,
name, takes_context, node_class):
"""
Returns a TemplateNode subclass.
"""
bits = token.split_contents()[1:]
args, kwargs = parse_bits(parser, bits, params, varargs, varkw,
defaults, takes_context, name)
nodelist = parser.parse(('end%s' % name,))
parser.delete_first_token()
return node_class(nodelist, takes_context, args, kwargs)
def inclusion_block_tag(register, file_name, func=None, context_class=Context,
takes_context=None, name=None):
"""
Block tag saves content parsed from TAGNAME to TAGNAMEend into ``content``
context variable and renders given template.
If function returns None, given kwargs will be used as context.
Usage::
register = template.Library()
@inclusion_block_tag(register, file_name='html_components/panel.html')
def panel(title, class_name):
return None
#template.html
{% panel title="My title" class_name="panel-danger" %}
<p>
{% trans "Yes" %}
</p>
{% endpanel %}
#html_components/panel.html
<div class="panel {{ class_name }}">
<div class="panel-heading">
<h3 class="panel-title">{{ title }}</h3>
</div>
<div class="panel-body">
{{ content }}
</div>
</div>
"""
def dec(func):
params, varargs, varkw, defaults = getargspec(func)
class TemplateNode(TagHelperNode):
def __init__(self, nodelist, takes_context, args, kwargs):
self.nodelist = nodelist
super(TemplateNode, self).__init__(takes_context, args, kwargs)
def render(self, context):
resolved_args, resolved_kwargs = self.get_resolved_arguments(
context
)
_dict = func(*resolved_args, **resolved_kwargs)
if _dict is None:
_dict = resolved_kwargs
ctx = context_class(_dict)
ctx['content'] = self.nodelist.render(context)
t = get_template(file_name)
return t.render(ctx)
function_name = (name or
getattr(func, '_decorated_function', func).__name__)
compile_func = partial(
tag_compiler,
params=params, varargs=varargs, varkw=varkw,
defaults=defaults, name=function_name,
takes_context=takes_context, node_class=TemplateNode)
compile_func.__doc__ = func.__doc__
register.tag(function_name, compile_func)
return func
if func is None:
# @register.simple_tag(...)
return dec
elif callable(func):
# @register.simple_tag
return dec(func)
else:
raise TemplateSyntaxError(
"Invalid arguments provided to inclusion_block_tag")
{%load mytags%}
{% panel title="title" class_name="panel-danger" %}
<p>
{% trans "Yes" %}
</p>
{% endpanel %}
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from inclusion_block_tag import inclusion_block_tag
from django import template
register = template.Library()
@inclusion_block_tag(register, file_name='html_components/panel.html')
def panel(title, class_name):
return None
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment