Preface
Goal: Add common feature such as configuration, terminal interface, and web server
This is a multiparts article.
Optionally, we need a web server, to refactor the HTML document into chunks. So we can develop easier.
As I promised, we will discuss about simple web server. We will utilize AIOHTTP as web server and Jinja2 as templating engine.
15: Static Sites with AIOHTTP
Web Server: We Serve Stuff
Instead of openong file from time to time. We can utilize simple web server. This would make our project more professional. And also, other people can have a look at from other pc as well, as long as it is in the same network.
There are some web server choices including Flask and AIOHTTP. You can pick whataver suit you best.
Official Documentation
Python Source Code
For convenience, I present the source code as well.
Serving HTML
The code is simple. I grab it from official documentation.
Instead of open `23-show.html’ from file manager, to either firefox or chrome, we can utilize web server.
import logging
from aiohttp import web
async def root_handler(request):
return web.HTTPFound('/23-show.html')
def main():
logging.basicConfig(level=logging.DEBUG)
app = web.Application()
app.router.add_route('*', '/', root_handler)
app.router.add_static('/', '../site')
web.run_app(app)
main()
Serving Static Files
All assets, such as bulma css
and custom javascript
,
can be called from a static folder such as site
.
app.router.add_route('*', '/', root_handler)
app.router.add_static('/', '../site')
Running Web Server
Running web server is as simple as running script.
❯ python 26-jinja2.py
======== Running on http://0.0.0.0:8080 ========
(Press CTRL+C to quit)
Preview in Web Browser
So we can we this http
protocol in our web browser.
You might wondering the result between:
localhost:8080
, 127.0.0.1:8080
, and 0:0:0:0:8080
.
Logging
Since we have this line:
import logging
def main():
logging.basicConfig(level=logging.DEBUG)
Everytime, we load a file, we have this bunch of long log.
INFO:aiohttp.access:192.168.0.67 [23/Jan/2023:17:26:52 +0000] "GET /favicon.ico HTTP/1.1" 404 173 "http://192.168.0.191:8080/" "Mozilla/5.0 (Linux; Android 5.1; A1601) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.74 Mobile Safari/537.36"
Access From Network
Now we can check our IP Address from command line.
❯ ip addr show wlan0
If you need some reference on linux, you might consider to read this article:
From command above I know that,
my ip address is 192.168.0.191
.
Now we can open, as you see in statusbar in web browser below:
- http://192.168.0.191:8080/
Now connect your smartphone to your wifi network, and open the same address.
My Oppo F1S show about the same result as above.
16: Serving Jinja2 Template
Enhance IOHTTP with Jinja2 Template
We also need to refactor our HTML into a bunch of template.
The HTML Problem
Where is Waldo?
HTML is not modular. As you can see in figure below, our HTML is getting complex day by day, and tend to be error prone.
You can try to search code part such as Bulma tab. This wil give you sometime to find whatever you seek. This could be even more stressfull in limited time.
Python Source Code
We you can just: copy, paste, and then run.
First we need to prepare handler
and template
file.
import logging
import sys
import jinja2
import aiohttp_jinja2
from aiohttp import web
class HomeHandler(web.View):
@aiohttp_jinja2.template("index.jinja")
async def get(self):
return {}
And then inject jinja2 in loader.
def main():
logging.basicConfig(level=logging.DEBUG)
app = web.Application()
# setup jinja2
aiohttp_jinja2.setup(app,
loader=jinja2.FileSystemLoader('../templates'))
app.router.add_get('/', HomeHandler, name="index")
app.router.add_static('/', '../site')
web.run_app(app)
main()
Running Web Server
And finally, run again web server using script.
❯ python 26-jinja2.py
======== Running on http://0.0.0.0:8080 ========
(Press CTRL+C to quit)
As you can see, there is no such differences, in either script and web browser. They all output the same this as previous.
17: Jinja2 Templates
Separate HTML into chunks.
The good thing with small chunks is, we can examine each HTML code, without slowly getting insane by the complexity.
But how exatcly does it looks?
The directory Tree
Consider have a look at our directory tree:
❯ exa ../templates -T
../templates
├── content-progress.jinja
├── content-report.jinja
├── content-review.jinja
├── head.jinja
├── index.jinja
├── layout.jinja
├── page-title.jinja
├── tab-contents.jinja
└── tab-names.jinja
Hmmm… Where should I start?
Layout Tree
Confused?
Consider have a look again. We are going to have this layout structure.
layout.jinja
└── head.jinja
index.jinja
├── page-title.jinja
├── tab-names.jinja
└── tab-contents.jinja
├── content-progress.jinja
├── content-review.jinja
└── content-report.jinja
Layout
This might give you better understanding, on how the html sliced into chunks happened.
<!DOCTYPE html>
<html lang="en">
{% include 'head.jinja' %}
<body>
{%block body%}{%endblock%}
</body>
</html>
Simple right?
How about the code below
{% include 'head.jinja' %}
Head
What is inside the head?
You can add meta, css link, or script here:
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, initial-scale=1.0"/>
<title>Your mission. Good Luck!</title>
<link rel="stylesheet" href="bulma.min.css">
<link rel="stylesheet" href="hover.css">
<link rel="stylesheet" href="animate.css">
<script src="22-tabs.js"></script>
<script src="23-script.js"></script>
</head>
Index
Extending Layout
Our python script load index.jinja
right?
What is the relationship with layout?
{% extends "layout.jinja" %}
{% block body %}
<div class="columns box m-1 is-multiline">
<div class="column is-full has-text-centered">
{% include 'page-title.jinja' %}
</div>
<div class="column is-full">
{% include 'tab-names.jinja' %}
</div>
<div class="column is-full">
{% include 'tab-contents.jinja' %}
</div>
</div>
{% endblock %}
This clearly show our previous structure:
index.jinja
├── page-title.jinja
├── tab-names.jinja
└── tab-contents.jinja
├── content-progress.jinja
├── content-review.jinja
└── content-report.jinja
Now we can have a peek, one template at a time:
Page Title
Index > Page Title
This is soooo short.
<h1 class="title is-3 has-text-dark
hvr-underline-from-center"
>Your mission. Good Luck!</h1>
We should do it often!
Tab Names
Index > Tab Names
Now we can concentrate on Bulma Tab instead of looking, where the code reside.
<div class="tabs is-centered">
<ul class="tab-headers">
<li data-target="progress" id="tab-progress"
class="hvr-pulse-grow is-active">
<a><span>Progress</span></a>
</li>
<li data-target="review" id="tab-review"
class="hvr-pulse-grow">
<a><span>Review</span></a>
</li>
<li data-target="report" id="tab-report"
class="hvr-pulse-grow">
<a><span>Report</span></a>
</li>
</ul>
</div>
Tab Contents
Index > Tab Contents
The rest follow.
and you can even include
sub template as well.
<div class="tab-contents has-text-centered">
<div id="progress"
class="animate__animated animate__bounceInLeft">
{% include 'content-progress.jinja' %}
</div>
<div id="review"
class="animate__animated animate__bounceInLeft">
{% include 'content-review.jinja' %}
</div>
<div id="report"
class="animate__animated animate__bounceInLeft">
{% include 'content-report.jinja' %}
</div>
</div>
Progress Content
Index > Tab Contents > Progress Content
Now you can manage each content. For example for this daily spreadsheet, this is the HTML representation
<div class="columns">
<div class="column is-full">
Sender Timestamp: <span id="d-timestamp"></span>
<br/>
Connection Status: <span id="d-status"></span>
</div>
</div>
<table class="table mx-auto">
<thead>
...
</thead>
<tbody>
...
</tbody>
</table>
Review Content
Index > Tab Contents > Review Content
And osi for the global spreadsheet, this is the HTML representation
<div class="columns">
<div class="column is-full">
Sender Timestamp: <span id="c-timestamp"></span>
<br/>
Connection Status: <span id="c-status"></span>
</div>
</div>
<table class="table mx-auto">
<thead>
...
</thead>
<tbody>
...
</tbody>
</table>
Report Content
Index > Tab Contents > Report Content
And finally, our chart… Still under construction here.
<h3 class="title is-4">Report</h3>
<p>Lorem ipsum dolor sit amet,
consectetur adipiscing elit.
<b>Quisque in faucibus magna.</b></p>
No need to be perfect.
Preview in Browser
Nothing chance.
The result is exactly the same with, our previous HTML site.
We can keep the site persistent.
More Jinja2 Example
If you want to learn more about Jinja, you can visit my site:
Or even my Pelican Bulma showcase at my repository:
What is Next 🤔?
We will continue integrating web logging with rich panel using StringIO.
Consider continue reading [ Excel - Monitor - Logging Panel ].