Проверьте, существует ли шаблон в шаблоне Django
Есть ли готовый способ проверить, существует ли шаблон, прежде чем включать его в шаблон Django? Альтернативы приветствуются, но некоторые из них не будут работать из-за особых обстоятельств.
Например, вот ответ на несколько иной вопрос. Это не то, что я ищу:
Как проверить, существует ли шаблон в Django?
Ответы
Ответ 1
Предполагая, что include
не взорвется, если вы передадите ему неправильную ссылку на шаблон, это, вероятно, лучший способ. Другой альтернативой может быть создание тега шаблона, который по существу выполняет проверки в указанной ссылке.
Очень простая реализация:
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"
В вашем шаблоне:
{% template_exists 'someapp/sometemplate.html' %}
Этот тег на самом деле не так полезен, поэтому вы, вероятно, захотите создать тот, который фактически добавит переменную в контекст, который вы могли бы проверить в инструкции if или нет.
Ответ 2
Я столкнулся с этим, пытаясь отобразить шаблон только в том случае, если он существует, и завершился следующим решением шаблона:
Включить шаблон, только если он существует
Поместите следующее в 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
Получите доступ к ним из своих шаблонов, добавив {% load include_maybe %}
в начало вашего шаблона и используя {% include_maybe "my_template_name.html" %}
в коде.
Этот подход имеет приятный побочный эффект, связанный с добавлением тега существующего шаблона, поэтому вы можете передавать контекстные переменные так же, как вы можете с помощью простого {% include %}
.
Переключение на основе наличия шаблона
Однако, если бы шаблон существовал, мне понадобилось дополнительное форматирование на сайте внедрения. Вместо написания тега {% if_template_exists %}
я написал фильтр, который позволяет работать с существующим тегом {% if %}
.
С этой целью добавьте следующее в yourapp/templatetags/include_maybe.py
(или что-то еще)
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
И затем, из вашего шаблона, вы можете сделать что-то вроде:
{% load include_maybe %}
{% if "my_template_name"|template_exists %}
<div>
<h1>Notice!</h1>
<div class="included">
{% include_maybe "my_template_name" %}
</div>
</div>
{% endif %}
Преимущество использования настраиваемого фильтра с использованием настраиваемого тега заключается в том, что вы можете делать такие вещи, как:
{% if "my_template_name"|template_exists and user.is_authenticated %}...{% endif %}
вместо нескольких тегов {% if %}
.
Обратите внимание, что вам все равно придется использовать include_maybe
.
Ответ 3
Мне нужно было условно включить шаблоны, если они существуют, но я хотел использовать переменную для хранения имени шаблона, как это можно сделать с обычным тегом {% include %}
.
Здесь мое решение, которое я использовал с 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)
Ответ 4
include
принимает переменные:
{% include template_name %}
чтобы вы могли выполнить проверку в своем представлении.