プログラム猿思慮深く、生涯学習の専門家は、スタートアップのチームで、現在どのチームリーダーである、技術スタックは、AndroidやPython、Java、および移動を必要とする、これが主な技術が私たちのチームをスタックです。
GitHubの:HTTPS://github.com/hylinux1024
マイクロチャネルパブリック番号:生涯現像剤(angrycode)
前にFlask
起動処理及びルーティング原理ソース通勤されています。今日は見とりテンプレートレンダリングプロセスを。
0x00のテンプレートを使用して
からの公式文書をレンダリングするためのテンプレートを使用した例ではまず見て
from flask import render_template
@app.route('/hello/')
@app.route('/hello/<name>')
def hello(name=None):
return render_template('hello.html', name=name)
プロジェクトディレクトリの下に必要templates
ディレクトリを作成し、hello.html
ファイルを
/templates
/hello.html
hello.html
コンテンツ
<!doctype html>
<title>Hello from Flask</title>
{% if name %}
<h1>Hello {{ name }}!</h1>
{% else %}
<h1>Hello, World!</h1>
{% endif %}
このテンプレートは、name
呼び出しによってパラメータでありrender_template
、パラメータの方法に従って達成することができhtml
、テンプレートファイルをレンダリングします。
0x01のFlask.render_template
def render_template(template_name, **context):
"""Renders a template from the template folder with the given
context.
:param template_name: the name of the template to be rendered
:param context: the variables that should be available in the
context of the template.
"""
current_app.update_template_context(context)
return current_app.jinja_env.get_template(template_name).render(context)
アプローチから、明らかである注意事項templates
にフォルダの名前を見つけるtemplate_name
レンダリングするためのファイル。これはcurrent_app
次の文で初期化されます
_request_ctx_stack = LocalStack()
current_app = LocalProxy(lambda: _request_ctx_stack.top.app)
LocalStack
これは、あるクラスのスタックの実現。そして、_request_ctx_stack
中にFlask.request_context()
例の方法では、現在のコンテキストpush
のスタックの内部に
def request_context(self, environ):
"""Creates a request context from the given environment and binds
it to the current context. This must be used in combination with
the `with` statement because the request is only bound to the
current context for the duration of the `with` block.
Example usage::
with app.request_context(environ):
do_something_with(request)
:params environ: a WSGI environment
"""
return _RequestContext(self, environ)
_RequestContext
クラスは、プロトコルコンテキストマネージャを実装し、それができるwith
の文を使用します
class _RequestContext(object):
"""The request context contains all request relevant information. It is
created at the beginning of the request and pushed to the
`_request_ctx_stack` and removed at the end of it. It will create the
URL adapter and request object for the WSGI environment provided.
"""
def __init__(self, app, environ):
self.app = app
self.url_adapter = app.url_map.bind_to_environ(environ)
self.request = app.request_class(environ)
self.session = app.open_session(self.request)
self.g = _RequestGlobals()
self.flashes = None
def __enter__(self):
_request_ctx_stack.push(self)
def __exit__(self, exc_type, exc_value, tb):
# do not pop the request stack if we are in debug mode and an
# exception happened. This will allow the debugger to still
# access the request object in the interactive shell.
if tb is None or not self.app.debug:
_request_ctx_stack.pop()
実行するには__enter__()
、操作push
、終了をwith
文の実装にpop
操作。
バックrequest_context()
である方法、wsgi_app()
で呼ばれるように
def wsgi_app(self, environ, start_response):
"""The actual WSGI application. This is not implemented in
`__call__` so that middlewares can be applied:
app.wsgi_app = MyMiddleware(app.wsgi_app)
:param environ: a WSGI environment
:param start_response: a callable accepting a status code,
a list of headers and an optional
exception context to start the response
"""
with self.request_context(environ):
rv = self.preprocess_request()
if rv is None:
rv = self.dispatch_request()
response = self.make_response(rv)
response = self.process_response(response)
return response(environ, start_response)
以下からの原理は、ルーティングの分析記事を知られており、wsgi_app()
サーバはクライアントの要求を受信したときに実行されます。
要求が来たときしたがって、電流がされるFlask
インスタンスのコンテキスト・インスタンスを要求されたインスタンスをスタックに退避され_request_ctx_stack
、内部のスタックから現在のコンテキスト・インスタンスの要求をポップするために、要求処理。
LocalProxy
プロキシクラスは、コンストラクタが渡され、あるlambda
式を:lambda: _request_ctx_stack.top.app
。
この操作は、現在のコンテキスト・インスタンスを介して置かれLocalProxy
、即ち、カプセル化されているcurrent_app
現在のFlask
プロキシ・インスタンスのコンテキスト。
ときにcurrent_app.jinja_env
文が実際にアクセスするFlask
インスタンスの属性をjinja_env
、このプロパティはであるFlask
初期化するコンストラクタ。
class Flask(object):
...
#: 源码太长了省略
#: options that are passed directly to the Jinja2 environment
jinja_options = dict(
autoescape=True,
extensions=['jinja2.ext.autoescape', 'jinja2.ext.with_']
)
def __init__(self, package_name):
...
#: 源码太长省略部分源码
#: the Jinja2 environment. It is created from the
#: :attr:`jinja_options` and the loader that is returned
#: by the :meth:`create_jinja_loader` function.
self.jinja_env = Environment(loader=self.create_jinja_loader(),
**self.jinja_options)
self.jinja_env.globals.update(
url_for=url_for,
get_flashed_messages=get_flashed_messages
)
jinja_env
これは、あるEnvironment
例。これは、jinja
テンプレートエンジンは、クラスの提供Flask
テンプレートフレームのレンダリングが通過でjinja
達成します。
Environment
必要性はloader
、以下の方法により得られます
def create_jinja_loader(self):
"""Creates the Jinja loader. By default just a package loader for
the configured package is returned that looks up templates in the
`templates` folder. To add other loaders it's possible to
override this method.
"""
if pkg_resources is None:
return FileSystemLoader(os.path.join(self.root_path, 'templates'))
return PackageLoader(self.package_name)
デフォルトでは、からtemplates
ディレクトリ構築するFileSystemLoader
インスタンスを、このクラスの役割は、ファイルシステムからテンプレートファイルをロードすることです。
0x02のEnvironment.get_template
@internalcode
def get_template(self, name, parent=None, globals=None):
"""Load a template from the loader. If a loader is configured this
method ask the loader for the template and returns a :class:`Template`.
If the `parent` parameter is not `None`, :meth:`join_path` is called
to get the real template name before loading.
The `globals` parameter can be used to provide template wide globals.
These variables are available in the context at render time.
If the template does not exist a :exc:`TemplateNotFound` exception is
raised.
.. versionchanged:: 2.4
If `name` is a :class:`Template` object it is returned from the
function unchanged.
"""
if isinstance(name, Template):
return name
if parent is not None:
name = self.join_path(name, parent)
return self._load_template(name, self.make_globals(globals))
get_template()
内部メソッド呼び出し_load_template()
方法を
@internalcode
def _load_template(self, name, globals):
if self.loader is None:
raise TypeError('no loader for this environment specified')
if self.cache is not None:
template = self.cache.get(name)
if template is not None and (not self.auto_reload or \
template.is_up_to_date):
return template
template = self.loader.load(self, name, globals)
if self.cache is not None:
self.cache[name] = template
return template
_load_template()
方法キャッシュは、キャッシュの使用に利用可能である場合、キャッシュが存在するかどうかを最初にチェックし、キャッシュが使用するために利用可能でないloader
テンプレートを読み込むためには、これはloader
以前に記載されているFileSystemLoader
(デフォルトで)インスタンス。
0x03のBaseLoader.load
@internalcode
def load(self, environment, name, globals=None):
...
# 省略部分源码
return environment.template_class.from_code(environment, code, globals, uptodate)
BaseLoader
これは、あるFileSystemLoader
基底クラス。このload
方法は、このような負荷の論理として、テンプレートの編集を可能にします。最後に、使用するenvironment.template_class.from_code()
方法を。どちらtemplate_class
でTemplate
コンパイルされたテンプレートオブジェクトを表すクラス。
from_code
でTemplate
作成するために使用することができる静的メソッドの種類Template
のインスタンスを。場合load
メソッド戻り、そこに得られたTemplate
ターゲットを。
そして最後に、バックrender_template
方法
def render_template(template_name, **context):
...
return current_app.jinja_env.get_template(template_name).render(context)
実装Template
オブジェクトrender()
のメソッド。
0x04のTemplate.render
def render(self, *args, **kwargs):
"""This function accepts either a dict or some keyword arguments which
will then be the context the template is evaluated in. The return
value will be the rendered template.
:param context: the function accepts the same arguments as the
:class:`dict` constructor.
:return: the rendered template as string
"""
ns = self.default_context.copy()
if len(args) == 1 and isinstance(args[0], utils.MultiDict):
ns.update(args[0].to_dict(flat=True))
else:
ns.update(dict(*args))
if kwargs:
ns.update(kwargs)
context = Context(ns, self.charset, self.errors)
exec self.code in context.runtime, context
return context.get_value(self.unicode_mode)
この方法は、受信したdict
テンプレートにパラメータを渡すために使用されるタイプのパラメータを、。方法コアが実行するexec
機能。組み込み関数は、動的実行できるコード。exec
Python
Python
0x05のまとめ
Flask
使用するJinja
テンプレートエンジンとして。実行パス
Flask.render_template => Environment.get_template => Template.render => exec
0x06の学習教材
- https://palletsprojects.com/p/flask/
- http://jinja.pocoo.org/docs/2.10/