Python使用Flask构建简单Web应用
Flask基础概述
Flask是什么
Flask是一个用Python编写的轻量级Web应用框架。它基于Werkzeug WSGI工具包和Jinja2模板引擎。WSGI(Web Server Gateway Interface)是Python中定义Web服务器与Web应用程序之间接口的规范,Werkzeug实现了这个规范,为Flask提供了底层的请求处理等功能。Jinja2则用于动态生成HTML等模板文件,方便将数据与模板结合展示给用户。
Flask之所以轻量级,是因为它核心功能简洁,开发者可以根据项目需求灵活选择和集成各种扩展。例如,如果需要数据库支持,可以添加SQLAlchemy扩展;如果要处理用户认证,Flask - Login是不错的选择。这种灵活性使得Flask既适合快速搭建小型项目,也能在大型复杂应用中发挥重要作用。
安装Flask
在开始使用Flask构建Web应用之前,需要先安装它。假设你已经安装了Python和pip(Python的包管理工具),在命令行中执行以下命令即可安装Flask:
pip install flask
如果你使用的是虚拟环境(强烈推荐,它可以隔离不同项目的Python包环境,避免版本冲突),在创建并激活虚拟环境后执行上述安装命令。例如,使用venv
模块创建虚拟环境:
python -m venv myenv
source myenv/bin/activate # Windows下使用 myenv\Scripts\activate
pip install flask
创建第一个Flask应用
简单的Hello World示例
创建一个新的Python文件,比如app.py
,输入以下代码:
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello, World!'
if __name__ == '__main__':
app.run()
在这段代码中:
- 首先从
flask
模块导入Flask
类。 - 创建一个
Flask
类的实例app
,__name__
是Python的一个内置变量,它表示当前模块的名称。Flask用它来确定应用的根路径等信息。 - 使用
@app.route
装饰器来定义路由。这里@app.route('/')
表示当用户访问网站根路径(例如http://127.0.0.1:5000/
)时,会执行下面的hello_world
函数。 hello_world
函数返回字符串Hello, World!
,这个字符串会作为HTTP响应的内容返回给客户端。if __name__ == '__main__':
这个条件判断保证了当直接运行这个脚本时,app.run()
才会执行。app.run()
启动Flask内置的开发服务器,默认监听在127.0.0.1:5000
,即本地的5000端口。
在命令行中运行这个脚本:
python app.py
然后在浏览器中访问http://127.0.0.1:5000/
,就能看到Hello, World!
的页面。
路由与视图函数
- 路由定义:路由是Flask应用中URL与处理函数之间的映射关系。通过
@app.route
装饰器来定义路由。例如,要定义一个处理/about
路径的路由:
@app.route('/about')
def about():
return 'This is an about page'
- 动态路由:有时我们需要在URL中传递参数,Flask支持动态路由。例如,要获取用户的ID并展示相关信息,可以这样定义路由:
@app.route('/user/<int:user_id>')
def user_profile(user_id):
return f'This is the profile of user {user_id}'
在这个例子中,<int:user_id>
表示这里接受一个整数类型的参数user_id
,并且将其传递给user_profile
函数。int
是类型转换器,Flask还支持其他类型转换器,如string
(默认类型,接受字符串)、float
、path
(接受包含斜杠的字符串)等。
- HTTP方法:默认情况下,
@app.route
装饰的视图函数只接受GET
请求。如果要处理其他HTTP方法,如POST
,可以在@app.route
中指定methods
参数。例如:
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
# 处理POST请求的数据,比如获取表单数据
username = request.form.get('username')
password = request.form.get('password')
# 进行登录验证等操作
return f'Logging in user {username}'
else:
# 返回登录表单等内容
return 'This is the login form'
这里导入了request
对象(从flask
模块),它包含了客户端发送的请求信息。通过request.method
可以判断请求的HTTP方法。
模板引擎Jinja2
Jinja2模板基础
- 模板文件创建:在Flask项目中,通常在项目根目录下创建一个
templates
文件夹来存放模板文件。例如,创建一个index.html
模板文件:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>My Flask App</title>
</head>
<body>
<h1>Welcome to my Flask app</h1>
<p>{{ message }}</p>
</body>
</html>
在这个模板中,{{ message }}
是一个Jinja2变量占位符,它会在渲染模板时被实际的值替换。
- 模板渲染:在Flask应用中,使用
render_template
函数来渲染模板。修改app.py
如下:
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def index():
message = 'This is a sample message'
return render_template('index.html', message=message)
if __name__ == '__main__':
app.run()
在index
函数中,定义了一个message
变量,并将其传递给render_template
函数。render_template
函数第一个参数是模板文件名,后面可以跟着一系列的变量名和对应的值,这些值会在模板中可用。
模板继承与块
- 模板继承:模板继承允许我们创建一个基础模板,其他模板可以继承它并根据需要覆盖部分内容。创建一个基础模板
base.html
:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% block title %}Default Title{% endblock %}</title>
{% block styles %}
<style>
body {
font-family: Arial, sans - serif;
}
</style>
{% endblock %}
</head>
<body>
<header>
<h1>My Flask Site</h1>
</header>
{% block content %}
<p>This is the default content</p>
{% endblock %}
<footer>
<p>© 2023 My Company</p>
</footer>
{% block scripts %}
<script>
console.log('This is a default script');
</script>
{% endblock %}
</body>
</html>
在这个基础模板中,使用{% block %}
标签定义了几个块,如title
、styles
、content
和scripts
。
- 子模板继承:创建一个继承自
base.html
的子模板about.html
:
{% extends 'base.html' %}
{% block title %}About Us{% endblock %}
{% block content %}
<p>We are a company dedicated to providing great services.</p>
{% endblock %}
在about.html
中,使用{% extends 'base.html' %}
声明继承自base.html
,然后通过{% block %}
标签覆盖了title
和content
块的内容。在Flask应用中,渲染about.html
模板就会按照继承规则展示页面。
@app.route('/about')
def about():
return render_template('about.html')
模板中的控制结构
- 条件判断:在模板中可以使用
if - else
结构。例如,根据一个变量的值显示不同的内容:
{% if user.is_authenticated %}
<p>Welcome, {{ user.username }}</p>
{% else %}
<p>Please log in</p>
{% endif %}
- 循环:使用
for
循环可以遍历列表等可迭代对象。假设在视图函数中有一个用户列表:
@app.route('/users')
def users():
user_list = [
{'name': 'Alice', 'age': 25},
{'name': 'Bob', 'age': 30}
]
return render_template('users.html', user_list=user_list)
在users.html
模板中:
<ul>
{% for user in user_list %}
<li>Name: {{ user.name }}, Age: {{ user.age }}</li>
{% endfor %}
</ul>
这样就会将用户列表中的每个用户信息展示出来。
处理表单数据
Flask - WTF扩展
- 安装:Flask - WTF是一个用于处理表单的Flask扩展,它基于WTForms库。安装命令如下:
pip install flask - wtf
- 创建表单类:在项目中创建一个
forms.py
文件,定义表单类。例如,创建一个简单的登录表单:
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired
class LoginForm(FlaskForm):
username = StringField('Username', validators=[DataRequired()])
password = PasswordField('Password', validators=[DataRequired()])
submit = SubmitField('Login')
在这个表单类中,StringField
用于创建文本输入框,PasswordField
用于密码输入框,SubmitField
用于提交按钮。validators
参数用于添加验证规则,DataRequired
表示该字段是必填的。
在视图和模板中使用表单
- 视图函数处理:修改
app.py
来处理登录表单:
from flask import Flask, render_template, request
from forms import LoginForm
app = Flask(__name__)
app.secret_key = 'your_secret_key'
@app.route('/login', methods=['GET', 'POST'])
def login():
form = LoginForm()
if form.validate_on_submit():
username = form.username.data
password = form.password.data
# 进行登录验证逻辑
return f'Logging in user {username}'
return render_template('login.html', form=form)
if __name__ == '__main__':
app.run()
这里创建了LoginForm
的实例form
,form.validate_on_submit()
方法会在表单提交时验证数据是否符合验证规则。如果验证通过,获取表单数据进行登录验证等操作。
- 模板显示表单:在
login.html
模板中显示表单:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Login</title>
</head>
<body>
<form method="post">
{{ form.csrf_token }}
<label for="{{ form.username.id }}">{{ form.username.label }}</label>
{{ form.username }}
<br>
<label for="{{ form.password.id }}">{{ form.password.label }}</label>
{{ form.password }}
<br>
{{ form.submit }}
</form>
</body>
</html>
{{ form.csrf_token }}
用于添加跨站请求伪造(CSRF)保护令牌,这是Flask - WTF自动生成的。其他表单字段通过{{ form.field_name }}
的方式显示,标签通过{{ form.field_name.label }}
显示。
数据库集成
SQLite与SQLAlchemy
- SQLAlchemy介绍:SQLAlchemy是一个强大的数据库抽象层库,Flask - SQLAlchemy是其针对Flask的扩展。它允许我们使用Python代码与各种数据库进行交互,而不需要编写特定数据库的SQL语句。首先安装Flask - SQLAlchemy:
pip install flask - sqlalchemy
- 配置数据库:在
app.py
中配置SQLite数据库:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] ='sqlite:///myapp.db'
db = SQLAlchemy(app)
这里设置SQLALCHEMY_DATABASE_URI
为SQLite数据库文件路径myapp.db
,然后创建了SQLAlchemy
的实例db
。
定义数据库模型
- 模型类创建:在
models.py
文件中定义数据库模型类。例如,创建一个用户模型:
from app import db
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
def __repr__(self):
return f'<User {self.username}>'
在这个模型类中,id
是主键,username
和email
是普通字段,unique=True
表示字段值必须唯一,nullable=False
表示字段不能为空。__repr__
方法用于定义对象的字符串表示形式,方便调试等操作。
数据库操作
- 添加数据:在视图函数中添加用户数据:
from models import User
@app.route('/add_user', methods=['POST'])
def add_user():
username = request.form.get('username')
email = request.form.get('email')
new_user = User(username=username, email=email)
db.session.add(new_user)
db.session.commit()
return 'User added successfully'
这里从表单获取用户名和邮箱,创建User
对象,使用db.session.add
将对象添加到会话中,然后通过db.session.commit
提交会话,将数据保存到数据库。
- 查询数据:查询所有用户:
@app.route('/users')
def get_all_users():
users = User.query.all()
user_list = []
for user in users:
user_list.append(f'Username: {user.username}, Email: {user.email}')
return '<br>'.join(user_list)
User.query.all()
查询User
表中的所有记录,并将结果展示出来。
- 更新数据:更新用户的邮箱:
@app.route('/update_user/<int:user_id>', methods=['POST'])
def update_user(user_id):
user = User.query.get(user_id)
if user:
new_email = request.form.get('email')
user.email = new_email
db.session.commit()
return 'User email updated successfully'
return 'User not found'
通过User.query.get(user_id)
获取指定ID的用户,然后更新其邮箱并提交会话。
- 删除数据:删除用户:
@app.route('/delete_user/<int:user_id>', methods=['POST'])
def delete_user(user_id):
user = User.query.get(user_id)
if user:
db.session.delete(user)
db.session.commit()
return 'User deleted successfully'
return 'User not found'
获取用户后使用db.session.delete
删除对象并提交会话。
部署Flask应用
生产环境服务器选择
- Gunicorn:Gunicorn是一个广泛使用的Python WSGI HTTP服务器。它可以与Flask应用一起部署,提供更好的性能和稳定性。安装命令:
pip install gunicorn
- uWSGI:uWSGI也是一个流行的应用服务器,支持多种协议和功能。安装命令:
pip install uwsgi
使用Gunicorn部署
- 启动命令:假设你的Flask应用入口文件是
app.py
,应用实例是app
,在项目目录下执行以下命令启动Gunicorn:
gunicorn -w 4 -b 127.0.0.1:8000 app:app
这里-w 4
表示使用4个工作进程,-b 127.0.0.1:8000
指定绑定的IP地址和端口,app:app
表示应用入口文件app.py
中的app
实例。
- 配置文件:可以创建一个配置文件(例如
gunicorn.conf.py
)来更方便地管理启动参数:
workers = 4
bind = '127.0.0.1:8000'
然后使用以下命令启动:
gunicorn -c gunicorn.conf.py app:app
与Nginx配合部署
- Nginx安装与配置:安装Nginx后,在Nginx配置目录(通常是
/etc/nginx/sites - available
)下创建一个新的配置文件,例如myapp.conf
:
server {
listen 80;
server_name your_domain.com;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X - Real - IP $remote_addr;
proxy_set_header X - Forwarded - For $proxy_add_x_forwarded_for;
proxy_set_header X - Forwarded - Proto $scheme;
}
}
这里proxy_pass
指定将请求转发到Gunicorn运行的地址(127.0.0.1:8000
)。然后创建符号链接将配置文件链接到/etc/nginx/sites - enabled
目录:
ln -s /etc/nginx/sites - available/myapp.conf /etc/nginx/sites - enabled/
重启Nginx服务使配置生效:
sudo systemctl restart nginx
- HTTPS配置:为了安全,可以为网站配置HTTPS。可以使用Let's Encrypt获取免费的SSL证书。安装Certbot:
sudo apt install certbot python3 - certbot - nginx
然后使用Certbot为Nginx配置SSL:
sudo certbot --nginx -d your_domain.com
按照提示操作,Certbot会自动为你的网站配置HTTPS。
通过以上步骤,你可以逐步从创建一个简单的Flask应用,到集成数据库、处理表单,最后部署到生产环境,构建一个完整可用的Web应用。在实际开发中,还需要考虑更多的安全、性能优化等方面的问题,但这些基础知识为进一步深入学习和开发打下了坚实的基础。