Integrating Jinja with FastAPI enables you to create dynamic web pages that seamlessly blend Python code with HTML, allowing you to separate the presentation layer of your application from the logic layer. With dynamic web pages, you can generate personalized and data-driven content, enhancing user experiences.
What Is Jinja?
Jinja is a robust, feature-rich template engine for Python that generates dynamic web pages. Jinja Templating supports inheritance, conditional statements, loops, and various features that simplify the creation of dynamic web pages.
You can combine FastAPI and Jinja to create web pages with a consistent layout that can display real-time data and handle user input. You can also achieve separation of concerns, making your code more maintainable and easier to understand.
Set Up a FastAPI Project
To get started, you’ll need to set up a FastAPI project.
- Create and activate a virtual environment using these terminal commands:
python -m venv env
# On Unix/MacOS:
source venv/bin/activate# On Windows:
.\venv\Scripts\activate - Install FastAPI and the required dependencies.
pip install "fastapi[all]"
- Create a project directory my_blog.
- Create a Python file main.py in your project directory.
- Add the following code to the main.py file:
from fastapi import FastAPI
fake_posts_db = [{
'title': 'First Blog Post',
'content': 'Content of the first blog post.',
'author': 'John Doe',
'publication_date': '2023-06-20',
'comments': [
{'author': 'Alice', 'content': 'Great post!'},
{'author': 'Bob', 'content': 'Intresting read.'}
],
'status': 'published'
},{
'title': 'Second Blog Post',
'content': 'Content of the second blog post.',
'author': 'Jane Smith',
'publication_date': None,
'comments': [],
'status': 'draft'
}]app = FastAPI()
@app.get("/about")
def about():
return "All you need to know about Simple Blog"The code above creates a simple FastAPI application with a single endpoint that returns a JSON response when accessed via the corresponding URL. You can use a Python dictionary like this in place of an actual database; it helps reduce complexity while focusing on the primary goal.
- Run the server.
uvicorn main:app --reload
Visit http://localhost:8000/about in your browser to see the server response.
Integrating Jinja Templating
Having successfully set up your project, you can now add Jinja templating to it.
- In the main.py file, import the following modules:
from fastapi.templating import Jinja2Templates
from fastapi.staticfiles import StaticFiles - Below the app variable, create an instance of the Jinja2Templates class and pass the directory that will contain your templates.
templates = Jinja2Templates(directory="templates")
- After the templates variable, add the following line of code:
app.mount("/static", StaticFiles(directory="static"), name="static")
The code above mounts the static directory and instructs FastAPI to serve any static files located in the directory when a request URL begins with /static.
- In my_blog directory create two directories, templates to hold HTML files and static which will contain all static files.
With these steps completed, you have successfully integrated Jinja Templating with your project.
Creating Dynamic Web Page With Jinja
Jinja provides a rich set of syntax and features to create dynamic templates.
In this section, you’ll see how to use Jinja templating syntax to create dynamic web pages.
Template Tags
Enclose template tags with a curly brace and percent symbol on both sides. You can use such tags to perform control flow and logic operations in the template. Some commonly used template tags include:
- Condition: Runs the block of code if the condition is true.
{% if condition %}...{% endif %}
- Loop: Iterates over an iterable and runs the block of code for each item.
{% for item in iterable %}...{% endfor %}
- Include: Includes another template within the current template.
{% include 'template_name.html' %}
- Block: Defines a block that child templates can override using inheritance.
{% block block_name %}...{% endblock %}
- Extend: Allows the child template to inherit and extend the parent template.
{% extend parent_temp.html %}
These tags provide a flexible and expressive way to generate HTML content based on dynamic data and control the logic of your application.
Template Inheritance
Jinja Templating supports template inheritance. This lets you define a base (parent) template with a common layout and sections that a child template can extend or override. A child template can use the Extend tag to inherit and extend the parent template.
Create a base.html file in the templates directory with the following code.
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}Simple Blog{% endblock %}</title>
</head>
<body>
<h1>{% block heading %}Simple Blog{% endblock %}</h1> {% block content %}
{% endblock %}
{% include "footer.html" %}
</body>
</html>
This way, you have a parent template that contains the common code for all of your templates, allowing the child template to inherit and extend it as required.
In the templates directory create a footer.html file with the following code.
<footer>
<p>© 2023 Simple Blog. All rights reserved.</p>
<a href="{{ url_for('about') }}">About</a>
</footer>
footer.html is an included template that contains the HTML code for the footer section. You can reuse it across multiple pages by including it in the base template using the Include tag.
In the templates directory create a blog.html file with the following code.
{% extends "base.html" %}{% block title %}Simple Blog - Blog Page{% endblock %}
{% block heading %}Simple Blog - Blog Page{% endblock %}
{% block content %}
<h2>Total Number of Posts: {{ posts|length }}</h2>
{% for post in posts %}
<div class="post">
{% if post.status == 'published' %}
<h3>{{ post.title }}</h3>
<p>{{ post.content|truncate }}</p>
<p>Published on: {{ post.publication_date }}</p>
<h4>Comments:</h4>
<ul>
{% for comment in post.comments %}
<li class="comment">{{ comment.author }}-: {{ comment.content }}</li>
{% endfor %}
</ul>
{% else %}
<p>This post is still in draft mode.</p>
{% endif %}
</div>
<hr>
{% endfor %}
{% endblock %}
This child template inherits from base.html using the Extend tag. It overrides specific blocks defined in the base template to provide customized content for the blog page. It also includes the necessary logic and iteration for displaying a post and associated comments.
Expressions
Jinja supports a wide range of expressions, including arithmetic operations, comparisons, and logical operations. For example:
{{2 + 2}} // output: 4
Variable Substitution
To output variables in the template, enclose them within double curly braces. For example:
{{post.title}} // output: 'First Blog Post'
Filters
Filters modify the output of a variable. You can add one after a variable using the pipe symbol (|). For example:
{{post|length}} // output: 2
You can add inline comments and multiline comments in your templates. Jinja will ignore these comments during template rendering, so they are useful for adding explanations within a template.
{# #} // inline{% comment %} ... {% end comment %} // multiline
URLs
To allow you to generate correct hyperlinks to other pages within the application, the Jinja template context includes a url_for function. For example:
<a href="{{ url_for('about') }}">About</a>
The code above becomes http://localhost:8000/about. You’ll also see how to use the url_for function to get static file paths later on.
These are just some of the fundamental aspects of Jinja Templating syntax. Jinja Templating provides many more features and functionalities, such as macros, template context, and more, to make template creation and customization efficient and flexible.
Passing Data to Templates
Now that you have your templates ready you need to pass data from your FastAPI endpoints into the templates for rendering.
Add the following code to the main.py file:
from fastapi import FastAPI, Request
from fastapi.responses import HTMLResponse@app.get("https://www.makeuseof.com/", response_class=HTMLResponse)
async def read_posts(request: Request):
return templates.TemplateResponse("blog.html", {"request": request,
"posts": fake_posts_db})
The code defines a FastAPI endpoint that handles a GET request to the root URL (“/”) and returns an HTMLResponse generated from the blog.html template. It passes a context dictionary, containing the current request object and fake_posts_db, into the template. This way Jinja can render accurate and dynamic data.
Visit http://localhost:8000/ on your browser and you should see something like this:
You’ve successfully passed data into the templates for rendering.
Serving Static Files
In addition to rendering dynamic templates, FastAPI also provides functionality for serving static files such as CSS files, JavaScript files, and images.
You’ll use CSS to improve the look and feel of the page.
In the static directory, create a styles.css file with the following code.
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 20px;
background-color: #f5f5f5;
}h1, h2, h3, h4 {
color: #333;
}
.post {
background-color: #fff;
padding: 20px;
margin-bottom: 20px;
border-radius: 5px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.post h3 {
margin-top: 0;
}
.post p {
margin-bottom: 10px;
}
.post ul {
list-style-type: none;
padding-left: 0;
}
.comment {
margin-bottom: 10px;
padding: 10px;
background-color: #f9f9f9;
border-radius: 5px;
}
footer {
background-color: #f2f2f2;
padding: 10px;
text-align: center;
}
Modify the head element of the base.html template as follows:
<head>
<title>{% block title %}Simple Blog{% endblock %}</title>
<link href="{{ url_for('static', path="/styles.css") }}" rel="stylesheet">
</head>
The url_for() function generates a URL (path) for the styles.css (/static/styles.css) file in the static directory which is then served automatically by FastAPI.
Visit http://localhost:8000/ on your browser.
The same procedures apply to serving image and JavaScript files.
Remember to Follow Best Practices
When working with Jinja Templating in FastAPI, it’s important to follow certain best practices to ensure a well-organized and efficient code base.
- Organize templates in a dedicated directory and consider using subdirectories for related templates.
- Utilize template inheritance to create reusable base templates and extend them for specific content.
- Carefully select the data to pass to templates, keeping the payload lightweight, and use context processors or middleware for commonly used data.
- Make use of Jinja Templating features like macros, filters, and control structures for improved code reusability and readability.
- Optimize performance by implementing caching strategies for static templates, using HTTP caching headers, and profiling for performance bottlenecks.
By following these best practices, you can maintain a structured project, optimize rendering performance, and efficiently leverage the features of Jinja Templating in your FastAPI applications.
Using FastAPI for Building RestAPIs
Apart from building applications that require rendering templates. FastAPI excels at building RestAPIs due to its high performance, easy-to-use syntax, automatic documentation generation, and scalability. These features make FastAPI ideal for the efficient development of robust web APIs.