This is the eleventh part of the Flask Mega-Tutorial, in which I will tell you how to replace the basic HTML templates with new ones based on the Bootstrap user interface structure.
Under the spoiler is a list of all articles in this 2018 series.
Note 1: If you are looking for old versions of this course, this is here .
Note 2: If suddenly you would like to speak in support of my (Miguel) work, or simply do not have the patience to wait for the article for a week, I (Miguel Greenberg) offer the full version of this manual (in English) in the form of an electronic book or video. For more information, visit learn.miguelgrinberg.com .
You have been practicing with my Microblog application for some time, so I’m sure you’ve noticed that I didn’t try too hard to make the pages look beautiful, or, better said, I didn’t spend any time on it. The templates that I put together are fairly simple, with an absolutely simple style. It was important for me to focus on the actual logic of the application, without being distracted by good looking HTML and CSS.
I have already focused enough on the backend of this application. Therefore, in this chapter, I take a break from this glorious occupation and will make the application a little more attractive and outwardly professional.
This chapter will be somewhat different from the previous ones, because I will not be as detailed as working normally with Python, which in the end is the main theme of this book. Creating attractive web pages is a vast topic that is largely unrelated to web development in Python, but I’ll cover some of the basic principles and ideas. How to approach the task. And in the end, you will also have an application with a redesigned appearance for in-depth study.
GitHub links for this chapter: Browse , Zip , Diff .
Although you can argue that coding is hard, your pain is nothing compared to what web designers are experiencing, creating templates that should have a pleasant and concise look for the entire list of web browsers. In recent years, it has become better! But there are still strange errors or quirks in some browsers that greatly complicate the task of designing web pages so that they are displayed everywhere and always equally well. This is even more difficult if you also need to customize the display with the limitations of the screens for tablets and smartphones.
If you, like me, are a developer who just wants to get a good look of web pages, but do not have the time or interest to learn the depths of the mechanisms to achieve this efficiency by writing RAW HTML and CSS, then the only practical solution is to use the CSS framework
to simplify this task. You lose some creative freedom by taking this path, but on the other hand, your web pages will look decent in all browsers with minimal effort. framework CSS provides a collection of high-level CSS classes with predefined styles for common user interface element types. Most of these frameworks also provide JavaScript add-ons for solutions that cannot be made strictly with HTML and CSS.
One of the most popular CSS platforms is Bootstrap , created by Twitter. If you want to see with your own eyes the pages that can be developed with this platform in the documentation there are a few examples .
Here are some of the benefits of using Bootstrap for webpage style:
The easiest way to use Bootstrap is to simply import the Bootstrap.min.CSS
file into the base template. You can either download a copy of this file and add it to the project, or import it directly from the CDN . After that, you can start using the general-purpose CSS classes that it provides in accordance with the documentation , which is very convenient. You can import the Bootstrap.min.js
file containing the JavaScript code of the framework, which allows you to use the most advanced functions.
Fortunately, there is an extension called Flask Flask-Bootstrap. Provides a ready-to-use base template that includes the Bootstrap platform. Let's install this extension:
(venv) $ pip install flask-bootstrap
Flask-Bootstrap must be initialized, like most other Flask extensions:
app/__init__.py: Flask-Bootstrap.
# ... from flask_bootstrap import Bootstrap app = Flask(__name__) # ... bootstrap = Bootstrap(app)
When the extension is initialized, the bootstrap / base.html template becomes available in other application templates using the extends
tag.
As you remember, I already use the extends
tag with my own basic template, which allows me to form common parts of the page in one place. The base.html template defines a navigation bar that includes several links, and also exports the content
block. All other templates in my application inherit the elements of the basic template and provide the content
block with the main content of the page.
So, how should I use the basic template Bootstrap? The idea is to use a three-level hierarchy instead of two. The bootstrap / base.html template provides the basic page structure based on the Bootstrap framework. This template exports several blocks for derived templates, such as title
, navbar
and content
(see the Full List of Blocks here ). I'm going to change my base.html template to use solutions from bootstrap / base.html and provide implementations for titles ( title
), navigation blocks ( navbar
) and content blocks ( content
). In turn, base.html will export its own app_content
block for its derived templates defining the page content.
Below you can see what base.html looks like after modifying it to be the successor of the base Bootstrap template. Note that this structure does not include all the HTML for the navigation bar, but you can find the full implementation on GitHub or download the code for this chapter.
app/templates/base.html: .
{% extends 'bootstrap/base.html' %} {% block title %} {% if title %}{{ title }} - Microblog{% else %}Welcome to Microblog{% endif %} {% endblock %} {% block navbar %} <nav class="navbar navbar-default"> ... (. GitHub) ... </nav> {% endblock %} {% block content %} <div class="container"> {% with messages = get_flashed_messages() %} {% if messages %} {% for message in messages %} <div class="alert alert-info" role="alert">{{ message }}</div> {% endfor %} {% endif %} {% endwith %} {# app_content #} {% block app_content %}{% endblock %} </div> {% endblock %}
Here you can see how I use the template from bootstrap / base.html , followed by three blocks that implement the page title, navigation bar and page content, respectively.
The title
block defines the text that will be used as the title of the page, with <title>
tags. For this block, I just moved the logic that was inside the <title>
in the original base template.
The navbar
block is an optional block that is commonly used as a navigation bar. For this block, I adapted an example from the documentation on the Bootstrap navigation bar, so that it includes site branding, and then Home and Explore links. After that, I added profile, login or logout links aligned to the right page border. As I mentioned above, I omitted the HTML in the above example, but you can get the full base.html template from the download package for this chapter.
Finally, in the content
block, I define a top-level container, and inside it I have logic that displays minimized messages, which will now be displayed in the Bootstrap notification style. It is followed by a new app_content
block, which is defined so that derived templates can define their own content.
The original version of all page templates defined their contents in a block named content
. As you saw above, the block named content
used from Flask-Bootstrap, so I renamed my content
block as app_content
. After that, all my templates need to be app_content
in order to use app_content
as my content
block (content). As an example: this is the modified version of the 404.html template:
app/templates/404.html: 404.
{% extends "base.html" %} {% block app_content %} <h1>File Not Found</h1> <p><a href="{{ url_for('index') }}">Back</a></p> {% endblock %}
The area in which Flask-Bootstrap does a fantastic job is the use of forms. Instead of setting the form fields one by one, Flask-Bootstrap uses a macro that takes a form object Flask-WTF as an argument and displays the full form using Bootstrap styles.
Below you can see the redesigned register.html template as an example:
app/templates/register.html: .
{% extends "base.html" %} {% import 'bootstrap/wtf.html' as wtf %} {% block app_content %} <h1>Register</h1> <div class="row"> <div class="col-md-4"> {{ wtf.quick_form(form) }} </div> </div> {% endblock %}
Is not that great? import
at the top of the example works in the same way as importing Python. Only as part of the template. This command adds the wtf.quick_form()
macro, which, in one line of code, displays the full form, including support for display check errors, and all in Bootstrap style.
Once again, I'm not going to show you all the changes that I made for other forms in the application. But all these changes are made in the same code that you can download or check on GitHub.
The presentation logic, which displays individual blog posts, has been abstracted into a subpattern called _post.html . All I need to do with this template is to make small adjustments to make it look like Bootstrap.
app/templates/_post.html: - .
<table class="table table-hover"> <tr> <td width="70px"> <a href="{{ url_for('user', username=post.author.username) }}"> <img src="{{ post.author.avatar(70) }}" /> </a> </td> <td> <a href="{{ url_for('user', username=post.author.username) }}"> {{ post.author.username }} </a> says: <br> {{ post.body }} </td> </tr> </table>
Page binding is another area where Bootstrap provides direct support. To do this, I simply turned back to the Bootstrap documentation and adapted one of my examples. Here is what they look like on the index.html page:
app/templates/index.html: .
... <nav aria-label="..."> <ul class="pager"> <li class="previous{% if not prev_url %} disabled{% endif %}"> <a href="{{ prev_url or '#' }}"> <span aria-hidden="true">←</span> Newer posts </a> </li> <li class="next{% if not next_url %} disabled{% endif %}"> <a href="{{ next_url or '#' }}"> Older posts <span aria-hidden="true">→</span> </a> </li> </ul> </nav>
Please note that in this implementation, instead of hiding the next or previous link, when there is no more content in this direction, I use the disabled
state, which will make the link inaccessible.
I will not show everything here, but a similar change should be applied to user.html . The download package for this chapter includes these changes.
To update the application, download the zip file for this chapter and neatly compare and update your templates.
Below are a few screen shots before and after to demonstrate the transformation. Keep in mind that these changes were achieved without changing the application logic!
On the first screenshot, the invitation has the standard inscription 'Please log in to access this page.'
This is the default of the flask-login module. If for some reason this inscription does not suit you, then you can replace it with your own. To do this, you need to define the login_message
property of login_message
instance of the LoginManager
class. However, it should be remembered that if you add Cyrillic characters to the module, then it is necessary that the first line sets the required encoding.
app/__init__.py:
.
# -*- coding: utf-8 -*-
...
login = LoginManager (app)
login.login_view = 'login'
login.login_message = "Please login to open this page." # <--
I added this line
...
Source: https://habr.com/ru/post/349060/
All Articles