SoFunction
Updated on 2024-11-14

Tutorial on writing front-end templates for Python's web frameworks

Although we ran through one of the simplest MVCs, the page results were certainly not satisfactory.

For complex HTML front-end pages, we need a basic set of CSS framework to complete the page layout and basic styles. In addition, jQuery is essential as a JavaScript library for manipulating the DOM.

Writing CSS from scratch is not as good as starting directly with an existing functional CSS framework. There are many CSS frameworks to choose from. We choose uikit this time this powerful CSS framework. It has a perfect responsive layout, beautiful UI, as well as rich HTML components, so we can easily design a beautiful and simple page.

Packaged resource files can be downloaded from the uikit homepage.

All static resource files we unified to www/static directory, and grouped by category:

Copy Code The code is as follows.
static/
+- css/
|  +- addons/
|  |  +-
|  |  +-
|  |  +-
|  +-
|  +-
|  +-
|  +-
+- fonts/
|  +-
|  +-
|  +-
|  +-
+- js/
   +-
   +-
   +-
   +-

Since the front-end page is definitely more than just a home page, each page has the same header and footer. If each page is a separate HTML template, then we need to change each template when we modify the header and footer, which is obviously not efficient.

Common template engines have taken into account the reuse of duplicate HTML sections on a page. Some templates split the page into three parts via include:

<html>
  <% include file="inc_header.html" %>
  <% include file="index_body.html" %>
  <% include file="inc_footer.html" %>
</html>

This way, the same sections inc_header.html and inc_footer.html can be shared.

But the include method is not conducive to the maintenance of the overall structure of the page. jinjia2's templates also have another "inheritance" way to realize the reuse of the template is more simple.

The way to "inherit" a template is to write a "parent template" that defines some replaceable blocks. Then, write multiple "child templates", each of which can replace only the blocks defined by the parent template. e.g., define the simplest possible parent template:

<!--  -->
<html>
  <head>
    <title>{% block title%} Here is defined a file namedtitle(used form a nominal expression)block {% endblock %}</title>
  </head>
  <body>
    {% block content %} Here is defined a file namedcontent(used form a nominal expression)block {% endblock %}
  </body>
</html>

For child templates, just replace the title and content of the parent template:

{% extends '' %}

{% block title %} A {% endblock %}

{% block content %}
<h1>Chapter A</h1>
<p>blablabla...</p>
{% endblock %}

For sub-templates, as usual:

{% extends '' %}

{% block title %} B {% endblock %}

{% block content %}
<h1>Chapter B</h1>
<ul>
  <li>list 1</li>
  <li>list 2</li>
</ul>
{% endblock %}

This makes writing child templates very easy once the overall layout and CSS styles of the parent template have been defined.

Let's complete the parent template __base__.html with uikit, a CSS framework:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  {% block meta %}<!-- block meta -->{% endblock %}
  <title>{% block title %} ? {% endblock %} - Awesome Python Webapp</title>
  <link rel="stylesheet" href="/static/css/">
  <link rel="stylesheet" href="/static/css/">
  <link rel="stylesheet" href="/static/css/" />
  <script src="/static/js/"></script>
  <script src="/static/js/"></script>
  <script src="/static/js/"></script>
  <script src="/static/js/"></script>
  {% block beforehead %}<!-- before head -->{% endblock %}
</head>
<body>
  <nav class="uk-navbar uk-navbar-attached uk-margin-bottom">
    <div class="uk-container uk-container-center">
      <a href="/" class="uk-navbar-brand">Awesome</a>
      <ul class="uk-navbar-nav">
        <li data-url="blogs"><a href="/"><i class="uk-icon-home"></i> log (computing)</a></li>
        <li><a target="_blank" href="#"><i class="uk-icon-book"></i> Tutorials</a></li>
        <li><a target="_blank" href="#"><i class="uk-icon-code"></i> source code</a></li>
      </ul>
      <div class="uk-navbar-flip">
        <ul class="uk-navbar-nav">
        {% if user %}
          <li class="uk-parent" data-uk-dropdown>
            <a href="#0"><i class="uk-icon-user"></i> {{  }}</a>
            <div class="uk-dropdown uk-dropdown-navbar">
              <ul class="uk-nav uk-nav-navbar">
                <li><a href="/signout"><i class="uk-icon-sign-out"></i> appear (in a newspaper etc)</a></li>
              </ul>
            </div>
          </li>
        {% else %}
          <li><a href="/signin"><i class="uk-icon-sign-in"></i> make landfall (of typhoon etc)</a></li>
          <li><a href="/register"><i class="uk-icon-edit"></i> enrollment</a></li>
        {% endif %}
        </ul>
      </div>
    </div>
  </nav>

  <div class="uk-container uk-container-center">
    <div class="uk-grid">
      <!-- content -->
      {% block content %}
      {% endblock %}
      <!-- // content -->
    </div>
  </div>

  <div class="uk-margin-large-top" style="background-color:#eee; border-top:1px solid #ccc;">
    <div class="uk-container uk-container-center uk-text-center">
      <div class="uk-panel uk-margin-top uk-margin-bottom">
        <p>
          <a target="_blank" href="#" class="uk-icon-button uk-icon-weibo"></a>
          <a target="_blank" href="#" class="uk-icon-button uk-icon-github"></a>
          <a target="_blank" href="#" class="uk-icon-button uk-icon-linkedin-square"></a>
          <a target="_blank" href="#" class="uk-icon-button uk-icon-twitter"></a>
        </p>
        <p>Powered by <a href="#">Awesome Python Webapp</a>. Copyright &copy; 2014. [<a href="/manage/" target="_blank">Manage</a>]</p>
        <p><a href="/" target="_blank"></a>. All rights reserved.</p>
        <a target="_blank" href="#"><i class="uk-icon-html5" style="font-size:64px; color: #444;"></i></a>
      </div>
    </div>
  </div>
</body>
</html>

__base__.html defines several blocks with the following roles:

Used for subpages to define some meta, such as rss feed:

{% block meta %} ... {% endblock %}

Override the title of the page:

{% block title %} ... {% endblock %}

Subpages can insert JavaScript code before the tag is closed:

{% block beforehead %} ... {% endblock %}

The CONTENT layout and content of the subpage:

{% block content %}
...
{% endblock %}

Let's revamp the home page and inherit one from __base__.html:

{% extends '__base__.html' %}

{% block title %}log (computing){% endblock %}

{% block content %}

  <div class="uk-width-medium-3-4">
  {% for blog in blogs %}
    <article class="uk-article">
      <h2><a href="/blog/{{  }}">{{  }}</a></h2>
      <p class="uk-article-meta">Posted in.{{ blog.created_at}}</p>
      <p>{{  }}</p>
      <p><a href="/blog/{{  }}">Continue reading <i class="uk-icon-angle-double-right"></i></a></p>
    </article>
    <hr class="uk-article-divider">
  {% endfor %}
  </div>

  <div class="uk-width-medium-1-4">
    <div class="uk-panel uk-panel-header">
      <h3 class="uk-panel-title">Friendly Link</h3>
      <ul class="uk-list uk-list-line">
        <li><i class="uk-icon-thumbs-o-up"></i> <a target="_blank" href="#"> Programming</a></li>
        <li><i class="uk-icon-thumbs-o-up"></i> <a target="_blank" href="#"> reading</a></li>
        <li><i class="uk-icon-thumbs-o-up"></i> <a target="_blank" href="#"> Python Tutorials</a></li>
        <li><i class="uk-icon-thumbs-o-up"></i> <a target="_blank" href="#"> Git Tutorials</a></li>
      </ul>
    </div>
  </div>

{% endblock %}

Accordingly, the handler function for the home page URL is updated as follows:

@view('')
@get('/')
def index():
  blogs = Blog.find_all()
  # Find logged in users.
  user = User.find_first('where email=?', 'admin@')
  return dict(blogs=blogs, user=user)

Inserting some data manually into MySQL's blogs table, we can see a real front page. But the creation date of the Blog is shown as a floating point number, because it is rendered by this template:

<p class="uk-article-meta">Posted in.{{ blog.created_at }}</p>

The solution is to use jinja2's filter to convert a floating point number to a date string. Let's write a datetime filter, which is used in the template as follows:

<p class="uk-article-meta">Posted in.{{ blog.created_at|datetime }}</p>

The filter needs to be set when initializing jinja2. Modify the related code as follows:

# :

...

# Define datetime_filter with t as input and unicode string as output:.
def datetime_filter(t):
  delta = int(() - t)
  if delta < 60:
    return u'1 minute ago'
  if delta < 3600:
    return u'%s minutes ago' % (delta // 60)
  if delta < 86400:
    return u'%s hours ago' % (delta // 3600)
  if delta < 604800:
    return u'%s days ago' % (delta // 86400)
  dt = (t)
  return u'%s year %s month %s day' % (, , )

template_engine = Jinja2TemplateEngine((((__file__)), 'templates'))
# Add filter to jinjia2, the filter name is datetime and the filter itself is a function object:.
template_engine.add_filter('datetime', datetime_filter)

wsgi.template_engine = template_engine

The perfect home page is now displayed as follows:

 (640×708)