Flask

From Grundy
Jump to navigation Jump to search

Flask is a micro web framework written in Python, launched in 2010. Considered one of the simplest python framework and easiest to learn, there's no doubt that it's the one of most popular ones as well. It's a tool to create sites quicker. It's not required, frameworks never are, but it makes development faster by offering code for all sorts of processes like database interaction or file activity.

Why Flask?

  • It's based on Python: We all know that Python is one of the coolest languages ever to code, because of the ease of understanding and easy to code nature. Python has a great number of libraries for diverse applications such as Numerical computing, Machine learning, Data analytics which greatly eases up development. Like the Python community in general, the Flask community contributes useful packages and utilities for use by the wider world. Searching for “flask” on PyPI finds over 4,000 packages available for use.
  • Good Documentation: Flask has an incredible documentation. And it most definitely is an inspiration as to why documenting your project properly is so crucial. It saves a lot of time, which otherwise would have been wasted in trial and error.
  • Performance: You can think about a micro framework being slightly more “low-level” than something like Django. There are fewer levels of abstraction between you and the database, the requests, the cache, etc. So performance is inherently better from the start.
  • Modularity: Modular code provides a huge number of benefits. With Flask, you have the ability to create multiple Flask applications or servers, distributed across a large network of servers, each with specific purposes. This creates more efficiency, better testability, and better performance.

Getting started

  • Installation:Just a pip install flask in your terminal will do your job, of course, provided that you have pip installed, which I am assuming you do because you're going to work on a Python framework. If not, I have created a thorough document to install python and pip
  • Documentation: I strongly suggest that you do read the documentation, as it is actually a good way to know about how it came into existence and will definitely help you appreciate the beauty of this framework.
  • Tutorials: Though the documentation itself has good tutorials, but it's way better to have someone explain it in a video while showing you live examples. So here are links to some tutorials which I personally used to explore flask, and definitely would recommend as well - Corey Schafer, rmotr.com. I would recommend starting with rmotr's videos and completing the whole playlist. It might be better to refer to Corey's specific videos in the playlist for learning specific things. Also, here is the GitHub Repository containing all the codes listed below.

Your First Flask Webapp

1 from flask import Flask
2 app = Flask(__name__)
3 
4 @app.route("/")
5 def hello():
6 	return "My first Flask Webapp"
7 
8 if __name__ == '__main__':
9 	app.run(debug=True)

Type this python code in your text editor, save it as main.py and run it in your terminal by typing python main.py. Now open http://127.0.0.1:5000/ in your browser, and you should see the text "My first Flask Webapp". Now let's understand this code line by line. flask is a python library, while Flask is a class. The we create the app variable and set this to the instance of Flask. While __name__ is a special variable in python, that is just the name of the module. It basically is for flask to know where to look for templates, etc. Next comes route. Routes are decorators(always start with an @) and allow us to go to different pages like About,Contact, etc. In simple words, decorators just add additional functionality to existing functions. In our case, app.route() decorator will allow us to show the code on our website for this specific route. The / represents the home page of our website. def is used to define a function, that returns the given string.

Template Inheritance

Now that we have learnt how to get a server running, let's make something much more interesting. You do realise that even though it's possible but it's not actually feasible/advisable to write the code of all pages in a single file. Here's where templating languages come into picture. Python uses Jinja2 as its templating language. Although, not much knowledge in this context right now. Create a templates folder in the same directory as your file. Create a file home.html in that directory. Write some basic html code in that file. Now we want to import our home.html in main.py. For that, we have to import a render_template function from flask. Then return render_template('home.html'). So now, your main.py file looks like -

1 from flask import Flask, render_template
2 app = Flask(__name__)
3 
4 @app.route("/")
5 def hello():
6 	return render_template('home.html')
7 
8 if __name__ == '__main__':
9 	app.run(debug=True)

Try editing the HTML page, while your server is running. Save the changes, and refresh the webpage. You can see your changes without having to restart your server again, Note: It's always better to do a ctrl+shift+R instead of ctrl+R as the former clears cache as well. Task: try adding more routes and templates, like About,Contact, etc. with the pages containing links for each other. Now, you would have noticed that most sites have a common navigation bar for each page, and maybe a sidebar too. It would be wasteful to write that piece of code again and again in each and every file, so, thanks to Jinja2, we can create a layout.html file, with all other files extending its code. This is called Template Inheritance. Anyways, so type the following code in your layout:

 1 <!DOCTYPE html>
 2 <html>
 3 <head>
 4  {% block head %}
 5  <title>{% block title %}{% endblock %}</title>
 6  {% endblock %}
 7 </head>
 8 <body>
 9  {% block body %}{% endblock %}
10 </body>
11 </html>

As you might probably guess, other html files just have to write the code to be put in-between the block tags. Also, block tags are nested, like all HTML tags, i.e. The tag opened most recently is to be closed first. Type the following code in home.html:

1 {% extends “layout.html” %}
2 {% block title %} Index {% endblock %}
3 {% block head %}
4  {{ super() }}
5 {% endblock %}
6 {% block body %}
7  <h1>Hello World</h1>
8  <p>I just learnt and used template inheritance and it's so cool!</p>
9 {% endblock %}

So, this is mostly it about Templates. Oh, and one more thing. The render_template function in main.py can take more arguments other than the template its going to render. These arguments can then be used as variables inside the html file. We'll look at an example of this in the next section.

Login System

Let's move on to the trickier part now. For a login system, we need a Login page and a user page which only logged in users can see. We also need a Registration page, but for that we need a database to maintain the list of registered users, making it a bit complicated. We'll see to that in the next section. In this part we'll make the user page static to avoid complications, but it definitely can be dynamic as well, with the content depending upon which user has logged in. Let's get started. Creating forms from scratch will definitely get pretty complicated. So, right now we'll use an extension called wtforms, as it has already done the boring work for us. Just a pip install flask-wtf & pip install wtforms will make it ready to use. I myself couldn't find out the full form of wt :P. Now let's create a new file, forms.py where we'll list all the forms to be used in our project. Currently We'll make just 1 form, for Logging in. Note: Even though we could write this code in our main.py file, it's always have as much seperate files as possible, so that it's easier to debug when you have thousands of lines of code. In forms.py write the following code.

1 from flask_wtf import FlaskForm
2 from wtforms import StringField, PasswordField, SubmitField, BooleanField
3 from wtforms.validators import DataRequired, Length, Email, EqualTo
4 
5 
6 class LoginForm(FlaskForm):
7     username = StringField('Username', validators=[DataRequired()])
8     password = PasswordField('Password', validators=[DataRequired()])
9     submit = SubmitField('Login')

If you ever have written forms in HTML, this is different from that in the sense that we are creating Classes representing our forms. Classes are like templates for objects, that will have some predefined properties which are derived from those classes. Try understanding the code, it's simple and self explanatory. Now let's create a login page that to log us in:

 1 {% extends "layout.html" %}
 2 
 3 {% block body %}
 4 
 5 <form method="POST", action="">
 6 	{{ form.hidden_tag() }}
 7 <fieldset>
 8 		<legend>Join Now!</legend>
 9 		<div>
10 			{{ form.username.label() }}
11 			{{ form.username()}}
12 		</div>
13 		<div>
14 			{{ form.password.label() }}
15 			{{ form.password()}}
16 		</div>
17 		<div>
18 			{{ form.submit() }}
19 		</div>
20 	</fieldset>
21 </form>
22 
23 {% endblock body %}

Here, we have borrowed HTML's form tag. Method is set to POST, which is an HTTP method. It requests that a web server accepts the data enclosed in the body of the request message. You can notice that whenever you open a new link in your server, you will see a GET request being made in your terminal. {{ }} are delimiters (credits to Jinja2) used for accessing variables that we passed in our main.py file, about which we talked towards the end of the previous section.

is again an HTML tag to make a seperation between each input of our form. It's not necessary, but makes our form a bit more legible.

Now finally edit your main.py file to look like this:

 1 from flask import Flask, render_template, url_for, redirect 
 2 from forms import LoginForm 
 3 
 4 app = Flask(__name__)
 5 app.config['SECRET_KEY'] = '5791628bb0b13ce0c676dfde280ba245'
 6 
 7 
 8 @app.route("/")
 9 def home():
10 	return render_template('home.html')
11 
12 @app.route("/about")
13 def about():
14 	return render_template('about.html')
15 
16 
17 @app.route("/login", methods=['GET', 'POST'])
18 def login():
19 	form = LoginForm()
20 	if form.validate_on_submit():
21 		if form.username.data == 'admin' and form.password.data == 'password':
22 			return redirect(url_for('about'))
23 			
24 	return render_template('login.html', form=form)
25 
26 
27 
28 if __name__ == '__main__':
29 	app.run(debug=True)

Now, a lot of new code added here, let's demystify this. In the first line we have imported more functions whose use I'll explain later. In the second line, I've imported the class LoginForm from our forms.py. Flask has made it compulsory to use a secret key to assess the session. Why? google and find out :P. We didn't require this earlier because we were not running sessions then. Since we will be using redirect function now, it will create a session, and hence the requirement of a key. Now let's come to Login decorator. Since, we are using forms, we need to explicitly specify that we want to allow this route to make get and post requests. form is an instance of our LoginForm. validate_on_submit() is a function returning True or False, depending upon if the form is valid. Since we aren't using databases currently, I've hardcoded it to check just one specific value. We have used redirect here since once the user is logged in, we have to start a session. Although it isn't really required in this section, but I've added it just so that you know about its functionality.