Python Flask 框架使用指南 #

一、Flask简介 #

Flask是一个轻量级的Python Web框架,以其简洁、灵活和易用性而闻名。它基于Werkzeug WSGI工具包和Jinja2模板引擎,被广泛用于构建Web应用和API。

1.1 Flask的特点 #

  • 轻量级:核心功能简洁,扩展丰富
  • 灵活性:没有强制性的项目结构,可根据需求自由组织
  • 易用性:API设计简洁明了,学习曲线平缓
  • 扩展性:通过丰富的扩展生态系统,可以轻松添加各种功能
  • 适用于小型到中型项目:特别适合快速开发和原型设计

二、Flask安装与环境配置 #

2.1 安装Flask #

bash
# 使用pip安装Flask
pip install flask

# 安装特定版本
pip install flask==3.0.3

# 安装开发版本
pip install flask --pre

2.2 创建虚拟环境 #

bash
# 创建虚拟环境
python -m venv myflaskenv

# 激活虚拟环境
# Windows
myflaskenv\Scripts\activate
# macOS/Linux
source myflaskenv/bin/activate

# 退出虚拟环境
deactivate

2.3 项目结构推荐 #

text
myflaskapp/
├── app/
│   ├── __init__.py
│   ├── routes.py
│   ├── models.py
│   ├── forms.py
│   ├── templates/
│   └── static/
├── requirements.txt
└── run.py

三、Flask基础入门 #

3.1 第一个Flask应用 #

创建hello.py文件:

python
from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello, Flask!'

if __name__ == '__main__':
    app.run(debug=True)

运行应用:

bash
python hello.py

访问http://localhost:5000查看结果。

3.2 路由与视图函数 #

python
# 基本路由
@app.route('/')
def index():
    return '首页'

# 带参数的路由
@app.route('/user/<username>')
def show_user_profile(username):
    return f'用户 {username}'

# 带类型的参数
@app.route('/post/<int:post_id>')
def show_post(post_id):
    return f'帖子 {post_id}'

# 多个HTTP方法
from flask import request

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        return '登录处理'
    else:
        return '登录表单'

3.3 URL构建 #

python
from flask import url_for

# 构建URL
@app.route('/')
def index():
    return url_for('login')  # 返回 /login

@app.route('/login')
def login():
    return 'login'

@app.route('/user/<username>')
def profile(username):
    return f'{username}\s profile'

with app.test_request_context():
    print(url_for('index'))  # /
    print(url_for('login'))  # /login
    print(url_for('profile', username='张三'))  # /user/张三
    print(url_for('profile', username='张三', next='/'))  # /user/张三?next=/

四、模板引擎与视图渲染 #

4.1 模板目录结构 #

text
app/
└── templates/
    ├── base.html
    ├── index.html
    └── user/
        └── profile.html

4.2 基本模板使用 #

base.html(基础模板):

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{% block title %}Flask应用{% endblock %}</title>
</head>
<body>
    <nav>
        <a href="{{ url_for('index') }}">首页</a>
        <a href="{{ url_for('about') }}">关于</a>
    </nav>
    
    {% block content %}{% endblock %}
    
    <footer>
        <p>© 2026 Flask应用</p>
    </footer>
</body>
</html>

index.html(继承基础模板):

html
{% extends "base.html" %}

{% block title %}首页 - Flask应用{% endblock %}

{% block content %}
    <h1>欢迎来到Flask应用</h1>
    <p>这是首页内容</p>
    
    <!-- 循环示例 -->
    <h2>用户列表</h2>
    <ul>
    {% for user in users %}
        <li><a href="{{ url_for('profile', username=user.username) }}">{{ user.username }}</a></li>
    {% endfor %}
    </ul>
    
    <!-- 条件示例 -->
    {% if current_user.is_authenticated %}
        <p>欢迎回来,{{ current_user.username }}!</p>
    {% else %}
        <p>请 <a href="{{ url_for('login') }}">登录</a></p>
    {% endif %}
{% endblock %}

4.3 渲染模板 #

python
from flask import render_template

@app.route('/')
def index():
    users = [{'username': '张三'}, {'username': '李四'}]
    return render_template('index.html', users=users)

@app.route('/about')
def about():
    return render_template('about.html', title='关于我们')

4.4 模板过滤器 #

python
# 自定义过滤器
@app.template_filter('capitalize')
def capitalize_filter(s):
    if not isinstance(s, str):
        return s
    return s.capitalize()

# 在模板中使用
# {{ name|capitalize }}

五、表单处理 #

5.1 使用Flask-WTF扩展 #

安装扩展:

bash
pip install flask-wtf

5.2 创建表单类 #

python
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, BooleanField, SubmitField
from wtforms.validators import DataRequired, Length, Email, EqualTo

class RegistrationForm(FlaskForm):
    username = StringField('用户名', validators=[DataRequired(), Length(min=2, max=20)])
    email = StringField('邮箱', validators=[DataRequired(), Email()])
    password = PasswordField('密码', validators=[DataRequired()])
    confirm_password = PasswordField('确认密码', validators=[DataRequired(), EqualTo('password')])
    submit = SubmitField('注册')

class LoginForm(FlaskForm):
    email = StringField('邮箱', validators=[DataRequired(), Email()])
    password = PasswordField('密码', validators=[DataRequired()])
    remember = BooleanField('记住我')
    submit = SubmitField('登录')

5.3 处理表单提交 #

python
from flask import flash, redirect, url_for

@app.route('/register', methods=['GET', 'POST'])
def register():
    form = RegistrationForm()
    if form.validate_on_submit():
        # 处理注册逻辑
        flash(f'账户创建成功,欢迎 {form.username.data}!', 'success')
        return redirect(url_for('login'))
    return render_template('register.html', title='注册', form=form)

@app.route('/login', methods=['GET', 'POST'])
def login():
    form = LoginForm()
    if form.validate_on_submit():
        # 处理登录逻辑
        if form.email.data == 'admin@example.com' and form.password.data == 'password':
            flash('登录成功!', 'success')
            return redirect(url_for('index'))
        else:
            flash('登录失败,请检查邮箱和密码', 'danger')
    return render_template('login.html', title='登录', form=form)

5.4 模板中的表单渲染 #

html
{% extends "base.html" %}

{% block content %}
    <div class="content-section">
        <form method="POST" action="">
            {{ form.hidden_tag() }}
            <fieldset class="form-group">
                <legend class="border-bottom mb-4">注册账户</legend>
                <div class="form-group">
                    {{ form.username.label(class="form-control-label") }}
                    
                    {% if form.username.errors %}
                        {{ form.username(class="form-control form-control-lg is-invalid") }}
                        <div class="invalid-feedback">
                            {% for error in form.username.errors %}
                                <span>{{ error }}</span>
                            {% endfor %}
                        </div>
                    {% else %}
                        {{ form.username(class="form-control form-control-lg") }}
                    {% endif %}
                </div>
                <div class="form-group">
                    {{ form.email.label(class="form-control-label") }}
                    {% if form.email.errors %}
                        {{ form.email(class="form-control form-control-lg is-invalid") }}
                        <div class="invalid-feedback">
                            {% for error in form.email.errors %}
                                <span>{{ error }}</span>
                            {% endfor %}
                        </div>
                    {% else %}
                        {{ form.email(class="form-control form-control-lg") }}
                    {% endif %}
                </div>
                <div class="form-group">
                    {{ form.password.label(class="form-control-label") }}
                    {% if form.password.errors %}
                        {{ form.password(class="form-control form-control-lg is-invalid") }}
                        <div class="invalid-feedback">
                            {% for error in form.password.errors %}
                                <span>{{ error }}</span>
                            {% endfor %}
                        </div>
                    {% else %}
                        {{ form.password(class="form-control form-control-lg") }}
                    {% endif %}
                </div>
                <div class="form-group">
                    {{ form.confirm_password.label(class="form-control-label") }}
                    {% if form.confirm_password.errors %}
                        {{ form.confirm_password(class="form-control form-control-lg is-invalid") }}
                        <div class="invalid-feedback">
                            {% for error in form.confirm_password.errors %}
                                <span>{{ error }}</span>
                            {% endfor %}
                        </div>
                    {% else %}
                        {{ form.confirm_password(class="form-control form-control-lg") }}
                    {% endif %}
                </div>
            </fieldset>
            <div class="form-group">
                {{ form.submit(class="btn btn-outline-info") }}
            </div>
        </form>
    </div>
    <div class="border-top pt-3">
        <small class="text-muted">
            已有账户? <a class="ml-2" href="{{ url_for('login') }}">登录</a>
        </small>
    </div>
{% endblock content %}

六、数据库集成 #

6.1 使用Flask-SQLAlchemy扩展 #

安装扩展:

bash
pip install flask-sqlalchemy

6.2 配置数据库 #

python
from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)

# SQLite配置
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///site.db'

# MySQL配置
# app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://user:password@localhost/db_name'

# PostgreSQL配置
# app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://user:password@localhost/db_name'

app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

db = SQLAlchemy(app)

6.3 定义模型 #

python
from datetime import datetime

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(20), unique=True, nullable=False)
    email = db.Column(db.String(120), unique=True, nullable=False)
    image_file = db.Column(db.String(20), nullable=False, default='default.jpg')
    password = db.Column(db.String(60), nullable=False)
    posts = db.relationship('Post', backref='author', lazy=True)
    
    def __repr__(self):
        return f"User('{self.username}', '{self.email}', '{self.image_file}')"

class Post(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(100), nullable=False)
    date_posted = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
    content = db.Column(db.Text, nullable=False)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    
    def __repr__(self):
        return f"Post('{self.title}', '{self.date_posted}')"

6.4 创建数据库 #

python
# 在Python终端中执行
with app.app_context():
    db.create_all()

6.5 数据库操作 #

python
# 添加数据
with app.app_context():
    user_1 = User(username='admin', email='admin@example.com', password='password')
    db.session.add(user_1)
    db.session.commit()

# 查询数据
users = User.query.all()
user = User.query.filter_by(username='admin').first()
user = User.query.get(1)

# 更新数据
user.username = 'new_username'
db.session.commit()

# 删除数据
db.session.delete(user)
db.session.commit()

七、认证与授权 #

7.1 使用Flask-Login扩展 #

安装扩展:

bash
pip install flask-login

7.2 配置Flask-Login #

python
from flask_login import LoginManager

login_manager = LoginManager(app)
login_manager.login_view = 'login'  # 登录页面的路由
login_manager.login_message_category = 'info'  # 登录消息的Bootstrap类别

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

7.3 扩展User模型 #

python
from flask_login import UserMixin

class User(db.Model, UserMixin):
    # 现有字段...
    pass

7.4 登录与登出 #

python
from flask_login import login_user, current_user, logout_user, login_required

@app.route('/login', methods=['GET', 'POST'])
def login():
    if current_user.is_authenticated:
        return redirect(url_for('index'))
    form = LoginForm()
    if form.validate_on_submit():
        user = User.query.filter_by(email=form.email.data).first()
        if user and check_password_hash(user.password, form.password.data):
            login_user(user, remember=form.remember.data)
            next_page = request.args.get('next')
            return redirect(next_page) if next_page else redirect(url_for('index'))
        else:
            flash('登录失败,请检查邮箱和密码', 'danger')
    return render_template('login.html', title='登录', form=form)

@app.route('/logout')
def logout():
    logout_user()
    return redirect(url_for('index'))

# 保护路由
@app.route('/account')
@login_required
def account():
    return render_template('account.html', title='账户信息')

7.5 密码哈希 #

bash
pip install werkzeug
python
from werkzeug.security import generate_password_hash, check_password_hash

# 创建密码哈希
password_hash = generate_password_hash('password', method='pbkdf2:sha256')

# 验证密码
is_valid = check_password_hash(password_hash, 'password')

八、文件上传 #

8.1 配置上传目录 #

python
import os

app.config['UPLOAD_FOLDER'] = 'static/profile_pics'
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024  # 16MB

# 允许的文件扩展名
ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif'}

def allowed_file(filename):
    return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

8.2 处理文件上传 #

python
from flask import request, url_for, flash
import secrets
from PIL import Image

@app.route('/account', methods=['GET', 'POST'])
@login_required
def account():
    form = UpdateAccountForm()
    if form.validate_on_submit():
        if form.picture.data:
            picture_file = save_picture(form.picture.data)
            current_user.image_file = picture_file
        current_user.username = form.username.data
        current_user.email = form.email.data
        db.session.commit()
        flash('您的账户信息已更新!', 'success')
        return redirect(url_for('account'))
    elif request.method == 'GET':
        form.username.data = current_user.username
        form.email.data = current_user.email
    image_file = url_for('static', filename='profile_pics/' + current_user.image_file)
    return render_template('account.html', title='账户信息', image_file=image_file, form=form)

def save_picture(form_picture):
    random_hex = secrets.token_hex(8)
    _, f_ext = os.path.splitext(form_picture.filename)
    picture_fn = random_hex + f_ext
    picture_path = os.path.join(app.root_path, 'static/profile_pics', picture_fn)
    
    # 调整图片大小
    output_size = (125, 125)
    i = Image.open(form_picture)
    i.thumbnail(output_size)
    i.save(picture_path)
    
    return picture_fn

九、REST API开发 #

9.1 创建API路由 #

python
from flask import jsonify, request

# 获取所有用户
@app.route('/api/users', methods=['GET'])
def get_users():
    users = User.query.all()
    output = []
    for user in users:
        user_data = {
            'id': user.id,
            'username': user.username,
            'email': user.email
        }
        output.append(user_data)
    return jsonify({'users': output})

# 获取单个用户
@app.route('/api/users/<int:id>', methods=['GET'])
def get_user(id):
    user = User.query.get_or_404(id)
    return jsonify({
        'id': user.id,
        'username': user.username,
        'email': user.email
    })

# 创建用户
@app.route('/api/users', methods=['POST'])
def create_user():
    data = request.get_json()
    hashed_password = generate_password_hash(data['password'], method='pbkdf2:sha256')
    new_user = User(username=data['username'], email=data['email'], password=hashed_password)
    db.session.add(new_user)
    db.session.commit()
    return jsonify({'message': '用户创建成功'}), 201

# 更新用户
@app.route('/api/users/<int:id>', methods=['PUT'])
def update_user(id):
    user = User.query.get_or_404(id)
    data = request.get_json()
    user.username = data['username']
    user.email = data['email']
    db.session.commit()
    return jsonify({'message': '用户更新成功'})

# 删除用户
@app.route('/api/users/<int:id>', methods=['DELETE'])
def delete_user(id):
    user = User.query.get_or_404(id)
    db.session.delete(user)
    db.session.commit()
    return jsonify({'message': '用户删除成功'})

9.2 使用Flask-RESTful扩展 #

安装扩展:

bash
pip install flask-restful

使用Flask-RESTful:

python
from flask_restful import Api, Resource, reqparse

api = Api(app)

user_parser = reqparse.RequestParser()
user_parser.add_argument('username', required=True, help='用户名不能为空')
user_parser.add_argument('email', required=True, help='邮箱不能为空')
user_parser.add_argument('password', required=True, help='密码不能为空')

class UserResource(Resource):
    def get(self, user_id):
        user = User.query.get_or_404(user_id)
        return {
            'id': user.id,
            'username': user.username,
            'email': user.email
        }
    
    def put(self, user_id):
        user = User.query.get_or_404(user_id)
        args = user_parser.parse_args()
        user.username = args['username']
        user.email = args['email']
        db.session.commit()
        return {'message': '用户更新成功'}
    
    def delete(self, user_id):
        user = User.query.get_or_404(user_id)
        db.session.delete(user)
        db.session.commit()
        return {'message': '用户删除成功'}

class UserListResource(Resource):
    def get(self):
        users = User.query.all()
        output = []
        for user in users:
            output.append({
                'id': user.id,
                'username': user.username,
                'email': user.email
            })
        return {'users': output}
    
    def post(self):
        args = user_parser.parse_args()
        hashed_password = generate_password_hash(args['password'], method='pbkdf2:sha256')
        new_user = User(username=args['username'], email=args['email'], password=hashed_password)
        db.session.add(new_user)
        db.session.commit()
        return {'message': '用户创建成功'}, 201

# 添加API资源
api.add_resource(UserListResource, '/api/users')
api.add_resource(UserResource, '/api/users/<int:user_id>')

十、错误处理 #

10.1 自定义错误页面 #

python
@app.errorhandler(404)
def page_not_found(e):
    return render_template('404.html'), 404

@app.errorhandler(500)
def internal_server_error(e):
    return render_template('500.html'), 500

@app.errorhandler(403)
def forbidden(e):
    return render_template('403.html'), 403

10.2 错误日志 #

python
import logging

# 配置日志
logging.basicConfig(
    filename='flask_app.log',
    level=logging.DEBUG,
    format='%(asctime)s %(levelname)s %(name)s %(threadName)s : %(message)s'
)

# 记录日志
app.logger.debug('这是调试信息')
app.logger.info('这是普通信息')
app.logger.warning('这是警告信息')
app.logger.error('这是错误信息')
app.logger.critical('这是严重错误信息')

十一、部署 #

11.1 生产环境配置 #

python
import os

class Config:
    SECRET_KEY = os.environ.get('SECRET_KEY') or 'hard-to-guess-string'
    SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or 'sqlite:///site.db'
    SQLALCHEMY_TRACK_MODIFICATIONS = False
    MAIL_SERVER = os.environ.get('MAIL_SERVER')
    MAIL_PORT = int(os.environ.get('MAIL_PORT') or 25)
    MAIL_USE_TLS = os.environ.get('MAIL_USE_TLS') is not None
    MAIL_USERNAME = os.environ.get('MAIL_USERNAME')
    MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD')
    MAIL_DEFAULT_SENDER = os.environ.get('MAIL_DEFAULT_SENDER')

app.config.from_object(Config)

11.2 使用Gunicorn #

安装Gunicorn:

bash
pip install gunicorn

运行应用:

bash
gunicorn -w 4 -b 0.0.0.0:5000 run:app

11.3 使用Nginx作为反向代理 #

nginx
server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://127.0.0.1:5000;
        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;
    }

    location /static {
        alias /path/to/your/app/static;
    }

    location /media {
        alias /path/to/your/app/media;
    }
}

11.4 Docker部署 #

创建Dockerfile:

dockerfile
FROM python:3.11-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

EXPOSE 5000

CMD ["gunicorn", "-w", "4", "-b", "0.0.0.0:5000", "run:app"]

创建docker-compose.yml:

yaml
version: '3.8'

services:
  web:
    build: .
    ports:
      - "5000:5000"
    environment:
      - SECRET_KEY=your-secret-key
      - DATABASE_URL=sqlite:///site.db
    volumes:
      - ./site.db:/app/site.db

十二、Flask最佳实践 #

12.1 项目结构 #

采用模块化结构,将应用拆分为多个蓝图。

text
myapp/
├── app/
│   ├── __init__.py
│   ├── main/
│   │   ├── __init__.py
│   │   ├── routes.py
│   │   └── forms.py
│   ├── users/
│   │   ├── __init__.py
│   │   ├── routes.py
│   │   ├── forms.py
│   │   └── utils.py
│   ├── posts/
│   │   ├── __init__.py
│   │   ├── routes.py
│   │   └── forms.py
│   ├── models.py
│   ├── templates/
│   └── static/
├── config.py
├── run.py
└── requirements.txt

12.2 使用蓝图 #

python
# app/main/__init__.py
from flask import Blueprint

main = Blueprint('main', __name__)

from . import routes

# app/__init__.py
from flask import Flask
from app.main.routes import main

app = Flask(__name__)
app.register_blueprint(main)

12.3 环境变量 #

使用环境变量存储敏感信息,避免硬编码。

12.4 测试 #

安装测试工具:

bash
pip install pytest coverage

创建测试用例:

python
import pytest
from app import create_app, db
from app.models import User

@pytest.fixture
def client():
    app = create_app()
    app.config['TESTING'] = True
    app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///:memory:'
    
    with app.app_context():
        db.create_all()
        yield app.test_client()
        db.drop_all()

def test_home_page(client):
    response = client.get('/')
    assert response.status_code == 200
    assert b'Welcome' in response.data

运行测试:

bash
pytest
coverage run -m pytest
coverage report

12.5 性能优化 #

  • 使用缓存(如Flask-Caching)
  • 数据库查询优化
  • 静态文件压缩
  • 使用异步任务(如Celery)

十三、常用扩展 #

扩展名称 用途 安装命令
Flask-WTF 表单处理 pip install flask-wtf
Flask-SQLAlchemy 数据库集成 pip install flask-sqlalchemy
Flask-Login 用户认证 pip install flask-login
Flask-Mail 邮件发送 pip install flask-mail
Flask-Bcrypt 密码哈希 pip install flask-bcrypt
Flask-Caching 缓存支持 pip install flask-caching
Flask-RESTful REST API开发 pip install flask-restful
Flask-Admin 管理界面 pip install flask-admin
Flask-Migrate 数据库迁移 pip install flask-migrate
Flask-SocketIO WebSocket支持 pip install flask-socketio

十四、总结 #

Flask是一个灵活且强大的Python Web框架,适合从简单的个人项目到复杂的企业应用。通过掌握本文介绍的基础概念、核心功能和最佳实践,您将能够构建高质量的Flask应用程序。

继续学习和探索Flask生态系统,您将发现更多高级功能和扩展,帮助您更高效地开发Web应用。

最后更新:2026-02-07