Flask教程:从入门到精通 – wiki基地

“`markdown

Flask教程:从入门到精通

Flask是一个轻量级的Python Web框架,以其简洁、灵活和易于扩展的特性而广受欢迎。与Django等全功能框架不同,Flask被称为“微框架”,因为它不强制要求特定的工具或库,而是让开发者自由选择最适合项目的组件。本教程将引导你从零开始,逐步掌握Flask的核心概念和高级用法,最终能够构建出功能完善的Web应用程序。

1. 简介:为什么选择Flask?

什么是Flask?

Flask是一个基于Werkzeug WSGI工具集和Jinja2模板引擎的Python Web开发框架。它被称为微框架,但其“微”并非指功能弱小,而是指其核心库保持精简,只提供Web应用开发的基本功能,如路由、请求处理和模板渲染。

Flask的优势

  • 轻量级和简洁:核心代码库小,学习曲线平缓,非常适合初学者。
  • 灵活性:不强制使用任何ORM、模板引擎或表单验证库,开发者可以根据需求自由选择。
  • 易于扩展:拥有丰富的第三方扩展,可以轻松添加数据库集成、用户认证、RESTful API等功能。
  • 良好的文档和社区支持:拥有详尽的官方文档和活跃的社区,遇到问题可以迅速找到解决方案。

2. 环境搭建

在开始之前,我们需要搭建一个干净的Python开发环境。推荐使用virtualenv来管理项目依赖。

安装virtualenv

bash
pip install virtualenv

创建和激活虚拟环境

在项目目录下创建一个虚拟环境:
bash
virtualenv venv

激活虚拟环境:
* Windows: venv\Scripts\activate
* macOS/Linux: source venv/bin/activate

安装Flask

激活虚拟环境后,安装Flask:
bash
pip install Flask

3. 你的第一个Flask应用 (Hello World)

创建一个名为 app.py 的文件,并写入以下代码:

“`python
from flask import Flask

app = Flask(name)

@app.route(‘/’)
def hello_world():
return ‘Hello, World!’

if name == ‘main‘:
app.run(debug=True)
“`

代码解析

  • from flask import Flask: 导入Flask类。
  • app = Flask(__name__): 创建一个Flask应用实例。__name__ 是当前模块的名称,Flask用它来定位资源。
  • @app.route('/'): 这是一个装饰器,将 hello_world 函数绑定到URL根路径 /。当用户访问 / 时,hello_world 函数会被调用。
  • def hello_world():: 定义视图函数,它返回一个字符串作为HTTP响应。
  • if __name__ == '__main__':: 确保只有在直接运行此文件时才启动开发服务器。
  • app.run(debug=True): 启动Flask的内置开发服务器。debug=True 开启调试模式,当代码更改时服务器会自动重启,并提供详细的错误信息。

运行应用

在命令行中,确保虚拟环境已激活,然后运行:
bash
python app.py

打开浏览器访问 http://127.0.0.1:5000/,你将看到 “Hello, World!”。

路由与变量规则

Flask支持在URL中定义变量:

“`python
@app.route(‘/user/‘)
def show_user_profile(username):
# show the user profile for that user
return f’User {username}’

@app.route(‘/post/‘)
def show_post(post_id):
# show the post with the given id, the id is an integer
return f’Post {post_id}’
``int:是一个转换器,确保post_id是一个整数。其他内置转换器包括string(默认),float,path,uuid`。

4. 使用Jinja2模板

直接在视图函数中返回HTML字符串很快就会变得难以维护。Flask推荐使用Jinja2模板引擎来渲染HTML。

创建模板文件夹

在项目根目录下创建一个名为 templates 的文件夹。

示例模板文件 (templates/index.html)

“`html






{{ title }}

Welcome, {{ name }}!

This is a Flask application.


“`

更新 app.py 以渲染模板

“`python
from flask import Flask, render_template

app = Flask(name)

@app.route(‘/’)
def index():
return render_template(‘index.html’, title=’Home Page’, name=’Guest’)

@app.route(‘/hello/‘)
def hello(name):
return render_template(‘index.html’, title=f’Hello {name}’, name=name)

if name == ‘main‘:
app.run(debug=True)
“`

模板继承

对于大型项目,你可以使用模板继承来避免重复代码。创建一个 templates/base.html

“`html






{% block title %}My Flask App{% endblock %}


{% block content %}{% endblock %}

© 2026 My Flask App


``
然后,子模板可以继承并覆盖
base.html` 中的块:

“`html

{% extends “base.html” %}

{% block title %}About Us{% endblock %}

{% block content %}

About Our Application

We are building something amazing with Flask!

{% endblock %}
“`
对应的视图函数:

python
@app.route('/about')
def about():
return render_template('about.html')

5. 处理表单

Web应用经常需要处理用户提交的数据,例如注册表单、登录表单等。Flask提供了 request 对象来访问这些数据。

“`python
from flask import Flask, render_template, request, flash, redirect, url_for

app = Flask(name)
app.secret_key = ‘supersecretkey’ # 用于flash消息和session,生产环境请使用复杂密钥

@app.route(‘/login’, methods=[‘GET’, ‘POST’])
def login():
if request.method == ‘POST’:
username = request.form[‘username’]
password = request.form[‘password’]
if username == ‘admin’ and password == ‘password’: # 简单的认证
flash(‘Login successful!’, ‘success’)
return redirect(url_for(‘index’))
else:
flash(‘Invalid credentials. Please try again.’, ‘error’)
return render_template(‘login.html’)

templates/login.html

“`html
{% extends “base.html” %}

{% block title %}Login{% endblock %}

{% block content %}

Login

{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}

    {% for category, message in messages %}

  • {{ message }}
  • {% endfor %}

{% endif %}
{% endwith %}





{% endblock %}
“`

request 对象

  • request.method: 请求方法(GET、POST等)。
  • request.args: URL查询参数(GET请求)。
  • request.form: 表单提交数据(POST请求)。
  • request.json: JSON格式的请求体数据。

flash 消息

flash 函数用于在请求之间传递一次性消息,常用于显示操作结果。需要设置 app.secret_key

6. 数据库集成 (使用SQLAlchemy)

大多数Web应用都需要持久化数据。SQLAlchemy是Python中最流行的ORM(对象关系映射)库,而Flask-SQLAlchemy是其Flask扩展,使其集成更加简单。

安装Flask-SQLAlchemy

bash
pip install Flask-SQLAlchemy

配置数据库

app.py 中配置SQLite数据库:

“`python
from flask import Flask, render_template, request, flash, redirect, url_for
from flask_sqlalchemy import SQLAlchemy

app = Flask(name)
app.config[‘SECRET_KEY’] = ‘your_secret_key_here’
app.config[‘SQLALCHEMY_DATABASE_URI’] = ‘sqlite:///site.db’ # 使用SQLite数据库
app.config[‘SQLALCHEMY_TRACK_MODIFICATIONS’] = False # 禁用事件追踪

db = SQLAlchemy(app)

定义模型

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}>'

在应用上下文内创建数据库表

with app.app_context():
db.create_all()

… 其他路由和应用代码 …

@app.route(‘/register’, methods=[‘GET’, ‘POST’])
def register():
if request.method == ‘POST’:
username = request.form[‘username’]
email = request.form[’email’]

    # 检查用户是否已存在
    existing_user = User.query.filter_by(username=username).first()
    if existing_user:
        flash('Username already exists.', 'error')
        return redirect(url_for('register'))

    new_user = User(username=username, email=email)
    db.session.add(new_user)
    db.session.commit()
    flash('Registration successful! You can now log in.', 'success')
    return redirect(url_for('login'))
return render_template('register.html')

“`

数据库操作

  • 创建表: with app.app_context(): db.create_all()
  • 添加数据: db.session.add(new_user); db.session.commit()
  • 查询数据:
    • User.query.all(): 获取所有用户。
    • User.query.get(1): 通过ID获取用户。
    • User.query.filter_by(username='admin').first(): 按条件查询第一个。
    • User.query.filter(User.username.startswith('A')).all(): 使用SQLAlchemy表达式查询。
  • 更新数据:
  • 删除数据:
    • user = User.query.get(1)
    • db.session.delete(user)
    • db.session.commit()

7. 蓝图 (Blueprints)

随着应用规模的增长,将所有路由和视图函数放在一个文件中会变得难以管理。蓝图允许你将应用组织成可重用的模块。

创建蓝图

在项目根目录下创建一个 auth 文件夹,并在其中创建 auth.py

“`python

auth/auth.py

from flask import Blueprint, render_template, request, flash, redirect, url_for

auth_bp = Blueprint(‘auth’, name, template_folder=’templates’) # 定义蓝图,并指定模板文件夹

@auth_bp.route(‘/register’, methods=[‘GET’, ‘POST’])
def register():
# … 注册逻辑 (如上面的数据库示例) …
if request.method == ‘POST’:
# 这里应该有实际的注册逻辑
flash(‘Registration logic goes here!’, ‘info’)
return redirect(url_for(‘auth.login’)) # 注意这里是 ‘auth.login’
return render_template(‘register.html’)

@auth_bp.route(‘/login’, methods=[‘GET’, ‘POST’])
def login():
# … 登录逻辑 (如上面的表单示例) …
if request.method == ‘POST’:
# 这里应该有实际的登录逻辑
flash(‘Login logic goes here!’, ‘info’)
return redirect(url_for(‘index’))
return render_template(‘login.html’)
“`

auth 文件夹内创建 templates 文件夹,并将 login.htmlregister.html 放入其中。

注册蓝图

app.py 中注册蓝图:

“`python

app.py

from flask import Flask, render_template
from flask_sqlalchemy import SQLAlchemy
from auth.auth import auth_bp # 导入蓝图

app = Flask(name)
app.config[‘SECRET_KEY’] = ‘your_secret_key_here’
app.config[‘SQLALCHEMY_DATABASE_URI’] = ‘sqlite:///site.db’
app.config[‘SQLALCHEMY_TRACK_MODIFICATIONS’] = False

db = SQLAlchemy(app)

定义模型 (User model 依然放在 app.py 或单独的 models.py 中)

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}>'

with app.app_context():
db.create_all()

app.register_blueprint(auth_bp, url_prefix=’/auth’) # 注册蓝图,并设置URL前缀

@app.route(‘/’)
def index():
return render_template(‘index.html’)

if name == ‘main‘:
app.run(debug=True)
``
现在,
registerlogin路由将分别通过/auth/register/auth/login` 访问。

8. 静态文件

静态文件(CSS、JavaScript、图片)通常放在项目根目录下的 static 文件夹中。

创建静态文件

在项目根目录下创建 static 文件夹,并在其中创建 static/style.css

css
/* static/style.css */
body {
font-family: sans-serif;
margin: 20px;
background-color: #f4f4f4;
color: #333;
}
h1 {
color: #0056b3;
}
.flashes {
list-style: none;
padding: 0;
}
.flashes li.success {
color: green;
}
.flashes li.error {
color: red;
}

在模板中引用静态文件

使用 url_for('static', filename='path/to/file') 来生成静态文件的URL:

“`html







{% block title %}My Flask App{% endblock %}



“`

9. 错误处理

Flask允许你定义自定义的错误页面,例如404 Not Found和500 Internal Server Error。

“`python

app.py

from flask import abort

… 省略其他代码 …

@app.errorhandler(404)
def page_not_found(error):
return render_template(‘404.html’), 404

@app.errorhandler(500)
def internal_server_error(error):
return render_template(‘500.html’), 500

@app.route(‘/secret’)
def secret_page():
# 模拟一个404错误
abort(404)
# 或者模拟一个500错误
# raise Exception(“Something went wrong!”)
return “This will not be shown.”
“`

创建 templates/404.htmltemplates/500.html 文件。

10. 会话管理 (Session)

Flask的会话(Session)允许你在不同请求之间存储用户特定的数据。会话数据存储在客户端的Cookie中,并使用 SECRET_KEY 进行签名加密,以防止篡改。

“`python
from flask import session

… 省略其他代码 …

@app.route(‘/set_session/‘)
def set_session(name):
session[‘username’] = name
return f’Session username set to {name}’

@app.route(‘/get_session’)
def get_session():
username = session.get(‘username’, ‘Not set’)
return f’Session username is {username}’

@app.route(‘/clear_session’)
def clear_session():
session.pop(‘username’, None)
return ‘Session username cleared’
``
确保你的
app.secret_key` 足够复杂且保密,因为它是会话安全的基石。

11. 用户认证与授权 (Flask-Login)

在实际应用中,用户认证和授权是必不可少的。Flask-Login 是一个流行的扩展,用于管理用户会话。

安装 Flask-Login

bash
pip install Flask-Login

集成 Flask-Login

你需要定义一个 User 模型,并实现 Flask-Login 要求的一些方法。

“`python
from flask_login import LoginManager, UserMixin, login_user, logout_user, login_required, current_user
from werkzeug.security import generate_password_hash, check_password_hash

… 省略其他代码 …

login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = ‘auth.login’ # 未登录用户访问login_required页面时重定向到此路由

修改User模型以继承UserMixin并添加密码哈希

class User(UserMixin, 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)
password_hash = db.Column(db.String(128))

def set_password(self, password):
    self.password_hash = generate_password_hash(password)

def check_password(self, password):
    return check_password_hash(self.password_hash, password)

def __repr__(self):
    return f'<User {self.username}>'

@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))

在auth蓝图中添加登录、注册、登出逻辑

… (略去部分代码,需自行实现) …

auth/auth.py

@auth_bp.route(‘/register’, methods=[‘GET’, ‘POST’])
def register():
if request.method == ‘POST’:
username = request.form[‘username’]
email = request.form[’email’]
password = request.form[‘password’] # 从表单获取密码

    existing_user = User.query.filter_by(username=username).first()
    if existing_user:
        flash('Username already exists.', 'error')
        return redirect(url_for('auth.register'))

    new_user = User(username=username, email=email)
    new_user.set_password(password) # 设置哈希密码
    db.session.add(new_user)
    db.session.commit()
    flash('Registration successful! You can now log in.', 'success')
    return redirect(url_for('auth.login'))
return render_template('register.html')

@auth_bp.route(‘/login’, methods=[‘GET’, ‘POST’])
def login():
if current_user.is_authenticated:
return redirect(url_for(‘index’)) # 如果已登录,重定向到首页

if request.method == 'POST':
    username = request.form['username']
    password = request.form['password']
    user = User.query.filter_by(username=username).first()
    if user and user.check_password(password):
        login_user(user) # 登录用户
        flash('Login successful!', 'success')
        next_page = request.args.get('next') # 重定向到之前尝试访问的页面
        return redirect(next_page or url_for('index'))
    else:
        flash('Invalid username or password.', 'error')
return render_template('login.html')

@auth_bp.route(‘/logout’)
@login_required # 需要登录才能访问
def logout():
logout_user() # 登出用户
flash(‘You have been logged out.’, ‘info’)
return redirect(url_for(‘index’))

app.py 中保护的路由

@app.route(‘/dashboard’)
@login_required # 只有登录用户才能访问
def dashboard():
return f’Hello, {current_user.username}! Welcome to your dashboard.’
“`

12. 部署

当你的Flask应用开发完成后,你需要将其部署到生产服务器上。Flask的内置开发服务器不适用于生产环境。常见的部署方式是使用WSGI服务器(如Gunicorn或uWSGI)结合反向代理服务器(如Nginx)。

Gunicorn + Nginx (示例)

  1. 安装Gunicorn: pip install gunicorn
  2. 运行Gunicorn:
    bash
    gunicorn -w 4 app:app # -w 指定worker数量,app:app 指 app.py 文件中的 Flask 实例

    这将启动一个Gunicorn服务器,监听在默认端口 http://127.0.0.1:8000
  3. 配置Nginx:
    Nginx作为反向代理,将外部请求转发给Gunicorn,并处理静态文件。
    创建一个Nginx配置文件(例如 /etc/nginx/sites-available/your_app):
    “`nginx
    server {
    listen 80;
    server_name your_domain.com www.your_domain.com;

    location /static {
        alias /path/to/your/project/static; # 你的静态文件路径
    }
    
    location / {
        proxy_pass http://127.0.0.1:8000; # Gunicorn监听的地址和端口
        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;
    }
    

    }
    ``
    然后创建软链接到
    sites-enabled` 并重启Nginx。
    4. 使用Supervisor或Systemd管理进程: 确保Gunicorn进程在服务器重启后自动启动并持续运行。

13. 单元测试

为了确保应用的健壮性和可维护性,编写测试至关重要。Flask提供了一个测试客户端,可以模拟请求。

“`python

test_app.py

import unittest
from app import app # 导入你的Flask应用

class FlaskTestCase(unittest.TestCase):

def setUp(self):
    self.app = app.test_client()
    self.app.testing = True

def test_home_page(self):
    response = self.app.get('/')
    self.assertEqual(response.status_code, 200)
    self.assertIn(b'Hello, World!', response.data) # 注意是字节串

def test_login_page_get(self):
    response = self.app.get('/auth/login')
    self.assertEqual(response.status_code, 200)
    self.assertIn(b'<h1>Login</h1>', response.data)

def test_login_valid_credentials(self):
    response = self.app.post('/auth/login', data=dict(
        username='admin',
        password='password'
    ), follow_redirects=True)
    self.assertEqual(response.status_code, 200)
    self.assertIn(b'Login successful!', response.data)

def test_login_invalid_credentials(self):
    response = self.app.post('/auth/login', data=dict(
        username='admin',
        password='wrongpassword'
    ), follow_redirects=True)
    self.assertEqual(response.status_code, 200)
    self.assertIn(b'Invalid credentials. Please try again.', response.data)

if name == ‘main‘:
unittest.main()
``
运行测试:
python -m unittest test_app.py`

14. 结论与进阶

通过本教程,你已经掌握了Flask从基础到高级的各个方面,包括:

  • Flask应用的基本结构和运行方式
  • 路由、视图函数和URL变量
  • Jinja2模板引擎的使用和模板继承
  • 处理HTTP请求和表单数据
  • 集成SQLAlchemy进行数据库操作
  • 使用蓝图组织大型应用
  • 静态文件的管理
  • 错误处理机制
  • 会话管理
  • 用户认证与授权(Flask-Login)
  • 生产环境部署概述
  • 单元测试

这只是Flask世界的开始。你可以进一步探索以下主题:

  • RESTful API开发:使用Flask-RESTful或直接构建。
  • 表单验证:使用WTForms和Flask-WTF。
  • 异步任务:Celery与Redis/RabbitMQ。
  • WebSockets:Flask-SocketIO。
  • 缓存:Flask-Caching。
  • 国际化与本地化:Flask-Babel。
  • 更复杂的数据库集成:PostgreSQL, MySQL。
  • 前端框架集成:与React、Vue、Angular等结合。

希望这篇教程能为你打开Flask开发的大门,祝你编码愉快!
“`

滚动至顶部