Django templates {% include %} fallback value - django

I'm trying to dynamically load a template like so:
{% include 'some-folder/'|add:var|add:'.html' %}
But these templates are not always present. So I would like to add a fallback value/default template to be loaded if one being requested is not found.
Is this possible? If not (out-of-the-box), how can I write a custom templatetag that does so?

from django import template
register = template.Library()
#register.simple_tag
def get_template_path(var1, var2):
template_path = 'some-folder/' + var1 + '/' + var2 + '.html'
default_template = 'some-folder/default_template.html'
try:
template.loader.get_template(template_path)
return template_path
except TemplateDoesNotExist:
return default_template
In template call this template tag like this:
{% load get_template_path %}
{% get_template_path var1='qq' var2='ee' as temlate_path %}
{% include template_path %}

Related

How to get a model by modelname in django template

I have model LandingSnippet that contains attribute ...model = CharField()..., and it is related to context keyword (for example cars in context below)
I have next code in my view
def GeneratedLanding(request):
snippets = LandingSnippet.objects.all().filter(view_on=True).order_by('order')
context = {
'snippets':snippets,
...
'cars':Car.objects.all(), # this is cars
...
return render(request,'qlanding/generateindex.html',{'context':context})
how i can get querySet cars that is in context by keyword cars as a string
for example
{{context}}
prints
{'snippets': <QuerySet [<LandingSnippet: Snippet1Title>, <LandingSnippet: 2 - about - Лучшая служба развозки детей>]>, 'services': <QuerySet []>, 'cars': <QuerySet []>, 'faqs': <QuerySet []>}
and
{{snippet.model}}
prints
cars
QUESTION:
How can i get the {{ context.cars }} ? I think something like context[snippet.model] where snippet.model='cars'
i want push it inside another template when include
{% if snippet.module %}
{% with "qlanding/snippets/module/"|add:snippet.module|add:".html" as path %}
{% include path with model=context[snippet.model] %} # But this is incorect while rendering
{% endwith %}
{% endif %}
you can write a simple template tag like this:
first in your app directory create a directory named templatetags this directory must contains an empty file named __init__.py
create a file with any name in this directory. for example load_from_context
write these code on this file
from django import template
register = template.Library()
#register.tag(name="GetFromContext")
def get_from_context(parser, token):
bits = token.split_contents()
node_list = parser.parse(('endGetFromContext',))
variable = bits[1]
return GetFromContextNode(node_list, variable)
class GetFromContextNode(template.Node):
def __init__(self, node_list, variable):
self.node_list = node_list
self.variable = variable
def render(self, context):
variable_value = template.Variable(self.variable).resolve(context)
with context.push():
context['model'] = context.get(variable_value)
return self.node_list.render(context)
then in your template you can use it like this
{% load load_from_context %}
{# any code in your template #}
{% GetFromContext snippet.model %}
{% include path %}
{% endGetFromContext %}
#vorujack , I get the same error still. but based on your solution I got next.
from Django import template
register = template.Library()
#register.simple_tag
def get_model_from_context(context,model_name):
return context[model_name]
and how I used in view
{% get_model_from_context context=context model_name=snippet.model as model %}
{% include "qlanding/snippets/module/"|add:snippet.module|add:".html" with model=model %}
many thanks for #vorujack

Test the return value of a template tag

There's a boolean variable defined in settings.py that I'd like to make visible in my templates, so that I can control whether a part of the template is shown.
I've thought of creating a template tag to expose the value to the template:
#register.simple_tag
def show_something():
return settings.SHOW_SOMETHING
... which I would use in the template like this:
{% if show_something %}
Show it
{% endif %}
... but unfortunately it doesn't seem to work.
Also tried outputting the value, and this displays it as I expected:
{% show_something %}
Any idea if using a template tag is possible for what I need, or if there's a better way?
I think a template context processor might be better suited for this. Put a context_processors.py file in your project
context_processors.py
from django.conf import settings
def some_setting(request):
# Or some other logic here instead of always returning it
return {
'some_setting': settings.SOME_SETTING
}
settings.py
SOME_SETTING = False
TEMPLATE_CONTEXT_PROCESSORS = (
...,
'path.to.context_processors.some_setting'
)
and in your templates you can now access the variable with {{ some_setting }} or use it in an if statement like {% if some_setting %}Show this{% endif %}

Custom include tag

I want to make a custom include tag (like {% smart_include something %} ), which realize what kind a thing we want to include and then call regular {% include %} tag. That's should be something like this:
#register.simple_tag
def smart_include(something):
if something == "post":
template_name = "post.html"
return regular_include_tag(template_name)
Is there a way to use {% include %} tag in python code, and how exactly?
UPD. turn's out, the best way to solve this problem is just use render_to_string shortcut
I assume there is a reason why you are not doing:
{% if foo %}
{% include 'hello.html' %}
{% endif %}
If something is a fixed number, you can use inclusion tags. In your template instead of {% smart_tag something %}, you have {% something %}, then your tag library looks like this:
#register.inclusion_tag('post.html')
def something():
return {} # return an empty dict
Finally, you can replicate the functionality of the include tag. This snippet should point you in the right direction:
filepath = '/full/path/to/your/template/%s' % something
try:
fp = open(filepath, 'r')
output = fp.read()
fp.close()
except IOError:
output = ''
try:
t = Template(output, name=filepath)
return t.render(context)
except TemplateSyntaxError, e:
return '' # Fail silently.
return output
If you look into the django.template.loader_tags you fill find a function do_include which is basically the function that is called when we use {% include %}.
So you should be able to import it call the function itself in python.
I have not tried this but I think it should work
render_to_string will render the given template_name to an html string
from django.template.loader import render_to_string
template_name = 'post.html'
optional_context = {}
html = render_to_string(template_name, optional_context)

Check if a template exists within a Django template

Is there an out-of-the-box way of checking if a template exists before including it in a Django template? Alternatives are welcome too but some of them would not work due to the particular circumstances.
For example, here's an answer to a slightly different question. This is not what I'm looking for:
How to check if a template exists in Django?
Assuming include doesn't blow up if you pass it a bad template reference, that's probably the best way to go. Your other alternative would be to create a template tag that essentially does the checks in the link you mentioned.
Very basic implementation:
from django import template
register = template.Library()
#register.simple_tag
def template_exists(template_name):
try:
django.template.loader.get_template(template_name)
return "Template exists"
except template.TemplateDoesNotExist:
return "Template doesn't exist"
In your template:
{% template_exists 'someapp/sometemplate.html' %}
That tag isn't really all that useful, so you'd probably want to create one that actually adds a variable to the context, which you could then check in an if statement or what not.
I encountered this trying to display a template only if it exists, and wound up with the following template tag solution:
Include a template only if it exists
Put the following into yourapp/templatetags/include_maybe.py
from django import template
from django.template.loader_tags import do_include
from django.template.defaulttags import CommentNode
register = template.Library()
#register.tag('include_maybe')
def do_include_maybe(parser, token):
"Source: http://stackoverflow.com/a/18951166/15690"
bits = token.split_contents()
if len(bits) < 2:
raise template.TemplateSyntaxError(
"%r tag takes at least one argument: "
"the name of the template to be included." % bits[0])
try:
silent_node = do_include(parser, token)
except template.TemplateDoesNotExist:
# Django < 1.7
return CommentNode()
_orig_render = silent_node.render
def wrapped_render(*args, **kwargs):
try:
return _orig_render(*args, **kwargs)
except template.TemplateDoesNotExist:
return CommentNode()
silent_node.render = wrapped_render
return silent_node
Access it from your templates by adding {% load include_maybe %} at the top of your template, and using {% include_maybe "my_template_name.html" %} in code.
This approach has the nice side effect of piggy-backing the existing template include tag, so you can pass in context variables in the same way that you can with a plain {% include %}.
Switch based on whether a template exists
However, I wanted some additional formatting on the embedding site if the template existed. Rather than writing an {% if_template_exists %} tag, I wrote a filter that lets you work with the existing {% if %} tag.
To this end, put the following into yourapp/templatetags/include_maybe.py (or something else)
from django import template
from django.template.defaultfilters import stringfilter
register = template.Library()
#register.filter
#stringfilter
def template_exists(value):
try:
template.loader.get_template(value)
return True
except template.TemplateDoesNotExist:
return False
And then, from your template, you can do something like:
{% load include_maybe %}
{% if "my_template_name"|template_exists %}
<div>
<h1>Notice!</h1>
<div class="included">
{% include_maybe "my_template_name" %}
</div>
</div>
{% endif %}
The advantage of using a custom filter over using a custom tag is that you can do things like:
{% if "my_template_name"|template_exists and user.is_authenticated %}...{% endif %}
instead of using multiple {% if %} tags.
Note that you still have to use include_maybe.
I needed to conditionally include templates if they exist but I wanted to use a variable to store the template name like you can do with the regular {% include %} tag.
Here's my solution which I've used with Django 1.7:
from django import template
from django.template.loader_tags import do_include
register = template.Library()
class TryIncludeNode(template.Node):
"""
A Node that instantiates an IncludeNode but wraps its render() in a
try/except in case the template doesn't exist.
"""
def __init__(self, parser, token):
self.include_node = do_include(parser, token)
def render(self, context):
try:
return self.include_node.render(context)
except template.TemplateDoesNotExist:
return ''
#register.tag('try_include')
def try_include(parser, token):
"""
Include the specified template but only if it exists.
"""
return TryIncludeNode(parser, token)
In a Django template it might be used like this:
{% try_include "template-that-might-not-exist.html" %}
Or, if the template name is in a variable called template_name:
{% try_include template_name %}
include accepts variables:
{% include template_name %}
so you could do the check in your view.

Django: How can you get the current URL tagname (for pagination)?

I'm trying to do pagination with the page parameter in the URL (instead of the GET parameter). I also want my pagination to be shared code across multiple different templates.
Given that, I think I need to do something like this :
urls.py:
url(r'^alias/page;(?P<page>[0-9]+)/(?P<id>.*)$', alias.get, name="alias"),
tempaltes/alias.html:
<div>...stuff...</div>
{% include "paginator.html" %}
templates/paginator.html :
{% if page_obj.has_previous or page_obj.has_next %}
{% load filters %}
<div class="pagination clear">
{% if page_obj.has_previous %}
‹‹ previous
...
What is somemagic?
Assume I want to keep my url the same except set the page page_obj.previous_page_number
Edit:
You need somemagic to be a variable with the name of the current view.
Try this:
{% with request.path_info|resolve_url_name as current_view %}
{% url current_view page_obj.previous_page_number object.id %}
{% endwith %}
You can get this working with some code from django-snippets:
Variable resolving URL template tag Makes the {% url %} tag resolve variables from context.
Resolve URLs to view name The function resolve_to_name(path) returns the view name for path. You just need to create a filter that uses this function.
This solution wont work with urls like:
'alias/param1_regexp/param2_regexp/page;(?P<page>[0-9]+)/(?P<id>.*)$'
because you've no clue about param1 and param2.
A modification can be done to the django-snippets above to make this kind of urls work:
First snippet modifications:
from django.template import defaulttags, VariableDoesNotExist, Variable
class ResolvingURLNode(defaulttags.URLNode):
def render(self, context):
original_view_name = self.view_name
try:
resolved = Variable(self.view_name).resolve(context)
if len(resolved) > 1:
self.view_name = resolved[0]
if resolved[1]:
self.args = [Variable(arg) for arg in resolved[1]]
elif len(resolved) > 0:
self.view_name = resolved[0]
else:
self.view_name = resolved
except VariableDoesNotExist:
pass
ret = super(defaulttags.URLNode, self).render(context)
# restore view_name in case this node is reused (e.g in a loop) in
# which case the variable might resolve to something else in the next iteration)
self.view_name = original_view_name
return ret
defaulttags.URLNode = ResolvingURLNode
Second snippet modifications
from django.core.urlresolvers import RegexURLResolver, RegexURLPattern, Resolver404, get_resolver
__all__ = ('resolve_to_name',)
def _pattern_resolve_to_name(self, path):
match = self.regex.search(path)
if match:
name = ""
if self.name:
name = self.name
elif hasattr(self, '_callback_str'):
name = self._callback_str
else:
name = "%s.%s" % (self.callback.__module__, self.callback.func_name)
if len(match.groups()) > 0:
groups = match.groups()
else:
groups = None
return name, groups
def _resolver_resolve_to_name(self, path):
tried = []
match = self.regex.search(path)
if match:
new_path = path[match.end():]
for pattern in self.url_patterns:
try:
resolved = pattern.resolve_to_name(new_path)
if resolved:
name, groups = resolved
else:
name = None
except Resolver404, e:
tried.extend([(pattern.regex.pattern + ' ' + t) for t in e.args[0 ['tried']])
else:
if name:
return name, groups
tried.append(pattern.regex.pattern)
raise Resolver404, {'tried': tried, 'path': new_path}
# here goes monkeypatching
RegexURLPattern.resolve_to_name = _pattern_resolve_to_name
RegexURLResolver.resolve_to_name = _resolver_resolve_to_name
def resolve_to_name(path, urlconf=None):
return get_resolver(urlconf).resolve_to_name(path)
Basically, resolve_to_name returns the name of the view and it's parameters as a tuple, and the new {% url myvar %} takes this tuple and uses it to reverse the path with the view name and it's parameters.
If you don't like the filter approach it can also be done with a custom middleware.
Previous answer
You should check django-pagination, it's a really nice django application, easy tu use and gets the job done.
With django pagination the code to paginate an iterable would be:
{% load pagination_tags %}
{% autopaginate myiterable 10 %} <!-- 10 elements per page -->
{% for item in myiterable %}
RENDERING CONTENT
{% endfor %}
{% paginate %} <!-- this renders the links to navigate through the pages -->
myiterable can be anything that is iterable:list, tuple, queryset, etc
The project page at googlecode:
http://code.google.com/p/django-pagination/
It will be something like the following. Except I don't know what you mean by id so I just put a generic object id. The syntax for url is {% url view_name param1 param2 ... %}
{% url alias page_obj.previous_page_number object.id %}
Updated base on your need:
{% url alias page_obj.previous_page_number object.id as prev_url %}
{% include "paginator.html" %}
...
{% if page_obj.has_previous %}
‹‹ previous