如何在 Django 1.8 中使用 jinja2 作为模板引擎

Posted

技术标签:

【中文标题】如何在 Django 1.8 中使用 jinja2 作为模板引擎【英文标题】:How to use jinja2 as a templating engine in Django 1.8 【发布时间】:2015-08-22 11:25:26 【问题描述】:

我一直在寻找如何在 django 1.8 中使用 jinja2,但是没有完整的源代码可以将 django 与 jinja2 一起使用。我想知道你们是否知道在 django 中使用 jinja2 的过程。我查看了官方文档,并查看了以下问题:How to setup django 1.8 to use jinja2?

但他们都没有清楚地解释如何以综合方式使用 jinja2。我刚开始使用 django,不知道文档中的所有术语。非常感谢您的帮助。

【问题讨论】:

【参考方案1】:

首先你必须安装jinja2:

$ pip install Jinja2

然后在 settings.py 中修改您的 TEMPLATES 列表以包含 jinja2 BACKEND

TEMPLATES = [

    
        'BACKEND': 'django.template.backends.jinja2.Jinja2',
        'DIRS': [os.path.join(BASE_DIR, 'templates/jinja2')],
        'APP_DIRS': True,
        'OPTIONS': 'environment': 'myproject.jinja2.Environment',, 
    ,
    
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': 
        'context_processors': [
            'django.template.context_processors.debug',
            'django.template.context_processors.request',
            'django.contrib.auth.context_processors.auth',
            'django.contrib.messages.context_processors.messages',
           ],
        ,
    ,
]

templates/jinja2 是您的 jinja2 模板文件所在的目录。

在你的views.py文件中:

from __future__ import absolute_import  # Python 2 only
from jinja2 import Environment
from django.contrib.staticfiles.storage import staticfiles_storage
from django.urls import reverse

def environment(**options):
    env = Environment(**options)
    env.globals.update(
       'static': staticfiles_storage.url,
       'url': reverse,
    )
    return env

这使得 staticurl 在您的 Jinja2 模板中可用。

P.S.更多详情请见this article。

【讨论】:

我们如何添加 context_processors ? 根据docs.djangoproject.com/en/1.11/topics/templates/…,不鼓励在 Jinja2 模板中使用上下文处理器 APP_DIRS 对于 jinja2 无效。 在设置中,您将环境配置为myproject.jinja2.Environment,但您应该改用myproject.jinja2.environment小写'e')。前者加载内置的 Environment 类,它不包含您的自定义函数 'static' 和 'url'。【参考方案2】:

我花了很长时间才弄清楚一切,这里的答案并没有那么有帮助。

doru 的回答最接近真相,但并不完整。

如何使用 jinja 作为模板语言:

1.在您的项目文件夹中创建 jinja2.py 文件。这是修改默认 jinja2 环境所必需的(在我们的例子中,传递一些额外的全局变量)。

位置:root/main/jinja2.py:

from __future__ import absolute_import  # Python 2 only
from jinja2 import Environment
from django.contrib.staticfiles.storage import staticfiles_storage
from django.core.urlresolvers import reverse

def environment(**options):
    env = Environment(**options)
    env.globals.update(
       'static': staticfiles_storage.url,
       'url': reverse,
    )
    return env

2.将jinja2后端添加到django项目设置文件中,包括我们修改后的环境。

TEMPLATES = [
    
        'BACKEND': 'django.template.backends.jinja2.Jinja2',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': 
            'environment': "main.jinja2.environment",
        ,
    ,
    ...
]

3.现在您不再需要在任何地方导入 jinja2,在您的视图中,您将像 django 模板一样通过 django 使用 jinja 模板:

from django.shortcuts import render

def index(request, **kwargs):
    return render(request, "index.html.j2", 'title': 'MyTitle', 'text': "MyText")

最后,将 APP_DIRS 设置为 True jinja 将在所有已安装的应用程序jinja2 目录中搜索模板。 (与搜索 templates 文件夹的 DTL 不同)。如果你想改变这种行为,或者想要一些额外的调整,比如扩展匹配、过滤或全局变量,你应该看看 django-jinja 扩展。

您还可以通过设置的TEMPLATES['DIRS'] 选项提供其他目录来搜索模板。

【讨论】:

❝Django 2.0 删除了 django.core.urlresolvers 模块,该模块在 1.10 版中已移至 django.urls。您应该将任何导入更改为使用 django.urls。❞ 请参阅***.com/a/43139407【参考方案3】:

混合 Django 和 Jinja2 模板:环境:Django 1.8 + Jinja2

我有一些遗留的 Django 模板,一次将它们全部重写到 Jinja2 并不容易,所以将这个自定义的 % jinja_include "some_template.jinja" % 标签添加到 my_custom_tags.py

from django.template.loader import get_template
from django import template
register = template.Library()

@register.simple_tag(takes_context=True)
def jinja_include(context, filename):
    template = get_template(filename)
    return template.render(context.flatten())

从你的 Django 模板中这样调用它:

% load my_custom_tags %
% jinja_include "some_template.jinja" %

【讨论】:

【参考方案4】:

Django 3+ 更新:真实生活配置 Jinja2 3.0.X +

/settings.py

TEMPLATES = [

    "BACKEND": "django.template.backends.jinja2.Jinja2",
    "DIRS": [os.path.join(BASE_DIR, "ui", "templates")], # You can add a subdirectory like /jinja2 if you don't want Jinja2 to be default. But for consistency I do not recommand
    "APP_DIRS": True,
    "OPTIONS": 
        'environment': ".".join([os.path.basename(BASE_DIR), 'jinja2.environment']),
        "context_processors": [
            "django.contrib.auth.context_processors.auth",
            "django.template.context_processors.debug",
            "django.template.context_processors.i18n",
            "django.template.context_processors.media",
            "django.template.context_processors.static",
            "django.template.context_processors.tz",
            "django.contrib.messages.context_processors.messages",
        ],
    
,

    "BACKEND": "django.template.backends.django.DjangoTemplates",
    "DIRS": [],
    "APP_DIRS": True,
    "OPTIONS": 
        "context_processors": [
            "django.template.context_processors.debug",
            "django.template.context_processors.request",
            "django.contrib.auth.context_processors.auth",
            "django.contrib.messages.context_processors.messages",
        ],
    ,
,]

//jinja2.py

import inspect
import logging

from django.contrib import messages
from jinja2 import Environment, pass_context
from django.contrib.staticfiles.storage import staticfiles_storage
from django.urls import reverse

import ui.templatetags.extras as extras_filters
from crispy_forms.utils import render_crispy_form

logger = logging.getLogger(__name__)

# /!\ This this how you make csrf token generated by crispy properly injected
@pass_context 
def crispy(context, form):
    return render_crispy_form(form, context=context)

def environment(**options):
    logger.debug("Jinja2 environment loading")
    env = Environment(**options)
    env.globals.update(
       "get_messages": messages.get_messages,
       "static": staticfiles_storage.url,
       "crispy": crispy,  # this line is different
       "url": reverse,
   )
   # Bonus, get your django custom templatetag, backward compatible with Django Template
   env.filters.update(dict(inspect.getmembers(extras_filters, inspect.isfunction)))
   return env

/ui/views.py

import logging

from django import forms
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Submit


logger = logging.getLogger(__name__)

class AddRemoteServerForm(forms.Form):
    name = forms.CharField(max_length=20, min_length=3)
    url = forms.CharField(max_length=200)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.helper = FormHelper()
        self.helper.layout = Layout(
        'name',
        'url',
        Submit('submit', 'Associate Server')
    )

/ui/views.py

def add_remote_server(request):
if request.method == 'POST':
    form = AddRemoteServerForm(request.POST)
    logger.debug(form.data.dict())
    logger.debug("Form valid ? %s " % form.is_valid())
    if form.is_valid():
        d = form.data.dict()
        # TODO: Implmenent your business logic
        return redirect('/remote_servers/')
else:
    form = AddRemoteServerForm()
context = 'form': form
return render(request, 'form.html', context)

/ui/templates/form.html

% extends "base.html" %
% block extraappendjavascript %
% endblock %
% block content %
<div class="container">
    <div class="card">
        <div class="card-body">
             crispy(form) 
        </div>

    </div>
</div>
% endblock %

/ui/templatetags/extras.py # 奖金,仅供参考

import logging
import os
from datetime import datetime, timedelta

from django.utils.safestring import mark_safe
from django.template import Library

import json


register = Library()

logger = logging.getLogger(__name__)
@register.filter(is_safe=True)
def js(obj):
    try:
        return mark_safe(json.dumps(obj))
    except Exception:
        return ""

【讨论】:

【参考方案5】:

来自 settings.py 中的 Django website(请查看此以获得进一步指导):

TEMPLATES = [
    
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': 
            # ... some options here ...
        ,
    ,
]

BACKEND 是实现 Django 模板后端 API 的模板引擎类的点 Python 路径。内置后端是 django.template.backends.django.DjangoTemplates 和 django.template.backends.jinja2.Jinja2。

基本上找出你的 settings.py 文件中哪里有一个 TEMPLATES 变量,并设置后端(或确保后端)类似于上面的那个(因为 Jinga 是内置的)。如果一切都失败了,请将django.template.backends... 替换为django.template.backends.jinja2.Jinja2(尽管我认为没有必要)。

【讨论】:

django模板语言是django模板api吗? @wkcamp 问题在于设置'BACKEND':'django.template.backends.jinja2.Jinja2'。您的回复具有误导性。 @DenisTrofimov 我三年前写了这个答案。考虑到它的发布日期和收到的选票不足,我的回复首先应该被认为是过时的和无关紧要的。如果您忽略这一点,那么是的,它不会回答问题。

以上是关于如何在 Django 1.8 中使用 jinja2 作为模板引擎的主要内容,如果未能解决你的问题,请参考以下文章

如何在脚本中使用 django-template 而不是 jinja2?

如何在 jinja2 中使用 django 中的动态变量(variable.variable.variable)

在 Django 中使用 Jinja2 MemcachedBytecodeCache

在 jinja2 中使用 django 过滤器

如何检查 jinja2/django 模板中任何变量的大小写?

如何在 Jinja2 模板 Django 中计算循环“for in”中的所有元素