So i have a working layout _layout.html (using Jinja2 v2.6 and Flask) which is including my header with {% include 'header.html' %} and the body contents with {% block content %}{% endblock %} (in that order).
header.html
<ul>
<li><a href="/about" {% if active_page == 'about' %} class="selected" {% endif %}>ABOUT</a></li>
</ul>
about.html
{% extends "_layout.html" %}
{% set active_page = 'about' %}
{% block content %}
...
{% endblock %}
The problem is that as the child templates are global and executed before the layout template is evaluated so the class="selected" are not being added as the header.html template does not have the active_page in its context.
If i place the header.html contents in the main layout everything works fine, how can i get this to work using the include and structure i have?
EDIT:
I have also tried {% include 'header.html' with context %} and {% from 'header.html' import input with context %} both do not work.
The easiest work around could be to just use JavaScript (JQuery in this case):
JQuery:
var currentPage = window.location.pathname;
$('nav ul li a').each(function(){
if($(this).attr('href') == currentPage){
$(this).addClass('selected');
}
});
This function will add a selected class to the <a> tag that matches the current window location.
This is how I do it:
in my _mainlayout
{% block stylesheets %}
Links to stylesheets go here
{% endblock %}
{% block main_body_area %}
Replace with your html body
{% endblock %}
{% block scripts %}
Add js scripts here
{% endblock %}
Then in the child templates simply do the following:
{% extends "_mainlayout.html" %}
{% block stylesheets %}
<style sheets go here/>
{% endblock %}
{% block main_body_area %}
<your page content here/>
{% endblock %}
{% block scripts %}
add any js scripts here
{% endblock %}
You can then add your active_page in the head section which in the example I gave you is where I keep the stylesheets. I do it this way because in my _mainlayout file I have a standard css stylesheet which is used across all pages and then if I need additional page specific layouts I include it in that particular page if not just leave it blank.
The same goes with the js files I don't want to load scripts on pages that dont need them so it makes it easy to include them on pages that do require specific js files.
I just had the same issue in Jinja2 version 2.8. Upgrading it to version 2.9 solved the problem.
Related
I have the following structure of templates:
main.html
<html>
<body>
<p>
This works: {% block title %}{% endblock %}
</p>
{% include 'heading.html' with title=title %} {# but this does not work since it is not a variable #}
</body>
</html>
heading.html
<p>
{{ title }}
</p>
page.html
{% extends 'main.html' %}
{% block title %}test title{% endblock %}
How can I pass the title from page.html to heading.html? Ideally, it should be defined as a block like now, but alternatives are also welcome. I'd like to contain the solution within the templates if possible.
Clarification:
This is a minimal example, but I have multiple pages like main.html that share a larger header that has title and some other variables that I'd like defined in the child template (not necessarily as variable as long as the text is passed).
I could put the title into the view code, but this solution would just decrease the separation of displayed data from the logic.
Use a block around the include with variables, and then wrap {{ block.super }} in the with template tag.
main.html:
<html>
<body>
<p>
This works: {% block title %}{% endblock %}
</p>
{% block with_variables %}
{% include 'heading.html' %}
{% endblock %}
</body>
</html>
page.html:
{% extends 'main.html' %}
{% block title %}test title{% endblock %}
{% block with_variables %}
{% with title="variable title" %}
{{ block.super }}
{% endwith %}
{% endblock %}
You may name it {% block heading %}, or nest the whole main.html in {% block content %}.
instead of {% include %}, you might want to use custom template tags with returning html or extension like slippers
You don't need heading.html. You can use the context variable title directly; as long as you pass it to your render function in your view, e.g.:
views.py
def my_view(request):
context = {'title': 'Hello World!'}
return render(request, 'page.html', context=context)
main.html
<html>
<body>
<p>
This is my title:
{% block title %}{% endblock %}
</p>
</body>
</html>
page.html
{% extends 'main.html' %}
{% block title %}
<strong>{{title}}</strong>
{% endblock %}
If you have administrative rights to your Django installation, an easy and elegant solution would be to switch your Django's template renderer to Jinja2 instead using django-jinja as a backend.
The main advantage of Jinja2 for the needs of this question is that it supports assignment of a block to a variable through block assignments. Since Jinja2 is inspired by the Django template language, your existing templates will need few modifications, if any.
With Jinja2 as a template renderer, you can set the title variable with a block of HTML content in the child template:
page.html
{% extends 'main.html' %}
{% set title %}test title{% endset %}
The title variable will then work in the shared template:
main.html
<html>
<body>
<p>
Main template works: {{ title }}
</p>
{% include 'heading.html' %}
</body>
</html>
And it will also work in the included template:
heading.html
<p>
Included template also works: {{ title }}
</p>
Demo: https://replit.com/#blhsing/AlarmedCleverDebugmonitor
One possible solution is to split heading.html into two and add a {% block %} in-between, but this is an ugly workaround that is prone to bugs with unclosed tags.
I am searching for a better alternative.
main.html
...
{% include 'heading1.html' %} {# containing <p> #}
{% block title %}{% endblock %}
{% include 'heading2.html' %} {# containing </p> #}
...
Additionally, if white spaces are important, there has to be no new line between includes and the block.
add your title to the rendering context and it will be visible in page, main and included heading.
I am trying to use jinja for setting default title for page for that I am using
Home{% block title %}
{% endblock title %}</title>
now on some other page I need to use this block so there if I am using only -About is shown on the title
{% block title %}
-About
{% endblock title %}</title>
expected is Home-About
if I use blockextend whole home page is coming on about page which I don't way how can I correct
this
{% extends 'base.html' %}
{% block title %}
About
{% endblock title %}</title>
The way I would do the title is have something like this in your base.html file
{% if title %}
<title>Home - {{title}}</title>
{%else%}
<title>Home</title>
{%endif%}
And then for each of your routes when you render the template you can set a title, if no title is set then the title will just be Home.
For example
retrun render_template("about.html", title = "About")
Would give you the title "Home - About"
If you want to use your method of doing it, I think what you have done should work, but in the base.html file you can change {% endblock title %} to just
{%endblock%}, and do the same in the other html file. Maybe that will solve your issue?
I hope that helps, sorry if I have misunderstood what you wanted.
To achieve this, it is better to use jinja macros. here is how:
my_macros.html
{% macro render_title(arg1, arg2) %}
# write your jinja html here
{% endmacro%}
{% macro render_something(arg1, arg2) %}
# write your jinja html here
{% endmacro%}
Then in your html where you want to use the macro:
{% extends 'base.html' %}
{% from 'my_macros.html' import render_title %}
{% block content %}
{{ render_title("something", "something else") }}
# jinja html anywhere
{% endblock content %}
I'm attempting to make a base template for my website. Ideally it would look like this
{% block navigationbar %}{% endblock %}
{% block content %}{% endblock %}
{% block footer %}{% endblock %}
This way I am able to have separate navigationbar.html and footer.html files. All views I would like to show would then just put this:
{% extends 'portfolio/base.html' %}
{% block content %}
// View Code here
{% endblock %}
Any way to achieve this. I have realized I can't do multiple extends and I've tried different combinations of nesting but nothing has worked for me so far.
So the ideal result would be 4 files. for the homepage:
NavigationBar.html - Holds the navigation bar code
Footer.html - Holds the footer code
Base.html - Holds the navigation bar, footer, and content
Home.html - Holds the content of the home page, but when it loads the user sees the navigationbar, and footer as well.
You can use include that loads a template and renders it with the current context. This is a way of “including” other templates within a template.
This example includes the contents of the template "NavigationBar.html" and "Footer.html" on your template:
{% extends 'portfolio/base.html' %}
{% block content %}
{% include "NavigationBar.html" %}
// View Code here
{% include "Footer.html" %}
{% endblock %}
You can also pass additional context to the template using arguments:
{% include "NavigationBar.html" with breadcrumb="home > wherever" %}
{% extends "bootstrap/base.html" %}
{% block content %}
<div class="container">
{% block page_content %}{% endblock %}
</div>
{% endblock %}
This works fine, however I am wondering where i can see the documentation for page_content block. i can't find any reference in available blocks for flask Bootstrap.
What defines page_content? Flask-Bootstrap or Jinja2?
Jinja2 does not define anything. It is just the framework.
I don't know which version of Flask-Bootstrap you are using, but I'm sure page_content is from it or from a dependency of it.
Flask-Bootstrap docs define the available blocks.
https://pythonhosted.org/Flask-Bootstrap/basic-usage.html#available-blocks
Of course you can check their templates and override anything else there, but I didn't found the page_content in their code. Maybe it is from an older version.
https://github.com/mbr/flask-bootstrap/search?utf8=%E2%9C%93&q=page_content
Hope this clarifies the confusion.
{% extends "bootstrap/base.html" %}
{% block content %}
<div class="container">
{% block page_content %}{% endblock %}
</div>
{% endblock %}
From your code note that {% block content %} is a Flask-Bootstrap's actually base template block. Blocks defined between {% block content %} and {% endblock %} can be named anything. The idea is that you can add new blocks (name them anything you want) but they must be defined inside a block that already exists in a parent template, and {% block content % } does exist in "bootstrap/base.html".
It seems that it's a user defined symbol, you can test this with changing both "base.html" and "derived.html"'s {% block page_content %} to {% block abcde %}, it also works, so I think it's a section reference.
i'm developing a small app with Python and Google app engine. I'm using boilerplate (https://github.com/coto/gae-boilerplate) as front-end which follows gae direction and python templates, so nothing diffrent than plain stuff.
Now, what i would like to have is this.
When a user logged in, if the field of name and last name are not filled in i would like to have, in the home page, the profile editing.
The page for editing the profile is a template (which extend the base.html), called edit_profile.html which works well.
The homepage is a template as well (extend the base.html) called home.html.
Now, can i include the edit_profile.html in home.html? how can i do it?
this is what i've, i don't know what to put instead of ???? i tried with
{% block edit_profile.html %} {% endblock %}
but does not work
{% if user_info.name and user_info.last_name %}
..
{% else %}
????
{% endif %}
thanks.
So you want to include only some block of given template. There are two solutions:
1) Create template just for profile editing form and include it into edit_profile.html. Then include it also into home.html to if condition branch:
profile_form.html:
<form action="{% url some-action %}">
{{ form }}
<input type="submit" value="save"/>
</form
profile_edit.html
{% extends "base.html" %}
{% block main %}
{% include "profile_form.html" %}
{% endblock %}
home.html
{% if user_info.name and user_info.last_name %}
{% include "profile_form.html" %}
{% endif %}
2) use variable for extended template:
profile_form.html
{% extend BASE_TEMPLATE %}
and set it into context w/ different value as needed:
in home.html (let's say included_form.html is some basic template)
{% if user_info.name and user_info.last_name %}
{% with "included_form.html" as BASE_TEMPLATE %}
{% include "edit_profile.html" %}
{% endwith %}
{% endif %}
and if you want show form as a standalone page, set BASE_TEMPLATE to base.html