30 Days Of Python 👨‍💻 - Day 25 - Web Development Extras


This article is a part of a 30 day Python challenge series. You can find the links to all the previous posts of this series here:
Starting from the basic skeleton of the Flask app, today I implemented some basic features to complete our simple minimalist blog application. First using Flask’s template inheritance pattern, I worked on re-using common template code and then added two dummy posts to render them dynamically. Finally, generating a requirements.txt file to store all the package dependencies in a single file which can then be used to download all the packages using a single command.

Template Inheritance

Currently, the index.html, about.html templates contain duplicate HTML code. Since Flask uses Jinja as the templating engine, we can use the powerful template inheritance concept to create a base template file which would contain all the common HTML code such as the HTML skeleton, navbar, footer, etc. Other templates can then extend this base template hence making our template code more reusable. I created a base template file layout.html to contain the common template structure as follows:
  1. {% extends "layout.html" %}    
  2. {% block title %}Index{% endblock %}    
  3. {% block head %}    
  4.   {{ super() }}    
  5.   <style type="text/css">    
  6.     .important { color: #336699; }    
  7.   </style>    
  8. {% endblock %}    
  9. {% block content %}    
  10.   <h1>About</h1>    
  11.   <p class="important">    
  12.     Hi. I am Arindam. I love building User Interfaces. I am currently learning    
  13.     Python and created this simple blog using the Flask web development    
  14.     framework.    
  15. {% endblock %}   
A template re-usable block can be created and the code for that block needs to be placed within {% block block_name %} {% endblock %} The {% block %} informs the template engine that a child template may override these portions of the template.
The other files can then inherit this base template like this:
  1. {% extends "layout.html" %}    
  2. {% block title %}Index{% endblock %}    
  3. {% block head %}    
  4.   {{ super() }}    
  5.   <style type="text/css">    
  6.     .important { color: #336699; }    
  7.   </style>    
  8. {% endblock %}    
  9. {% block content %}    
  10.   <h1>About</h1>    
  11.   <p class="important">    
  12.     Hi. I am Arindam. I love building User Interfaces. I am currently learning    
  13.     Python and created this simple blog using the Flask web development    
  14.     framework.    
  15. {% endblock %}    
Here, the super() is used to render the contents of a block defined in the parent template.
More on templating using Flask can be found here https://flask.palletsprojects.com/en/1.1.x/patterns/templateinheritance/

Creating a Page Not Found Route

In Flask, we can handle various exceptions that can happen while loading the contents from the server such showing a custom 404 page when a route is not found, showing a custom page when there is a 500 internal server error, etc. I created a simple not_found.html file that would be rendered when a route is not found.
  1. {% extends 'layout.html' %}     
  2. {% block title %}Page Not Found{% endblock %}    
  3. {% block content %}    
  4.   <h1>Page Not Found</h1>    
  5.   <p class="important">    
  6.     Sorry, this page does not exist!    
  7. {% endblock %}   
  1. @app.errorhandler(404)    
  2. def page_not_found(error):    
  3.     return render_template('not_found.html'), 404    
More on Flask error handling can be found here.
Adding Sample Posts
For simplicity, I created a posts folder inside the templates directory and created two dummy post files first-post.html and second-post.html. Then I created a [posts.py](http://posts.py) file to read all the post files and store the names of the files in a list that can be rendered on the home page.
  1. import os    
  3. def get_all_post_names():    
  4.     try:    
  5.         post_files = os.listdir('templates/posts')    
  6.         post_names = list(map(lambda x: x.split('.')[0], post_files))    
  7.         return post_names    
  8.     except:    
  9.         print('An error occurred while fetching posts')    
  10.         return []    
  12. {% extends "layout.html" %}     
  13. {% block title %}Index{% endblock %}     
  14. {% block head%}    
  15. {{ super() }}    
  16.  {% endblock %}     
  17. {% block content %}    
  19. <h1 class="title">    
  20.   Welcome to the Python Blog.    
  21. </h1>    
  22. <h2>Recent Posts</h2>    
  23. <ul class="post-list">    
  24.   {% for post in post_names %}    
  25.   <li><a href="posts/{{post}}.html">{{post}}</a></li>    
  26.   {% endfor %}    
  27. </ul>    
  29. {% endblock %}   
All Python statements are written inside {% %} blocks as per the Jinja template syntax. Dynamic values are placed with {{ }}. We should now be able to see the two posts on the home page. Now on clicking on a post, it should open the respective post page. For that, we have to create a route that handles the post pages dynamically.
  1. @app.route('/posts/<string:post_name>')    
  2. def show_post(post_name):    
  3.     return render_template(f'posts/{post_name}.html')    
This route will handle page names and render the respective post pages dynamically.

Generating a requirement.txt file

In our Python project, we can use several external packages. If we want to share this project with someone, we need to share all the project files and also mention all the packages that are required to run the project along with the correct version number. This is not quite a practical approach.
All the installed dependencies used in the project can be listed in a single requirements.txt file (as per convention) along with their version using this command.
$ pip freeze > requirements.txt
This generates the requirements.txt file for the project. This file can be uploaded to any GIT repository. When someone downloads the project, they just need to run pip install -r requirement.txt, and all the project related dependencies would be installed with the exact versions automatically.
The complete project code can be found here.
The above project is a very minute use case of creating web apps using Python. I would like to list some useful references for further exploration:
  • A great Python web development course from edX
  • Building REST APIs using Flask
  • REST api using Django
  • https://programminghistorian.org/en/lessons/creating-apis-with-python-and-flask
  • Using Flask with Angular
  • Using Flask with React
  • Django and Angular app
That’s all for today. For the remaining part of this series, I will be briefly exploring advanced topics such as the basics of Machine Learning and Data Science with Python.
Have a great one!