Appearance
Using Web Frameworks
After understanding the WSGI framework, we realized that a web app essentially involves writing a WSGI handler function to respond to each HTTP request.
However, handling HTTP requests is not the main issue; the challenge is managing hundreds of different URLs. Each URL can correspond to GET and POST requests, as well as other types like PUT and DELETE, though we usually focus on the most common GET and POST requests.
A basic approach is to extract the HTTP request information from the environ
variable and handle it case by case:
python
def application(environ, start_response):
method = environ['REQUEST_METHOD']
path = environ['PATH_INFO']
if method == 'GET' and path == '/':
return handle_home(environ, start_response)
if method == 'POST' and path == '/signin':
return handle_signin(environ, start_response)
...
This code structure quickly becomes unmaintainable.
The reason why the code becomes unmanageable is that, although the WSGI interface is more advanced than the raw HTTP interface, it is still relatively low-level compared to the web app's processing logic. We need a higher level of abstraction on top of WSGI that allows us to focus on handling a URL with a function, while the mapping from URL to function is handled by a web framework.
Since developing a web framework in Python is fairly easy, there are hundreds of open-source Python web frameworks available. Instead of discussing the pros and cons of each, let's start by using a popular one—Flask.
Using Flask to write a web app is simpler than using the WSGI interface (which is a given; otherwise, there would be no point in using a framework). First, let's install Flask using pip:
bash
$ pip install flask
Then, create an app.py
file to handle three URLs:
- GET /: The homepage, returning "Home".
- GET /signin: The sign-in page, displaying a login form.
- POST /signin: Processes the login form and displays the login result.
Note that the same URL /signin
corresponds to both GET and POST requests, mapped to two different handler functions.
Flask uses Python decorators internally to automatically associate URLs with functions, so our code looks like this:
python
from flask import Flask
from flask import request
app = Flask(__name__)
@app.route('/', methods=['GET', 'POST'])
def home():
return '<h1>Home</h1>'
@app.route('/signin', methods=['GET'])
def signin_form():
return '''<form action="/signin" method="post">
<p><input name="username"></p>
<p><input name="password" type="password"></p>
<p><button type="submit">Sign In</button></p>
</form>'''
@app.route('/signin', methods=['POST'])
def signin():
# Read form data from the request object:
if request.form['username'] == 'admin' and request.form['password'] == 'password':
return '<h3>Hello, admin!</h3>'
return '<h3>Bad username or password.</h3>'
if __name__ == '__main__':
app.run()
Running the app.py
script starts Flask's built-in server, which listens on port 5000:
bash
$ python app.py
* Running on http://127.0.0.1:5000/
Open a browser and navigate to the homepage at http://localhost:5000/
:
The homepage displays correctly!
Then, enter http://localhost:5000/signin
in the browser's address bar to display the login form:
Enter the preset username admin
and password password
to log in successfully:
If you enter an incorrect username or password, login will fail:
In a real web app, after obtaining the username and password, you should query the database to compare and determine whether the user can successfully log in.
Besides Flask, other common Python web frameworks include:
- Django: A full-featured web framework.
- web.py: A lightweight web framework.
- Bottle: Similar to Flask.
- Tornado: An open-source asynchronous web framework by Facebook.
Developing a Python web framework is not particularly challenging, and we will cover web framework development later.
Summary
With a web framework, we shift our focus from WSGI handler functions to URL + corresponding handler functions when writing web applications. This makes developing web apps simpler.
When writing URL handler functions, besides configuring URLs, it is crucial to retrieve user data from HTTP requests. Web frameworks provide their own APIs to accomplish these tasks. In Flask, you can use request.form['name']
to get the content of a form.