This tutorial explains some of the common Flask design patterns and best practices to follow while designing web applications with examples:
Application design is an essential aspect of software development. An unplanned application design results in insurmountable technical debt. Therefore, whenever we want to scale our application, then it is okay to try out time tested design patterns.
Flask community has many such examples that can inspire you and impact your design decisions when you want to try out a few patterns for your application. Flask is so unopinionated and flexible that you might like to combine concepts from the existing patterns and create a new one.
=> Visit Here To Learn Flask From Scratch
Table of Contents:
Flask Design Patterns
For example, You will find many examples from the MVC pattern to Single Page Applications to SAAS pattern. You name the design paradigm, and it is already there tried by someone in the community and is freely available for you to try your hands on.
Enlisted below are a few of the repositories worth looking at.
Flusk
Flusk is an example that you can use to create big Flask applications that include SQLAlchemy, Docker, and Nginx. It has a beautiful logic separation to create backend, domain, views, and models into their respective layers.
It has excellent use of Flask Blueprints and follows the Factory design pattern. It is easy to create extensions in Flusk, and is further easy to containerize the application using Docker. Have a look at its source code here.
Cookiecutter Flask
Cookiecutter Flask is a flask template with features such as asset bundling and minification with webpacks. It has starter templates for user registration/authentication and is built on Bootstrap 4.
Cookiecutter is a command-line utility to create a Python package project. It means that if you use this template, you can publish your Flask application as PyPI too. This project is under active development.
It is worth evaluating at this link.
Flask Full
Flask full is one more power-packed boilerplate that makes use of Celery, MongoEngine, Signals, Shell commands, WebSocket, and eventlet. It is quite well integrated with Swagger API docs, and Sphinx docs.
Evaluate this project as its source. It is freely available here.
Flasky
For creating lightweight applications, you may want to consider Flasky. Flasky’s source code is available here. This repository was created by Miguel Grinberg, who has over 25 years of experience in web development.
He created Flasky to provide code examples for the concepts discussed in his book called Flask Web Development.
Whichever, Framework, or template you pick, all of these have some standard features and talk about those in their own ways. We here list some of those features and discuss them, and implement those using Flask-Appbuilder in our sample application of this tutorial series.
This tutorial discusses some more common patterns that you will find in almost all the web applications today and are nice to have in the kit of a web developer.
Flask Login Example
A web application usually requires Users to register and access the restricted part of the application based on the assigned privileges. The users have permission-based roles. For example, a public user doesn’t have permission to create another user. However, an Admin user has those permissions.
Sometimes, web applications automate the user registration and user creation by assigning them the default or pre-defined permissions.
Create User Offline
Let’s create a user using by using the flask fab create-user command. Once you use this command, you will get command-line prompts to give the details of the user account. Give the details similar to the ones shown below, and your User is created.
Role [Public]: Username: user1 User first name: User1 User last name: Last1 Email: user1@sthwebsite.com Password: Repeat for confirmation: ## various logs 2020-06-21 13:55:01,053:INFO:flask_appbuilder.security.sqla.manager:Added user user1 User user1 created.
Notice that at the end of the command output, the sqla.manager prints confirmation messages for user creation.
Now Access the Application, and log in with the details that you just entered. If you have created the User on the production database, then pass on those details to the person for whom you created this account.
Navigate to http://localhost:8080/login, and you will see the login form as shown below.
Once the user1 logs in, the User can see the Welcome message.
Create User Online
It might be impossible for us to create all the users offline. Moreover, it might require more technical expertise to use the flask fab create-user command in the production environment. You might get a requirement to take away some workload off from an Admin, who are most of the time tasked with the User creation.
Therefore, in our example web application, let’s allow users to register themselves.
We use Google’s reCAPTCHA service to prevent malicious actors from accessing the restricted parts of the application.
First, let’s register our domain on Google’s reCAPTCHA service and acquire the SITE key and SECRET key.
Step 1: Install Flask-Mail using the command below.
pip install Flask-Mail
Go to https://www.google.com/recaptcha/intro/v3.html and login as Admin using your Google Account.
Step 2: Choose the type of reCaptcha.
Step 3: Give the domain for which you want to use Google’s reCaptcha.
Also, add the localhost in the list of allowed domains for this key and accept the terms and submit them. You can remove it later after the development of this feature.
Step 4: Note Down the SITE KEY which is also known as a public key.
Step 5: Note Down the SECRET KEY that is also known as a private key.
Once you note down the keys as mentioned above, it is best to store them at a place where these can be referred and read in the config. For this tutorial, we have saved the values as environment variables as SITE_KEY and SECRET_KEY.
Now open the config.py and update it as shown below.
# Will allow user self registration AUTH_USER_REGISTRATION = True# The default user self registration role AUTH_USER_REGISTRATION_ROLE = "Public"# Config for Flask-WTF Recaptcha necessary for user registration RECAPTCHA_PUBLIC_KEY = os.environ.get('SITE_KEY', None) RECAPTCHA_PRIVATE_KEY = os.environ.get('SECRET_KEY', None) # Config for Flask-Mail necessary for user registration MAIL_PORT = 587 MAIL_USE_SSL = False MAIL_SERVER = "smtp.gmail.com" MAIL_USE_TLS = True MAIL_USERNAME = "sthtestmail@gmail.com" MAIL_PASSWORD = "Passw0rdqwerty" MAIL_DEFAULT_SENDER = "sthtestmail0@gmail.com"
You might have to enable less secure access to your Google Account. Enable Account access at the below URLs if you get stuck in any Email related problems.
- https://accounts.google.com/DisplayUnlockCaptcha
- https://support.google.com/mail/?p=BadCredentials
Now on the Login page, we can see an additional user Registration button. Once you click on registration, we can see many fields along with the reCaptcha Challenge.
Once you register with your email and pass the reCaptcha challenge, you will see a confirmation message, as shown below.
If the email that you gave during registration is valid, then you will receive the account activation email similar to the one shown in the below image.
Flask Admin
If you have read the other tutorials in this Flask tutorial series, then you will notice that we have taken the benefit of the in-built security that comes with Flask-Appbuilder. The views that we added using add_view_no_menu are not protected. However, the views that we added based on DataModels are automatically protected for an Admin user.
Alternatively, we could make use of Flask-Admin, which mostly would have achieved a similar outcome. Flask-Admin too, let’s define views in an Object-Oriented manner. A webpage on the frontend represents a method on a view class that we explicitly add to the interface.
In this tutorial, we do not use Flask-Admin. Instead, we take the path of achieving the same results with more speed and skipping the necessity of knowing about security build around Login, Auths, Roles, and permissions. It was possible as we used Flask-Appbuilder.
Both Flask-Appbuilder as well as Flask-Admin have their pros and cons. In the case of Flask-Admin, we must know that there are no existing security assumptions, and you can create apps based on your security model. To know more about Flask-Admin, please visit here and go through suitable examples.
Flask File Upload
Almost all web applications these days have the requirements of storing and serving files. A typical pattern for them is to save the files at a path on the Server, with some information to do the operation on the stored file and keep in Application Models and views.
We are going to work on a similar example. Let’s modify our Song Model with additional features.
In the models.py file enter the following code.
from flask import Markup, url_for from flask_appbuilder.models.mixins import FileColumn from flask_appbuilder.filemanager import get_file_original_name from flask_appbuilder import Model from sqlalchemy import Column, Integer, String, ForeignKey from sqlalchemy.orm import relationship class Song(Model): id = Column(Integer, primary_key=True) title = Column(String(200), nullable=False) rating = Column(Integer) album_id = Column(Integer, ForeignKey('album.id')) # for storing MP3 file of the song song_file = Column(FileColumn, nullable=False) album = relationship("Album") def __str__(self): return self.title def download(self): return Markup( '<a href="' + url_for("SongsView.download", filename=str(self.song_file)) + '">Download</a>' ) def file_name(self): return get_file_original_name(str(self.song_file))
We have modified our previously created Song model by adding a new column of type FileColumn. Furthermore, we have added two more columns that will be added to the SongsView to display the File Name and a link to download the uploaded file.
Flask url_for method has been used along with Markup to display the Download as a link. Also, we have used the get_file_original_name method from the Flask-Appbuilder as the file name is stored by concatenating it with a UUID to avoid collisions between the same file names.
Modify views.py with the below-given code to update the corresponding SongsView.
class SongsView(ModelView): datamodel = SQLAInterface(Song) label_columns = {"file_name" : "File Name", "download": "Download"} list_columns = ["title", "file_name", "download"] show_columns = ["title", "file_name", "download"]
In SongsView class, we have mentioned the new labels that need to be displayed, and we want to list only the columns mentioned in the specified list.
Here you need to remember that we have modified a database model by adding a column to the model. The corresponding table in the database doesn’t have this new column. Therefore, we will remove the app.db file, as we are working on the SQLite database since the last tutorial.
Alternatively, we could also use the flask db migrate command and make necessary changes to the version file, and use flask db upgrade to update the table. However, the change we introduced is minimal, and we can recreate the application database and User.
We recommend that in production, consider using the Flask-Migrate commands whenever you make any changes to the Database Schema of your application.
Use the below commands to remove the database file and create the admin user again.
rm app.db flask fab create-db flask fab create-admin
Now login into the application with the Admin credentials, and you will see the modified SongsView as shown in the below image.
Add a song with a file.
Once you save the file, the columns in the View will look as shown below.
Notice the following values in config.py. The uploaded files will be stored on this path on the Server. For this tutorial, it will be uploaded to the machine on which we are developing this sample application.
Check the upload path, as mentioned in config.py. The files are stored with the UUID’s, as shown below.
Flask HTTPS
As far as development is concerned, we may continue to run our Flask Application running without HTTPS. From a security standpoint, HTTPS ensures that communication happens between legitimate Client and Server.
This encrypted communication requires that trust is established between a Client and a Server, using a CA-signed certificate with a pair of public and private keys. Please read more about it here
In this tutorial, we will let you know the methods to develop Flask based websites using HTTPs during development.
The quickest and easiest way to include HTTPS during development is to use an adhoc ssl_context, as mentioned below in run.py. However, please install pyopenssl using pip in the environment.
app.run(host='0.0.0.0', port=8080, debug=True, ssl_context='adhoc')
After adding ssl_context, when you navigate to https://localhost:8080/, you will get a warning raising doubt about the validity of the certificate being used in this communication. Moreover, navigation to http://localhost:8080/ will not work anymore.
Thus, this approach is a bit cumbersome, and it will require you to keep accepting this request whenever you restart your development server.
You need to click on unsafe access to continue working, as shown below.
Alternatively, to develop with the https features, we can pass the path to the certificate and key in a Python Tuple to the ssl_context parameter in the run method. However, to adopt this approach, you will have to generate a self-signed certificate and a key by using the command below.
openssl req -x509 -newkey rsa:4096 -nodes -out mycert.pem -keyout mykey.pem -days 365
Give appropriate values for the asked queries.
We have left all default values. Now stop the development server, and pass the path certificate and the key path as shown below.
app.run(host='0.0.0.0', port=8080, debug=True, ssl_context=('mycert.pem', 'mykey.pem'))
This approach is also similar to the previous method of using Adhoc ssl_context. However, in this case, the details persist for a longer time. We have mentioned 365 days. You can specify the expiry to the days that you need. Moreover, these files can be shared with the other team members if you are developing in a team.
In the production environment, the certificates are issued by the CA, and Miguel Grinberg discusses some use cases here. We recommend that you read more details on that page.
Conclusion
In this tutorial, we have discussed some patterns that web developers follow while developing features related to Flask Login, Flask Admin, Flask File Upload, and Flask HTTPS. We have provided code examples, and the readers can try that too.
In our next tutorial, we will cover the concepts of extending Flask and see how to create REST API based features. Moreover, we will discuss how we can use Twitter API inside Flask.
=> Explore The Flask Training Series Here