Which is the preferred method to use jinja2 on App

2019-04-05 12:20发布

I originally implemented Jinja2 on App Engine using the examples shown on the App Engine site here: https://developers.google.com/appengine/docs/python/gettingstartedpython27/templates where jinja2 is imported directly:

import jinja2
import os

jinja_environment = jinja2.Environment(
    loader=jinja2.FileSystemLoader(os.path.dirname(__file__)))

class MainPage(webapp2.RequestHandler):
    def get(self):
        greetings = 'somestring'
        template_values = {
            'greetings': greetings,
        }
        template = jinja_environment.get_template('index.html')
        self.response.out.write(template.render(template_values))

But I'm currently bolting on Simpleauth (https://github.com/crhym3/simpleauth) which follows the implementation that Nick Johnson described here: http://blog.notdot.net/2011/11/Migrating-to-Python-2-7-part-2-Webapp-and-templates where jinja2 is imported from webapp2_extras:

import os
import webapp2
from webapp2_extras import jinja2

class BaseHandler(webapp2.RequestHandler):
  @webapp2.cached_property
  def jinja2(self):
        return jinja2.get_jinja2(app=self.app)

  def render_template(self, filename, **template_args):
        self.response.write(self.jinja2.render_template(filename, **template_args))

class IndexHandler(BaseHandler):
  def get(self):
    self.render_template('index.html', name=self.request.get('name'))

Which of these is the preferred method for using jinja2? (They don't seem to play together nicely, and would prefer to standardize on the best option.)

4条回答
劫难
2楼-- · 2019-04-05 12:33

The first method is a very basic example.

The second (with the BaseHandler) is the preferred method. Here you put the webapp2 shared methods. These methods can be used by derived classes and here you put webapp2 methods you want to override like dispatch.

查看更多
兄弟一词,经得起流年.
3楼-- · 2019-04-05 12:35

TL;DR: Use option #2

If you don't use i18n, then it doesn't matter much. But in the real world people speak different languages than English, and there is a tricky issue with jinja2 i18n on GAE: Threading (i.e. threadsafe: true in app.yaml) is on by default and important for performance, but most jinja2 i18n docs that you can find on the web are not thread safe. Since you don't want to explicitly pass down the locale to each jinja2 macro, it needs to be held in a thread-local variable. This is what webapp2_extras.jinja2 does correctly.

查看更多
兄弟一词,经得起流年.
4楼-- · 2019-04-05 12:43

I had the same question, but the answers here do not satisfy me.

I think it's about encapsulation vs performance. For a small application you can have a global, no problem. So the first solution is just fine. It lets you solve an easy problem in an easy way, without the overhead to learn the details of a framework.

For a bigger application you probably like to encapsulate and bring some order into your objects. Basically you make a framework, an infrastructure for scalability. But that's what webapp2 is supposed to give you.

The basic problem behind it: If you decide to make a singleton type of object local to a class that gets instanciated and freed as part of the logic (like webapp2.RequestHandler classes in official examples), then that referenced object (jinja2) will be released when the last class instance is gone... you might get a lot of freeing and reallocating. So its good to have a link to an object somewhere (webapp2.registry) to prevent removing even if not referenced anywhere else. It's like global, but without poluting the global namespace, and it is accessible from everywhere through webapp2.get_app().registry. It's also caching. Then, with cached_property you do just another layer of caching.

In short: If you want to encapsulate you better add caching for your app to stay efficient

In this case you go for the webapp2_extra jinja2 and in every module you can access the same jinja environment with:

jinja2.get_jinja2().environment
查看更多
forever°为你锁心
5楼-- · 2019-04-05 13:00

I guess they are pretty much the same. What webapp2_extras.jinja2 does in addition is that it caches jinja2.Environment() initialization (for the request duration). Plus, you can leverage config/registry system of the webapp2.

Looking at get_jinja2() source you'll see that it's just a handy wrapper for jinja2.Environment() with some default environment args and enabled extensions (e.g. i18n).

查看更多
登录 后发表回答