'best practices in structuring jinja templates (flask)
I wrote a site in bootstrap and thinking about refactoring it in jinja. I am not much familiar with nesting blocks, and the site is relatively simple.
My goal is to save time in maintenance when I need to update things, like hyperlinks, sidebar menus etc. but I feel insecure if I am not overcomplicating things instead of just copy paste elements in different pages.
I learnt I need to render the child template, not the parent. But seems counter intuitive to me, for I would prefer to render the parent and it will call the blocks according to the view. Child template isn't rendering what are the differences between import and extends in Flask?
Now, suppose I have 4 pages, 4 views.
The pages have in common the sidebar and other few elements; elements of child pages may be active depending on which url we are (like the active
class in the example below).
So far I have been doing this: for each view, I have a different html in this fashion
@app.route("/view1")
def view1():
..
render_template('view1.html', **othervariables)
But in order to make inheritance work, I should render the child, not the parent, so: Child template isn't rendering
@app.route("/view1")
def view1():
..
render_template('sidebar.html', **othervariables, sidebar='view1')
and sidebar.html
extends view1.html
like:
{% extends "index.html" %}
{% block sidebarMenu %}
<!-- Sidebar Menu -->
<nav>
<ul>
<li>
{%if sidemenu == 'view1'%}
<a href="#" class="active">
{% else %}
<a href="/">
{% endif %}
item 1
</a>
</li>
....
</li>
</ul>
</nav>
<!-- /.sidebar-menu -->
{% endblock %}
Sidebar is also common to other views: view2, view3, view4: See the ugly if / else structure to just tell the child template to render the active link of the correct view, that I should repeat for each element.
I thought one approach to have sidebar common to all pages may be to have:
- a base.html (one single parent template)
- a sidebar.html (extends base.html)
- view1.html ... view4.html (extends base.html)
But I am afraid to mess things up with conditionals, as example I may have different blocks declarations on base.html, and then disseminate if else in the template with variables to render the proper element (like in the example of 'active' class in sidebar, see above).
How should I structure my layout so that:
- flask calls the render_template with its corresponding view (
@app.route("/view1"
) will call a functionview1
thatrender_template=view1.html
) - sidebar is common to all the views
- I can minimise the use of conditionals, to instruct the main base to only render the corresponding blocks
Solution 1:[1]
I believe you are looking for nested templates. Basically, we have one base.html
, a sidebar.html
and then each of our specific view templates.
The base template could look something like this:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title></title>
</head>
<body>
{% block sidebarMenu %}
<!-- Sidebar gets extended into here. -->
{% endblock %}
</body>
</html>
Your sidebar template would then extend the base file, while also declaring a new block to hold the information specific to the view:
{% extends "base.html" %}
{% block sidebarMenu %}
<!-- Sidebar Menu -->
<nav>
<ul>
<li>
{% block specificMenu %}
<!-- Specific information gets extended into here. -->
{% endblock %}
item 1
</a>
</li>
....
</li>
</ul>
</nav>
<!-- /.sidebar-menu -->
{% endblock %}
And lastly, your view templates would extend your sidebar.html
, adding the specific information for that page:
{% extends "sidebar.html" %}
{% block specificMenu %}
<!-- Specific info for the current view. -->
<a href="#" class="active">
{% endblock %}
Upon rendering a view like you have described above, the view template will extend the sidebar template, which in turn extends the base template. This minimises the use of conditionals, as the blocks are only filled if the child templates get rendered.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Patrick Yoder |