Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flask - SubViews

Tags:

python

flask

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.


Edit

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.

like image 384
user2097818 Avatar asked Jul 31 '26 14:07

user2097818


1 Answers

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)
like image 53
Sean Vieira Avatar answered Aug 03 '26 05:08

Sean Vieira



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!