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

27

我一直在寻找如何在django 1.8中使用jinja2的方法,但没有完整的源代码可以用来使用django和jinja2。我想知道你们是否知道使用jinja2在django中的过程。我已经查看了官方文档并查看了以下问题:如何设置django 1.8以使用jinja2?

但是它们都没有清楚地解释如何以组合的方式使用jinja2。我刚开始使用django,不知道文档中的术语。我真的很感激你们的帮助。

5个回答

27

首先,您需要安装jinja2

$ pip install Jinja2

然后在settings.py中修改TEMPLATES列表,将jinja2BACKEND添加进去:

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模板中可用。

附注:更多细节请参见这篇文章


2
我们如何添加context_processors? - ratata
1
根据 https://docs.djangoproject.com/en/1.11/topics/templates/#module-django.template.backends.django,不建议在Jinja2模板中使用上下文处理器。 - Denis Trofimov
1
在jinja2中,APP_DIRS没有任何效果。 - Eric
1
在设置中,您将环境配置为 myproject.jinja2.Environment,但您应该改用 myproject.jinja2.environment(**小写字母 'e'**)。前者加载内置的 Environment 类,其中不包含您的自定义函数“static”和“url”。 - Marcin Wojnarski

16

我花了相当长的时间来弄清楚一切,这里的答案并不是很有帮助。

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使用jinja模板,就像使用django模板一样:

from django.shortcuts import render

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

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

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


3
Django 2.0移除了django.core.urlresolvers模块,该模块在1.10版本中已移至django.urls。您应更改任何导入以使用django.urls。请参见https://dev59.com/aVgQ5IYBdhLWcg3wMhLn#43139407。 - dmmfll

2

针对Django 3+的更新:实际配置Jinja2 3.0.X +

<project_name>/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",
        ],
    },
},]

<project_name>/<project_name>/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')
    )

<project_name>/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)

<project_name>/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 "{}"

2

混合使用 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" %}

0

在 Django 网站(请参考此处以获取更多指导)中的 settings.py 文件中:

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

“BACKEND”是一个点式Python路径,指向实现Django模板后端API的模板引擎类。内置的后端包括django.template.backends.django.DjangoTemplates和django.template.backends.jinja2.Jinja2。
基本上,在您的settings.py文件中找到TEMLATES变量,并设置后端(或确保后端)与上面的类似(因为Jinga是内置的)。如果一切失败,请用“django.template.backends.jinja2.Jinja2”替换掉“django.template.backends…”(尽管我认为这不是必须的)。

Django模板语言是Django模板API吗? - shuboy2014
@wkcamp,问题在于设置了'BACKEND': 'django.template.backends.jinja2.Jinja2'。你的回复是误导性的。 - Denis Trofimov
@DenisTrofimov 我在三年前写下了这个答案。鉴于它的发布日期和缺乏支持票数,我的回复首先应该被视为过时和不相关。如果你忽略这一点,那么是的,它并没有回答问题。 - nonamorando

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接