(window.webpackJsonp=window.webpackJsonp||[]).push([[109],{631:function(t,e,a){"use strict";a.r(e);var s=a(56),n=Object(s.a)({},(function(){var t=this,e=t.$createElement,a=t._self._c||e;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"jinja2-environment-and-context"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#jinja2-environment-and-context"}},[t._v("#")]),t._v(" Jinja2 Environment and Context")]),t._v(" "),a("p",[t._v("The Environment and Context are two key parts of how Jinja evaluates templates.")]),t._v(" "),a("p",[t._v("The Environment contains things like the available "),a("strong",[t._v("filters")]),t._v(", "),a("strong",[t._v("configuration")]),t._v(", or "),a("strong",[t._v("tests")]),t._v(" (and more). The Context contains the variables that will be available in the rendered template, as well as any exported variables from evaluating the template (such as macros).")]),t._v(" "),a("p",[t._v("Something important to note is that if we render one template and pass it a Context, but that template tries to import something from another, the latter won't have access to the Context. It will have access to the Environment though. When we include a template, it does have access to the Context by default.")]),t._v(" "),a("p",[t._v("This means that the Context is used on a per-template basis, but the Environment is global to all templates.")]),t._v(" "),a("p",[t._v("It is because of this that the Environment has a "),a("code",[t._v("globals")]),t._v(" property that can contain variables to be shared across all rendered templates.")]),t._v(" "),a("h2",{attrs:{id:"how-we-use-the-environment-and-context"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#how-we-use-the-environment-and-context"}},[t._v("#")]),t._v(" How we use the Environment and Context")]),t._v(" "),a("p",[t._v("When we pass in values to the "),a("code",[t._v("render_template")]),t._v(" function, that adds values to the Context. Similarly, we can also tell Flask to add values to the Context through a few other means.")]),t._v(" "),a("p",[t._v("In addition, both Flask"),a("sup",{staticClass:"footnote-ref"},[a("a",{attrs:{href:"#fn1",id:"fnref1"}},[t._v("[1]")])]),t._v(" and Jinja2 provide values that are included in the Environment's "),a("code",[t._v("filters")]),a("sup",{staticClass:"footnote-ref"},[a("a",{attrs:{href:"#fn2",id:"fnref2"}},[t._v("[2]")])]),t._v(" and "),a("code",[t._v("tests")]),a("sup",{staticClass:"footnote-ref"},[a("a",{attrs:{href:"#fn3",id:"fnref3"}},[t._v("[3]")])]),t._v(" by default.")]),t._v(" "),a("p",[t._v("Flask also adds some values to the context that is passed to every rendered template as well.")]),t._v(" "),a("p",[t._v("Jinja2 provides some builtin functions"),a("sup",{staticClass:"footnote-ref"},[a("a",{attrs:{href:"#fn4",id:"fnref4"}},[t._v("[4]")])]),t._v(" which are part of the Environment, and are global.")]),t._v(" "),a("h2",{attrs:{id:"flask-context-values"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#flask-context-values"}},[t._v("#")]),t._v(" Flask context values")]),t._v(" "),a("p",[t._v("When we call "),a("code",[t._v("render_template")]),t._v(" in a Flask app, Flask passes the following values to the Context of the rendered template:")]),t._v(" "),a("ul",[a("li",[a("code",[t._v("config")]),t._v(": the current configuration object of our Flask app, "),a("code",[t._v("flask.config")]),t._v(".")]),t._v(" "),a("li",[a("code",[t._v("url_for()")]),t._v(": a function used to generate URLs given a Flask endpoint function name.")]),t._v(" "),a("li",[a("code",[t._v("get_flashed_messages()")]),t._v(": a function used to retrieve the messages that have been stored in the flashed messages stack.")])]),t._v(" "),a("p",[t._v("Flask will also add the following, if the template is rendered with an active request context (i.e. within a Flask endpoint):")]),t._v(" "),a("ul",[a("li",[a("code",[t._v("request")]),t._v(": the current request object, "),a("code",[t._v("flask.request")]),t._v(".")]),t._v(" "),a("li",[a("code",[t._v("session")]),t._v(": the current session object, "),a("code",[t._v("flask.session")]),t._v(".")]),t._v(" "),a("li",[a("code",[t._v("g")]),t._v(": the request-bound object for global variables, "),a("code",[t._v("flask.g")]),t._v(".")])]),t._v(" "),a("p",[t._v("It's important to note that these are in the Context, and not in the Environment. As such, if your rendered template imports or includes another template, that template won't have access to any of these variables by default.")]),t._v(" "),a("h2",{attrs:{id:"adding-values-to-the-context"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#adding-values-to-the-context"}},[t._v("#")]),t._v(" Adding values to the context")]),t._v(" "),a("h3",{attrs:{id:"with-render-template"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#with-render-template"}},[t._v("#")]),t._v(" With "),a("code",[t._v("render_template")])]),t._v(" "),a("p",[t._v("We've already discussed how to add new values to the Context using "),a("code",[t._v("render_template")]),t._v(": pass them in as keyword arguments.")]),t._v(" "),a("div",{staticClass:"language-py extra-class"},[a("pre",{pre:!0,attrs:{class:"language-py"}},[a("code",[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" render_template"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"home.html"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" name"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Bob"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n")])])]),a("p",[t._v("If you do that, the template's Context's "),a("code",[t._v("vars")]),t._v(" dictionary will have "),a("code",[t._v('{"name": "Bob"}')]),t._v(" inside it. You can then interpolate "),a("code",[t._v(t._s(t.name))]),t._v(", and Jinja will be able to find the correct value from there.")]),t._v(" "),a("h3",{attrs:{id:"with-context-processors"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#with-context-processors"}},[t._v("#")]),t._v(" With context processors")]),t._v(" "),a("p",[t._v("If you want to include variables in every template you render, without having to pass them manually as keyword arguments to "),a("code",[t._v("render_template")]),t._v(", then you can use a context processor, like so:")]),t._v(" "),a("div",{staticClass:"language-py extra-class"},[a("pre",{pre:!0,attrs:{class:"language-py"}},[a("code",[a("span",{pre:!0,attrs:{class:"token decorator annotation punctuation"}},[t._v("@app"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("context_processor")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("def")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("latest_posts")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"latest"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" database"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("get_posts"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("limit"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("3")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" sort"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"date"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("p",[t._v("Note the code above assumes that "),a("code",[t._v("database")]),t._v(" exists and it returns a list with the latest 3 posts.")]),t._v(" "),a("h2",{attrs:{id:"registering-filters-with-the-environment"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#registering-filters-with-the-environment"}},[t._v("#")]),t._v(" Registering filters with the Environment")]),t._v(" "),a("p",[t._v("If you want a particular template to use a particular Python function, you can pass it in as a keyword argument. This would add it to the Context for that template:")]),t._v(" "),a("div",{staticClass:"language-py extra-class"},[a("pre",{pre:!0,attrs:{class:"language-py"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("def")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("format_currency")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("value"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" currency"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string-interpolation"}},[a("span",{pre:!0,attrs:{class:"token string"}},[t._v('f"')]),a("span",{pre:!0,attrs:{class:"token interpolation"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("amount"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),a("span",{pre:!0,attrs:{class:"token format-spec"}},[t._v(".2f")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")])]),a("span",{pre:!0,attrs:{class:"token interpolation"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("currency"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")])]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"')])]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token decorator annotation punctuation"}},[t._v("@app"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("route")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"/"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("def")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("home")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" render_template"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"home.html"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" format_currency"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("format_currency"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("div",{pre:!0},[a("p",[t._v("Then, within the template, you could do "),a("code",[t._v('{{ format_currency(15.67, "£") }}')]),t._v(".")])]),a("p",[t._v("However, if you want that same function to be available to "),a("em",[t._v("all")]),t._v(" templates, you could register a filter. This would add it to the Environment that Flask uses to render templates.")]),t._v(" "),a("p",[t._v("The difference is that you'd have to use it as a filter instead of as a function call. This is how that would work:")]),t._v(" "),a("div",{staticClass:"language-py extra-class"},[a("pre",{pre:!0,attrs:{class:"language-py"}},[a("code",[a("span",{pre:!0,attrs:{class:"token decorator annotation punctuation"}},[t._v("@app"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("template_filter")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"format_currency"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("def")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("format_currency")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("value"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" currency"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string-interpolation"}},[a("span",{pre:!0,attrs:{class:"token string"}},[t._v('f"')]),a("span",{pre:!0,attrs:{class:"token interpolation"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("amount"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),a("span",{pre:!0,attrs:{class:"token format-spec"}},[t._v(".2f")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")])]),a("span",{pre:!0,attrs:{class:"token interpolation"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("currency"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")])]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"')])]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token decorator annotation punctuation"}},[t._v("@app"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("route")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"/"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("def")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("home")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" render_template"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"home.html"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("div",{pre:!0},[a("p",[t._v("That template (and all other templates) would be able to use the filter like so: "),a("code",[t._v('{{ 15.67 | format_currency("£") }}')]),t._v(".")])]),a("p",[t._v("Note that when defining custom filters, the value before the pipe ("),a("code",[t._v("15.67")]),t._v(" in this case) is passed as the first argument.")]),t._v(" "),a("h1",{attrs:{id:"conclusion"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#conclusion"}},[t._v("#")]),t._v(" Conclusion")]),t._v(" "),a("p",[t._v("We've learned how the Environment and Context work, as well as how they're different from each other.")]),t._v(" "),a("p",[t._v("If you want to:")]),t._v(" "),a("ul",[a("li",[t._v("Pass a particular piece of data to a specific template, pass it as a keyword argument when using "),a("code",[t._v("render_template")]),t._v(".")]),t._v(" "),a("li",[t._v("Pass data to all templates you are rendering, use a context processor.")]),t._v(" "),a("li",[t._v("Allow access to a function in all your templates, consider registering a filter.")])]),t._v(" "),a("hr",{staticClass:"footnotes-sep"}),t._v(" "),a("section",{staticClass:"footnotes"},[a("ol",{staticClass:"footnotes-list"},[a("li",{staticClass:"footnote-item",attrs:{id:"fn1"}},[a("p",[a("a",{attrs:{href:"https://flask.palletsprojects.com/en/1.1.x/templating/#standard-filters",target:"_blank",rel:"noopener noreferrer"}},[t._v("Standard Filters (Flask Official Documentation)"),a("OutboundLink")],1),t._v(" "),a("a",{staticClass:"footnote-backref",attrs:{href:"#fnref1"}},[t._v("↩︎")])])]),t._v(" "),a("li",{staticClass:"footnote-item",attrs:{id:"fn2"}},[a("p",[a("a",{attrs:{href:"https://jinja.palletsprojects.com/en/2.11.x/templates/#list-of-builtin-filters",target:"_blank",rel:"noopener noreferrer"}},[t._v("List of Builtin Filters (Jinja Official Documentation)"),a("OutboundLink")],1),t._v(" "),a("a",{staticClass:"footnote-backref",attrs:{href:"#fnref2"}},[t._v("↩︎")])])]),t._v(" "),a("li",{staticClass:"footnote-item",attrs:{id:"fn3"}},[a("p",[a("a",{attrs:{href:"https://jinja.palletsprojects.com/en/2.11.x/templates/#list-of-builtin-tests",target:"_blank",rel:"noopener noreferrer"}},[t._v("List of Builtin Tests (Jinja Official Documentation)"),a("OutboundLink")],1),t._v(" "),a("a",{staticClass:"footnote-backref",attrs:{href:"#fnref3"}},[t._v("↩︎")])])]),t._v(" "),a("li",{staticClass:"footnote-item",attrs:{id:"fn4"}},[a("p",[a("a",{attrs:{href:"https://jinja.palletsprojects.com/en/2.11.x/templates/#list-of-global-functions",target:"_blank",rel:"noopener noreferrer"}},[t._v("List of Global Functions (Jinja Official Documentation)"),a("OutboundLink")],1),t._v(" "),a("a",{staticClass:"footnote-backref",attrs:{href:"#fnref4"}},[t._v("↩︎")])])])])])])}),[],!1,null,null,null);e.default=n.exports}}]);