【问题标题】:How to use jinja2 as a templating engine in Django 1.8如何在 Django 1.8 中使用 jinja2 作为模板引擎
【发布时间】: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,不知道文档中的所有术语。非常感谢您的帮助。

【问题讨论】:

    标签: python django jinja2


    【解决方案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。❞ 请参阅stackoverflow.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 我三年前写了这个答案。考虑到它的发布日期和收到的选票不足,我的回复首先应该被认为是过时的和无关紧要的。如果您忽略这一点,那么是的,它不会回答问题。
        猜你喜欢
        • 2018-05-04
        • 2016-08-23
        • 2018-07-15
        • 2017-04-13
        • 2017-06-07
        • 2011-12-12
        • 2011-06-14
        • 2011-09-17
        • 2014-03-24
        相关资源
        最近更新 更多