Multiple level template inheritance in Jinja2? - python

I do html/css by trade, and I have been working on and off django projects as a template designer. I'm currently working on a site that uses Jinja2, which I have been using for about 2 weeks. I just found out through reading the documentation that Jinja2 doesn't support multiple level template inheritance, as in you can't do more than one
{% extends "foo" %}
per rendering. Now I'm pretty sure you can do this in Django, which is powerful because you can specify a base template, specify 3 or 4 templates based on that, and then build the meat of your pages using those base templates. Isn't the point of inheritance so you have more power to abstract so your only really messing with unique code?
In any case I have no idea what to do here. I don't know if there is some way I can do it that will work as well as it could with the Django templates. I'm not exactly an expert at either Django or Jinja(2) but I can provide any information needed.

One of the best way to achieve multiple level of templating using jinja2 is to use 'include'
let say you have 'base_layout.html' as your base template
<!DOCTYPE html>
<title>Base Layout</title>
<div>
<h1>Base</h1>
.... // write your code here
{% block body %}{% endblock %}
</div>
and then you want to have 'child_layout.html' that extends 'base_layout.
{% include "base_layout.html" %}
<div>
... // write your code here
</div>
{% block body %}{% endblock %}
and now your page can just extends 'child_layout.html' and it will have both base_layout.html and child_layout.html
{% extends "child_layout.html" %}
{% block body %}
...// write your code here
{% endblock %}

The way the documentation worded it, it seemed like it didn't support inheritance (n) levels deep.
Unlike Python Jinja does not support
multiple inheritance. So you can only
have one extends tag called per
rendering.
I didn't know it was just a rule saying 1 extends per template.... I now know, with some help from the jinja irc channel.

Try this, this work for me thanks to #Ixm answer.
base.html
<html xmlns="http://www.w3.org/1999/xhtml">
<body>
{% block content %}{% endblock %}
</body>
</html>
content.html
{% extends "base.html" %}
{% block content %}
<table>
<tr>
{% include "footer.html" %}
</tr>
</table>
{% endblock %}
footer.html
{% block footer %} <td> test</td>{% endblock %}
and call with
env = Environment(loader=FileSystemLoader(os.path.join(path, "Layouts")))
template = env.get_template('content.html')
html = template.render()
print html

After struggling for a long time, I found {{super}} for multiple levels of inheritance in jinja2 templates.
The following is inspired from https://stackoverflow.com/a/31093830/1300775.
base.html
<html>
<body>
{% block title %}
Brand
{% endblock %}
</body>
layer-1.html
{% extends "base.html" %}
{% block title %}
{{ super() }} - Section
{% endblock %}
layer-2.html
{% extends "layer-1.html" %}
{% block title %}
{{ super() }} - Article
{% endblock %}
Rendering template layer-2.html will output Brand - Section - Article in block title.

I recently faced the same issue. I wanted to inherit several child templates and it worked. To illustrate it I would like to show you a solution that worked for me:
I had a base.html file that has block content and extended by manage.html. and that manage.html has a block sub_manage which is extended by internet_market.html, so visually it looks like:
|- base.html (block content)
|--manage.html (extends base.html)
|---sub_manage.html (extends manage.html)
when I rendered it, everythink worked fine, which means that you can have several {% extends %} in one render. the only thing is that if you are using relative links to your css or js files then it might not work, rather it will render, but it won't find your css/js files.
like:
<head>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<link rel="stylesheet" type="text/css" href="../static/css/bootstrap.min.css">
<script type="text/javascript" src="../static/js/bootstrap.min.js"></script>
<style type="text/css">
</head>
In that case you have to use dynamic links by using url_for. like:
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<link rel="stylesheet" type="text/css" href="{{url_for("static", filename = "css/bootstrap.min.css")}}">
<script type="text/javascript" src="{{url_for("static", filename = "js/bootstrap.min.js")}}"></script>
<style type="text/css">

See the documentation extending, including, and importing.
This provides the means of getting functionality from multiple files for different purposes and is different from the depth of the nesting.
You can perfectly have a template that extends a template that extends a template...

Multiple inheritance and multiple-level inheritance are not the same. I understand the question is related to the latter.
Let me show my workaround for the problem:
parent-template.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset='utf-8'>
<meta name='viewport' content='width=device-width, initial-scale=1'>
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
<title>Your Title</title>
<link rel='stylesheet' href="{{ url_for('static', filename='css/main.css') }}">
{% block head %}{% endblock %}
</head>
<body>
{% block nav %}{% endblock %}
{% block body %}{% endblock %}
</body>
</html>
child-template.html
{% extends 'parent-template.html' %}
{% block nav %}
<header>
<div>
<nav>
...
[navbar html code]
...
</nav>
</div>
</header>
{% endblock %}
login.html (where I don't need navbar)
{% extends 'parent-template.html' %}
{% block body %}
<header>
...
[header html code]
...
</header>
<main>
...
[main html code]
...
</main>
{% endblock %}
home.html (where I need navbar)
{% extends 'child-template.html' %}
{% block body %}
<main>
...
[main html code]
...
</main>
{% endblock %}
Both login.html and home.html uses all the data from parent-template, but only home.html uses data from child-template (the navbar).

You could use the following way to combine different contents into a single layout.html for various layout designs:
{% if instance == 'type1' %}
{% elif instance == 'type2' %}
{% else %}
{% endif %}
...and call:
render_template('layout', instance='%s' % instance)
in python code.

Related

how to deal with dynamic items that are used on the base.html in Django

I have some dynamic fields on the base.html like the footer text and the social accounts links, but I need to fetch them from the database and send them alongside with each response for a view that uses a template which extends the base.html template.
right now I am fetching the needed Items on every view and send them alongside with the view context, but I feel that this is repetitive, especially if I have more dynamic items, I tried also to save them to the request session but also it will require more code and edge cases.
what is the most efficient way to fetch these items once and be able to use them on all the views that extends the base.html template?
Alexei's answer is a good one, I just want to expand a little and say you can also use snippets for reusable chunks of HTML.
eg.
_snippet.html
<p>Some html code</p>
any_page_on_your_website.html
{% extends 'base.html %}
{% block head %}
<title>Page title</title>
{% include '_snippet.html' %}
{% endblock %}
{% block content %}
<p>page content</p>
{% endblock %}
I like to use this to seperate bits out by name, so I can easily find what I need to change. For example, you might have snippets called `_company_info.html', '_basic_footer_sitemap.html' etc. It would be easy enough to put this info into your header, footer, navbar etc. but I find having the named files makes for simpler maintenance.
UPD: if you prefer to use snippets in your case, please read the answer below from #urbanespaceman.
You can use template tags for your footer. The same as we use {% block head %} {% endblock head %} to insert to base.html unique meta title and description on each page.
Create a template tag in your footer and path any parameters in it from your views.
base.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
{% block head %}
<title></title>
<meta name="description" content="">
{% endblock head %}
</head>
<body>
{% block content %}
{% endblock %}
<footer>
{% block footer_content %}
{% endblock %}
</footer>
</body>
</html>
any_page_on_your_website.html
{% extends 'base.html' %}
{% block head %}
<title>Page title</title>
{% endblock %}
{% block content %}
<p>page content</p>
{% endblock %}
{% block footer_content %}
<p>My unique footer with dynamic variables from view: {{var1}}, {{var2}}</p>
{% endblock %}
views.py
def any_page_on_your_website(request):
var1 = SomeModel.objects.filter(foo=bar)
var2 = AnotherYourModel.objects.filter(foobar=barfoo)
thanks to #DanielRoseman he pointed me to the use of context_processor,
now I have created a context_processor that returns a dict which contains all the objects that I frequently ask for, so it is now accessible from anywhere on my templates.

what is {% block content %} and {% endblock content %} for in Django?

so I just started reading a book on Django (for beginners) and I came across the following code snipet:
<header>
Home | About
</header>
{% block content %}
{% endblock content %}
Could anyone possibly explain to me what is the use of {% block content %} and {% endblock content %}? Thank you very much in advance!
block is used for overriding specific parts of a template.
In your case, you have a block named content and this is supposed to be overridden by children that inherit from this template.
From the examples at The Django Docs
Template to be extended, named base.html
<head>
<link rel="stylesheet" href="style.css">
<title>{% block title %}My amazing site{% endblock %}</title>
</head>
Overriding Child template
{% extends "base.html" %}
{% block title %}My amazing blog{% endblock %}
"My amazing site" will be overriden by the child and then display "My amazing blog"
That's where the power of the templates comes from in a sense.
You can create a hierarchy of templates so start with base.html which might be like you've got above;
<body>
{% block content %}
{% endblock content %}
</body>
Then you can create any other template, home.html for example, and do something like;
{% extends "base.html" %}
{% block content %}
<h1>Welcome</h1>
<p>This is the home page</p>
{% endblock content %}
Then you'd reference home.html in django and it'd include the markup from base.py with the content defined in home.html.
That's the basics, but if you put some templates together using blocks you'll pick it up.
For example, you have code excerpts from 2 files:
base.html:
<body bgcolor="cyan">
{% block content %}
{% endblock %}
</body>
home.html:
{% extends 'base.html' %}
{% block content %}
<h1>Hello World from Abhishek</h1>
{% endblock %}
here in home.html, the attributes of base.html will be extended but by using {% block content %} and {% endblock %} you will be able to override the code block of home.html upon the attributes of base.html
This is Jinja template for a dynamic website.

Can we include partial css files into a template file?

I intend to create a main page in a modular way. The main page might have a header, a footer, and a main section, I'd like to keep the markup and the css that is specific to each of those sections separate. So that if I need those sections on other pages, I can just include the files.
So I need to be able to include a css file into a template in a similar way I can include an html one. I could just keep all the styling on the same css file, but if I later remove some html file, I want the styling for that file to be removed as well.
So I came up with this minimal example, and it works on my setup, but I'm not sure it will work everywhere, or if it's idiomatic in django.
As you can see bellow I define one head section on the base html file, and another on the included html file. I need both these sections to define a link to the corresponding css files. I read the documentation on the head html tag though, and I'm not so sure I can just define multiple head sections, and I'm not sure where the head section from the included file will even end up, it seems like it will end up inside the body section of the base file, which I don't know if all browsers will render correctly.
So my questions are: Can I do this on all platforms? Should I do this? Is there another, better way, of doing this?
I received some suggestions to use inheritance, I'm not sure that will work, I don't have a base file that I can make a few changes to on a child, and then render the child. I have several files, that define several different sections of a main page, that I need to bring together.
base.html:
{% load static %}
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css"
href="{% static "appfolder/css/base.css" %}" />
</head>
<body>
{% include "header.html" %}
{% include "main.html" %}
{% include "footer.html" %}
</body>
</html>
base.css:
.header {
background-color: red;
}
.footer {
background-color: blue;
}
main.html:
{% load static %}
<head>
<link rel="stylesheet" type="text/css"
href="{% static "appfolder/css/main.css" %}" />
</head>
<main>
main
</main>
main.css:
.main {
background-color: green;
}
You shouldn't define multiple head sections in HTML. But there's no need to; you should use template inheritance and blocks just like you do with any other element. You shouldn't really be using include here at all; inheritance is much more powerful.
So, base.html looks like this:
{% load static %}
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css"
href="{% static "appfolder/css/base.css" %}" />
{% block extrastyles %}{% endblock %}
</head>
<body>
<header>header</header>
{% block main %}{% endblock %}
<footer>footer</footer>
</body>
</html>
and main.html is:
{% extends "base.html" %}
{% load static %}
{% block extrastyles %}
<link rel="stylesheet" type="text/css"
href="{% static "appfolder/css/main.css" %}" />
{% endblock %}
{% block main %}
main
{% endblock %}
and in your view you render main.html, not base.html.
The first problem, it not correct to put head into body. It makes so as your main.html is not a separate HTML file but the part of base.html. The second is it is not such easy to include another file if you need to once in the future.
I make such a thing in slightly another way. When using base file it looks more useful to extend the base template instead of including files. So, in the base template, we can make some placeholder blocks.
{% load static %}
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css"
href="{% static "appfolder/css/base.css" %}" />
{% block 'additional_includes' %}{% endblock %}
</head>
<body>
<header>header</header>
{% block 'content' %}{% endblock %}
<footer>footer</footer>
</body>
</html>
Then we are going to use it. So create child template and redefine needed blocks (if you don't redefine them, they will just stay empty):
{% extends '/path_to_base/base.html' %}
{% load static %}
{% block 'additional_includes' %}
<link rel="stylesheet" type="text/css" href="{% static "appfolder/css/main.css" %}" />
{% endblock %}
{% block 'content' %}
your content
{% endblock %}
That's all. You need to refer to main.html in your views instead of base.html. And, of course, you can a lot of other child templates.
Update.
Decided to edit my reply. The common structure of html file is:
<!DOCTYPE ...>
<html>
<head>
<!-- all your meta tags -->
<!-- title -->
<!-- css and other includes, you can include so many files as you need, but it is better to use as little as possible as it can reduce server performance -->
<!-- scripts definitions (not necessary to put there, often they are paced in the end of file) -->
</head>
<body>
<!-- content of file
you can divide this part in several parts and include them
but you can't use head here, because it is body -->
</body>
</html>
This structure must be used in any framework in different languages because it is just an HTML used by the browser. Any framework must have instruments to render simple HTML pages with its template engine. And Django has its own engine, that provides to create lots of big files from small parts using extending and including. You can include some parts that are common for all of your pages. You can redefine this includes wrapping this includes in block tags. And you can create different pages with the same layout using extend, so you don't have to copy your code (for header or footer) many times.
So, in Django, you can create the following structure. I use some sort of it and it seems comfortable enough:
base.html
<!DOCTYPE ...>
<html>
<head>
{% load static %}
{% include 'meta.html' %}
<title>{% block 'title' %}Main page{% endblock %} - my site</title>
<link href='{% static "appfolder/css/base.css" %}' ... />
{% block 'additional_includes' %}{% endblock %}
</head>
<body>
{% block 'header' %}{% include 'header.html' %}{% endblock %}
<!-- header is just visible site header, not including files -->
{% block 'content' %}{% endblock %}
{% block 'footer' %}{% include 'footer.html' %}{% endblock %}
</body>
</html>
first-page.html
{% extends 'base.html' %}
{% load static %}
{% block 'title' %}First-page{% endblock %}
{% block 'additional_includes' %}
<link href='{% static "appfolder/css/first-page.css" %}' ... />
{% endblock %}
<!-- if you DON'T use block, then the content defined in base template file will remain -->
{% block 'content' %}
Some page content
{% endblock %}
second-page.html
{% extends 'base.html' %}
{% load static %}
{% block 'title' %}Second-page{% endblock %}
{% block 'additional_includes' %}
<link href='{% static "appfolder/css/second-page.css" %}' ... />
{% endblock %}
<!-- if you USE block, then its content will be rewritten with new data. you can use {{ block.super }} to add the content of block from base template -->
{% block 'header' %}{% include 'header_for_second_page.html' %}{% endblock %}
{% block 'content' %}
Another page content
{% endblock %}

Modular templates in django

I am getting started with Django, and I'm trying to make a modular template, but I don't know how. Now, I have the following files:
1- base.html (which provides basic layout for all the website):
{% load staticfiles %}
<!DOCTYPE html>
<html>
<head>
<title>My site</title>
<link rel="stylesheet" type="text/css" href="{% static 'css/style.css' %}" />
<link rel="stylesheet" type="text/css" href="{% static 'css/bootsrap.min.css' %}" />
</head>
<body>
<h1>Test title</h1>
{% block content %}
{% endblock %}
</body>
</html>
2- index.html (main db read)
{% extends 'base.html' %}
{% block content %}
{% if latest_smartphones_list %}
<ul>
{% for s in latest_smartphones_list %}
<li>{{ s.brand }} {{ s.name }}</li>
{% endfor %}
</ul>
{% else %}
<p>No smarphones available.</p>
{% endif %}
{% endblock %}
Finally, i wanted to add a third file, called menu.html which would contain the site menu. I wanted to add it in the base.html file. I've been thinking about doing it in the following way, but i doesn't work:
{% load 'menu.html' %}
Thanks so much for your help!
Instead of using {% load 'menu.html' %} you have to use {% include 'menu.html' %}
Docs:
include
load
The correct way is using the include templatetag
{% include 'menu.html' %}
which includes a template and renders it with the current context.
NB: whenever you are in trouble, django docs is the best place to go to! Always keep this in mind

Django - automating certain template behaviours

so essentially I'm a recent convert to Django (and Python for the matter) from PHP. In PHP I'm used to being able to automate many things, especially when writing HTML I used to be able to write such commands such as <?php get_head() ?> and it would go fetch all the meta information that needs to be inside the <head></head> of the HTML page. Is there any such functionality built into Django, or am I going to have to write all the HTML manually?
Thanks so much for any pointers.
You are going to love the extends and block tags.
Assuming you already got a templated page working, you can extract the basic setup of your HTML page like this:
Create a template called base.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>{% block title %}{% endblock %}</title>
{% block head %}{% endblock %}
</head>
<body>
{% block body %}
Empty page.
{% endblock %}
</body>
</html>
Now, in your page template called page.html, you can extend your base template and override any blocks:
{% extends "base.html" %}
{% block title %}Page 1 title{% endblock %}
{% block body %}
Real page content.
{% block main %}
Subpage of page.html can also override this main block.
{% endblock %}
{% endblock %}
But Hamish is right, do checkout the doc:
https://docs.djangoproject.com/en/dev/topics/templates/

Categories