I am looking to use a certain design pattern in my application, but I am not sure if my pattern really even fits with Flask mechanisms. I am just verifying that I have not overlooked existing solutions.
I would like to have a top-level View that renders the response of another proxied request. The thing is, I am not proxying external URLs, but rather views from within my same application (kind of like Blueprints that depend on other Blueprints). Similar to the 'render_template()' function, I am looking for something like render_view, or even better, *request_view_as_string*. I then need to process the response and re-render.
I am using template inheritance to the best of my abilities (jinja2), but much of my difficulty is coming from lots of non-template processing in between the template blocks. I am still getting a feel for jinja, and my templates are starting to feel polluted with hacks.
Basically, I misunderstood the role of jinja. My application needs to build heavier on jinja. I kept trying to get in and out of jinja as quickly as possible, and that is where my nested dependencies were starting to cause problems. Ultimately, most of the features I needed for my "subviews" was built right into Jinja, I just wasn't sure how to properly integrate them with FLask.
First off, Jinja2 supports macros, which let you share functionality between templates:
{# helpers.jinja #}
{% macro generate_select(itrbl) %}
<select{{kwargs|xmlattrs}}>
{% for item in itrbl %}
<option value="{{item.value}}">{{item.text}}</option>
{% endfor %}
</select>
{% endmacro %}
{# page1.jinja #}
{% import "helpers.jinja" as helpers %}
{{ helpers.generate_select(data, name="my_data_field") }}
For more complicated bits of functionality (A / B testing, loading different features depending on what the user's account has enabled, etc.) extends, include, and import can take variable values:
{# A custom template with a *lot* of hooks #}
{% extends base_template %}
{% import custom_functionality_provider as provider %}
{% block common_name %}
{% if features.feature_x %}
{% include feature_x_include %}
{% endif %}
{{ provider.operation() }}
{% endblock common_name %}
@app.route("/some-route")
def some_route():
# Of course, in real life you would determine these values
# on the basis of user / condition lookups, rather than
# hardcoding values in your render_template call
render_template("custom.jinja", base_template="AB/A/base.jinja",
custom_functionality_provider="macros/lowcostplan.jinja",
feature_x_include="AB/A/features/feature_x.jinja",
features=some_features_object)
Finally, you can pass callables that return strings to any Jinja template, giving you access to the full power of Python:
def custom_implimentation_a(**context_args):
return render_template("template_a.jinja", **context_args)
def custom_implimentation_b(**context_args):
return render_template("template_b.jinja", **context_args)
@app.route("/some-route")
def some_route():
if condition:
provider = custom_implimentation_a # Note, no parenthesis
else:
provider = custom_implimentation_b
return render_template("some_page.jinja", provider=provider)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With