Flask学习总结

常用示例代码

1. 蓝图路由配置(模块化管理)

目录结构

project/
├── app.py          # 主应用
└── users/          # 用户模块(蓝图)
    ├── __init__.py
    ├── views.py    # 视图函数
    └── templates/  # 蓝图模板
        └── login.html

users/init.py(创建蓝图)

from flask import Blueprint

# 创建蓝图,指定模板目录和静态文件目录
users_bp = Blueprint(
    'users',
    __name__,
    template_folder='templates',
    static_folder='static',
    static_url_path='/users/static'
)

# 导入视图(避免循环导入)
from . import views

users/views.py(蓝图路由)

from flask import render_template, url_for
from . import users_bp

@users_bp.route('/login', methods=['GET', 'POST'])
def login():
    # 生成蓝图内路由的URL
    register_url = url_for('users.register')
    return render_template('login.html', register_url=register_url)

@users_bp.route('/register')
def register():
    return "用户注册页面"

users/templates/login.html(蓝图模板)

{% extends "../base.html" %}  # 继承项目根目录模板

{% block main %}
    <h1>登录</h1>
    <a href="{{ register_url }}">去注册</a>
{% endblock %}

app.py(主应用注册蓝图)

from flask import Flask
from users import users_bp

app = Flask(__name__)
app.config['DEBUG'] = True

# 注册蓝图,添加URL前缀
app.register_blueprint(users_bp, url_prefix='/users')

@app.route('/')
def index():
    return "首页"

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

2. 模板继承示例

base.html(父模板)

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>{{ title | default('默认标题') }}</title>
    {% block css %}{% endblock %}
</head>
<body>
    <header>公共头部</header>
    {% block main %}
        <p>默认内容</p>
    {% endblock %}
    <footer>公共底部</footer>
    {% block js %}{% endblock %}
</body>
</html>

list.html(子模板)

{% extends "base.html" %}

{% block css %}
    <style>body{color: red;}</style>
{% endblock %}

{% block main %}
    {{ super() }}  # 继承父模板内容
    <ul>
        {% for item in items %}
            <li>{{ item }}</li>
        {% endfor %}
    </ul>
{% endblock %}

3. 数据库模型与关联查询

from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy(app)

# 一对多关系:老师 -> 课程
class Teacher(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64))
    # 关联课程(反向引用为teacher)
    courses = db.relationship('Course', backref='teacher', lazy='dynamic')

class Course(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64))
    # 外键关联老师
    teacher_id = db.Column(db.Integer, db.ForeignKey('teacher.id'))

# 多对多关系:学生 -> 课程
student_course = db.Table(
    'student_course',
    db.Column('student_id', db.Integer, db.ForeignKey('student.id')),
    db.Column('course_id', db.Integer, db.ForeignKey('course.id'))
)

class Student(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64))
    # 关联课程
    courses = db.relationship(
        'Course',
        secondary=student_course,
        backref=db.backref('students', lazy='dynamic'),
        lazy='dynamic'
    )

4. 请求钩子示例

@app.before_request
def before_request():
    # 所有请求处理前执行(如权限验证)
    print("请求到来了")

@app.after_request
def after_request(response):
    # 响应返回前执行(如添加响应头)
    response.headers['X-Framework'] = 'Flask'
    return response

@app.teardown_request
def teardown_request(exc):
    # 请求结束后执行(如异常记录)
    if exc:
        print(f"发生异常:{exc}")

标准 Flask 项目示例代码(前后端分离)

一、标准 Flask 项目目录结构(生产级)

project/
├── app/                      # 应用核心目录
│  ├── __init__.py            # 应用工厂函数
│  ├── config/                # 配置文件
│  │  ├── __init__.py
│  │  ├── base.py             # 基础配置
│  │  ├── development.py      # 开发环境
│  │  └── production.py       # 生产环境
│  ├── models/                # 数据库模型(单独文件夹)
│  │  ├── __init__.py
│  │  ├── user.py             # 用户模型
│  │  └── article.py          # 文章模型
│  ├── api/                   # API蓝图(按模块拆分)
│  │  ├── __init__.py
│  │  ├── v1/                 # 版本1
│  │  │  ├── __init__.py
│  │  │  ├── users.py         # 用户相关接口
│  │  │  └── articles.py      # 文章相关接口
│  ├── services/              # 业务逻辑层(可选)
│  │  ├── __init__.py
│  │  └── user_service.py     # 用户业务处理
│  ├── schemas/               # 数据校验/序列化(可选,用marshmallow)
│  │  ├── __init__.py
│  │  └── user_schema.py
│  ├── utils/                 # 工具函数
│  │  ├── __init__.py
│  │  ├── response.py         # 响应格式化工具
│  │  └── validator.py        # 通用校验
│  └── extensions.py          # 扩展实例化(db、migrate等)
├── migrations/               # 数据库迁移文件(Flask-Migrate生成)
├── tests/                    # 单元测试
├── .env                      # 环境变量(不提交到git)
├── .gitignore
├── requirements.txt          # 依赖列表
└── manage.py                 # 项目入口(启动、迁移等命令)

二、核心文件实现(含数据库模型 + 请求响应处理)

1. 数据库模型(单独管理)

app/extensions.py(扩展初始化,避免循环导入)

from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate

db = SQLAlchemy()
migrate = Migrate()

app/models/user.py(用户模型)

from datetime import datetime
from app.extensions import db

class User(db.Model):
    __tablename__ = 'users'  # 数据库表名
    
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(64), unique=True, nullable=False)
    email = db.Column(db.String(120), unique=True, nullable=False)
    password_hash = db.Column(db.String(128), nullable=False)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
    
    # 关系:一个用户有多篇文章(一对多)
    articles = db.relationship('Article', backref='author', lazy='dynamic')
    
    def to_dict(self):
        """将模型转为字典(用于响应)"""
        return {
            'id': self.id,
            'username': self.username,
            'email': self.email,
            'created_at': self.created_at.isoformat()
        }

app/models/article.py(文章模型)

from datetime import datetime
from app.extensions import db

class Article(db.Model):
    __tablename__ = 'articles'
    
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(128), nullable=False)
    content = db.Column(db.Text, nullable=False)
    author_id = db.Column(db.Integer, db.ForeignKey('users.id'))  # 外键关联用户
    created_at = db.Column(db.DateTime, default=datetime.utcnow)

2. 请求与响应处理(核心功能)

app/utils/response.py(统一响应格式化工具)

from flask import jsonify

def success(data=None, message="操作成功"):
    """成功响应"""
    return jsonify({
        'code': 200,
        'message': message,
        'data': data
    })

def fail(message="操作失败", code=400):
    """失败响应"""
    return jsonify({
        'code': code,
        'message': message,
        'data': None
    }), code  # 第二个参数是HTTP状态码

app/api/v1/users.py(用户接口,含请求处理)

from flask import Blueprint, request, current_app
from app.extensions import db
from app.models.user import User
from app.utils.response import success, fail
from werkzeug.security import generate_password_hash  # 密码加密

# 创建用户模块蓝图
users_bp = Blueprint('users', __name__)

@users_bp.route('', methods=['GET'])
def get_users():
    """获取用户列表(处理查询参数)"""
    # 处理请求参数:/api/v1/users?page=1&size=10
    page = request.args.get('page', 1, type=int)
    size = request.args.get('size', 10, type=int)
    
    # 分页查询
    pagination = User.query.paginate(page=page, per_page=size)
    users = pagination.items
    
    # 构建响应
    return success({
        'total': pagination.total,
        'page': page,
        'size': size,
        'items': [user.to_dict() for user in users]
    })

@users_bp.route('', methods=['POST'])
def create_user():
    """创建用户(处理JSON/表单请求)"""
    # 处理JSON请求体
    data = request.get_json()  # 若前端传JSON
    # 若前端传表单:data = request.form.to_dict()
    
    # 校验必填字段
    if not all(k in data for k in ('username', 'email', 'password')):
        return fail("缺少必填字段", 400)
    
    # 检查用户是否已存在
    if User.query.filter_by(username=data['username']).first():
        return fail("用户名已存在", 409)
    
    # 创建用户
    try:
        user = User(
            username=data['username'],
            email=data['email'],
            password_hash=generate_password_hash(data['password'])  # 加密存储
        )
        db.session.add(user)
        db.session.commit()
        return success(user.to_dict(), "用户创建成功"), 201  # 201表示创建成功
    except Exception as e:
        db.session.rollback()
        current_app.logger.error(f"创建用户失败: {str(e)}")  # 日志记录
        return fail("服务器错误", 500)

@users_bp.route('/<int:user_id>', methods=['GET'])
def get_user(user_id):
    """获取单个用户(路径参数)"""
    user = User.query.get_or_404(user_id)  # 不存在返回404
    return success(user.to_dict())

3. 蓝图注册与应用初始化

app/api/v1/init.py(注册 v1 版本蓝图)

from flask import Blueprint
from .users import users_bp
from .articles import articles_bp  # 假设存在文章接口

# 创建v1版本总蓝图
api_v1_bp = Blueprint('api_v1', __name__, url_prefix='/api/v1')

# 注册子蓝图
api_v1_bp.register_blueprint(users_bp, url_prefix='/users')
api_v1_bp.register_blueprint(articles_bp, url_prefix='/articles')

app/init.py(应用工厂函数)

from flask import Flask
from app.config import config
from app.extensions import db, migrate
from app.api.v1 import api_v1_bp

def create_app(config_name='development'):
    app = Flask(__name__)
    app.config.from_object(config[config_name])  # 加载配置
    
    # 初始化扩展
    db.init_app(app)
    migrate.init_app(app, db)
    
    # 注册蓝图
    app.register_blueprint(api_v1_bp)
    
    return app

4. 项目入口(manage.py)

import os
from flask_migrate import MigrateCommand
from flask_script import Manager
from app import create_app
from app.extensions import db

app = create_app(os.getenv('FLASK_ENV', 'development'))
manager = Manager(app)

# 添加数据库迁移命令
manager.add_command('db', MigrateCommand)

# 自定义命令:创建管理员用户
@manager.command
def create_superuser():
    from app.models.user import User
    from werkzeug.security import generate_password_hash
    
    username = input("请输入管理员用户名: ")
    email = input("请输入管理员邮箱: ")
    password = input("请输入管理员密码: ")
    
    user = User(
        username=username,
        email=email,
        password_hash=generate_password_hash(password)
    )
    db.session.add(user)
    db.session.commit()
    print("超级管理员创建成功!")

if __name__ == '__main__':
    manager.run()

示例代码(前后端不分离)

一、含模板文件的目录结构(前后端不分离)

在原有结构基础上,增加模板(templates)和静态文件(static)目录:

project/
├── app/
│  ├── models/                # 数据库模型
│  ├── api/                   # API接口(前后端分离用)
│  ├── web/                   # 新增:Web页面模块(含蓝图和模板)
│  │  ├── users/              # 用户相关页面模块
│  │  │  ├── __init__.py      # 蓝图定义
│  │  │  ├── views.py         # 视图函数(渲染HTML)
│  │  │  ├── templates/       # 蓝图专属模板(优先重名)
│  │  │  │  └── users/        # 建议再嵌套一层同名文件夹,避免与其他蓝图冲突
│  │  │  │     ├── login.html
│  │  │  │     └── profile.html
│  │  │  └── static/          # 蓝图专属静态文件(CSS/JS/图片)
│  │  │     └── css/
│  │  │         └── user.css
│  ├── templates/             # 全局模板(公共组件,如base.html)
│  │  └── base.html
│  └── static/                # 全局静态文件(如全局CSS/JS)
│     └── js/
│         └── common.js

 二、蓝图指定模板 / 静态文件夹的正确配置

app/web/users/init.py(创建蓝图时指定路径):

from flask import Blueprint

# 关键:指定蓝图专属的模板和静态文件目录
users_bp = Blueprint(
    'users',  # 蓝图名(唯一标识)
    __name__,
    url_prefix='/users',  # URL前缀
    template_folder='templates',  # 模板文件夹(相对当前文件的路径)
    static_folder='static',  # 静态文件文件夹
    static_url_path='/users/static'  # 静态文件访问URL(避免与全局静态文件冲突)
)

# 导入视图(放在蓝图定义后,避免循环导入)
from . import views

三、视图函数渲染模板示例

app/web/users/views.py

from flask import render_template, redirect, url_for, request, flash
from . import users_bp
from app.models.user import User
from app.extensions import db

@users_bp.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        # 处理表单提交(获取表单数据)
        username = request.form.get('username')
        password = request.form.get('password')
        
        # 简单验证(实际项目需加密码校验)
        user = User.query.filter_by(username=username).first()
        if user:
            flash('登录成功', 'success')  # 消息提示
            return redirect(url_for('users.profile', user_id=user.id))
        else:
            flash('用户名或密码错误', 'danger')
    
    # 渲染蓝图专属模板(会自动查找 users/templates/users/login.html)
    return render_template('users/login.html')

@users_bp.route('/profile/<int:user_id>')
def profile(user_id):
    user = User.query.get_or_404(user_id)
    # 继承全局模板 base.html
    return render_template('users/profile.html', user=user)

四、模板文件内容示例

1、全局模板(app/templates/base.html)

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>{% block title %}Flask项目{% endblock %}</title>
    <!-- 引入全局静态文件 -->
    <script src="{{ url_for('static', filename='js/common.js') }}"></script>
    {% block css %}{% endblock %}  <!-- 预留CSS块 -->
</head>
<body>
    <header>导航栏</header>
    
    <!-- 消息提示(全局通用) -->
    {% with messages = get_flashed_messages(with_categories=true) %}
        {% if messages %}
            {% for category, message in messages %}
                <div class="alert alert-{{ category }}">{{ message }}</div>
            {% endfor %}
        {% endif %}
    {% endwith %}
    
    <main>{% block content %}{% endblock %}</main>  <!-- 内容块 -->
    
    <footer>页脚</footer>
    {% block js %}{% endblock %}  <!-- 预留JS块 -->
</body>
</html>

2、蓝图专属模板(app/web/users/templates/users/login.html)

{% extends "base.html" %}  <!-- 继承全局模板 -->

{% block title %}用户登录{% endblock %}

{% block css %}
    <!-- 引入蓝图专属CSS -->
    <link rel="stylesheet" href="{{ url_for('users.static', filename='css/user.css') }}">
{% endblock %}

{% block content %}
    <h1>用户登录</h1>
    <form method="POST">
        <div>
            <label>用户名:</label>
            <input type="text" name="username" required>
        </div>
        <div>
            <label>密码:</label>
            <input type="password" name="password" required>
        </div>
        <button type="submit">登录</button>
    </form>
{% endblock %}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值