flask 路由 add_url_rule 、@app.route app.test_request_context() 类视图

python 复制代码
from flask import Flask

app = Flask(__name__)

def hello():
    return "Hello, World!"

# 注册路由
app.add_url_rule('/', 'hello', hello)

# 等价于:
# @app.route('/')
# def hello():
#     return "Hello, World!"

#  带变量的路由 
def user_profile(username):
    return f"用户: {username}"

app.add_url_rule('/user/<username>', 'user_profile', user_profile)

# 带类型转换器
def post_detail(post_id):
    return f"文章ID: {post_id}"

app.add_url_rule('/post/<int:post_id>', 'post_detail', post_detail)


#  指定  请求方式的
def user_list():
    if request.method == 'GET':
        return "获取用户列表"
    elif request.method == 'POST':
        return "创建新用户"

app.add_url_rule('/users', 'user_list', user_list, methods=['GET', 'POST'])

# 等价于:
# @app.route('/users', methods=['GET', 'POST'])
# def user_list():
#     ...
python 复制代码
app.test_request_context() 返回一个请求上下文对象(RequestContext),它模拟一个 HTTP 请求环境,让你可以在没有实际请求的情况下使用 Flask 的请求相关功能。
from flask import Flask, url_for, request, session

app = Flask(__name__)

# 调用 test_request_context() 返回一个上下文对象
ctx = app.test_request_context()
print(type(ctx))  
# <class 'flask.ctx.RequestContext'>


#  在没有请求时使用 url_for()
# ❌ 这样会报错(没有应用上下文)
# url_for('index')  # RuntimeError: Working outside of application context

# ✅ 使用 test_request_context
with app.test_request_context():
    url = url_for('index')  # 正常工作
    print(url)  # /


# 模拟请求数据(路径、参数、方法等)

# 模拟 GET 请求,带查询参数
with app.test_request_context('/search?q=flask&page=2'):
    print(request.method)   # GET
    print(request.path)     # /search
    print(request.args)     # ImmutableMultiDict([('q', 'flask'), ('page', '2')])
    print(request.args.get('q'))  # flask

# 模拟 POST 请求,带表单数据
with app.test_request_context('/login', method='POST', data={'username': 'admin', 'password': '123'}):
    print(request.method)   # POST
    print(request.form)     # ImmutableMultiDict([('username', 'admin'), ('password', '123')])
    print(request.form['username'])  # admin

# 模拟 JSON 数据
with app.test_request_context('/api', json={'name': '张三', 'age': 20}):
    print(request.json)  # {'name': '张三', 'age': 20}

# 模拟携带请求头
with app.test_request_context('/', headers={
    'User-Agent': 'Mozilla/5.0',
    'X-Custom-Header': 'test'
}):
    print(request.headers.get('User-Agent'))  # Mozilla/5.0
    print(request.headers.get('X-Custom-Header'))  # test

#  操作session
with app.test_request_context():
    session['user_id'] = 123
    session['username'] = 'admin'
    print(session.get('user_id'))  # 123


# 手动调用视图函数
@app.route('/user/<int:user_id>')
def user_profile(user_id):
    return f"User {user_id}"

# 测试视图函数
with app.test_request_context('/user/42'):
    # 手动调用视图函数
    response = user_profile(42)
    print(response)  # User 42

# 测试需要请求数据的视图函数
@app.route('/login', methods=['POST'])
def login():
    username = request.form.get('username')
    password = request.form.get('password')
    if username == 'admin' and password == 'secret':
        session['user'] = username
        return '登录成功'
    return '登录失败', 401

# 测试登录功能
with app.test_request_context('/login', method='POST', data={
    'username': 'admin',
    'password': 'secret'
}):
    response = login()
    print(response)  # 登录成功
    print(session.get('user'))  # admin

批量注册路由

》》使用列表批量注册路由

python 复制代码
def index(): return "首页"
def about(): return "关于"
def contact(): return "联系我们"

routes = [
    ('/', 'index', index),
    ('/about', 'about', about),
    ('/contact', 'contact', contact),
]

for rule, endpoint, view_func in routes:
    app.add_url_rule(rule, endpoint, view_func)

》》》使用字典批量注册路由

python 复制代码
routes_config = {
    '/': {'endpoint': 'home', 'view_func': index, 'methods': ['GET']},
    '/admin': {'endpoint': 'admin', 'view_func': admin, 'methods': ['GET', 'POST']},
}

for rule, config in routes_config.items():
    app.add_url_rule(rule, **config)


#  在蓝图中使用
from flask import Blueprint

admin = Blueprint('admin', __name__)

def dashboard():
    return "管理后台"

# 在蓝图上使用 add_url_rule
admin.add_url_rule('/dashboard', 'dashboard', dashboard)
# 注册蓝图
app.register_blueprint(admin, url_prefix='/admin')

#  根据条件注册路由
def register_debug_routes(app):
    """仅在调试模式下注册的路由"""
    if app.debug:
        def debug_info():
            return "调试信息"
        app.add_url_rule('/debug', 'debug_info', debug_info)

register_debug_routes(app)


#  动态添加路由(运行时)
def dynamic_page(name):
    return f"动态页面: {name}"

# 运行时动态添加路由
page_name = "test"
app.add_url_rule(f'/{page_name}', page_name, dynamic_page)

# 甚至可以循环添加
pages = ['about', 'service', 'product']
for page in pages:
    def view_func(page=page):  # 注意捕获变量
        return f"这是{page}页面"
    app.add_url_rule(f'/{page}', page, view_func)

类视图

标准视图(继承 View)
python 复制代码
from flask import Flask, request
from flask.views import View

app = Flask(__name__)

class IndexView(View):
    def dispatch_request(self):
        return "欢迎来到首页!"

class UserView(View):
    def dispatch_request(self, user_id):
        # 可以接收 URL 参数
        return f"用户 {user_id} 的页面"

# 注册路由
app.add_url_rule('/', view_func=IndexView.as_view('index'))
app.add_url_rule('/user/<int:user_id>', view_func=UserView.as_view('user'))
方法视图(继承 MethodView)⭐ 推荐

》将每个 HTTP 方法映射到同名方法,代码更清晰。

python 复制代码
from flask.views import MethodView

class UserAPI(MethodView):
    def get(self, user_id=None):
        """处理 GET 请求"""
        if user_id:
            return f"获取用户 {user_id} 的信息"
        return "获取所有用户列表"
    
    def post(self):
        """处理 POST 请求 - 创建用户"""
        return "创建新用户"
    
    def put(self, user_id):
        """处理 PUT 请求 - 更新用户"""
        return f"更新用户 {user_id}"
    
    def delete(self, user_id):
        """处理 DELETE 请求 - 删除用户"""
        return f"删除用户 {user_id}"

# 注册多个路由到同一个类视图
user_view = UserAPI.as_view('user_api')
app.add_url_rule('/users/', view_func=user_view, methods=['GET', 'POST'])
app.add_url_rule('/users/<int:user_id>', view_func=user_view, methods=['GET', 'PUT', 'DELETE'])
python 复制代码
# 它内部大致做了这些工作:
def as_view(name):
    # 1. 创建一个闭包函数
    def view(**kwargs):
        # 2. 实例化 UserView 类
        instance = UserView()
        # 3. 调用 dispatch_request 方法
        return instance.dispatch_request(**kwargs)
    
    # 4. 给这个函数起个名字(用于 endpoint)
    view.__name__ = name
    
    return view  # 返回一个真正的函数


# ✅ 正确:通过 as_view 转换
app.add_url_rule('/users', view_func=UserView.as_view('user_list'))

# 相当于手动写了一个函数视图:
def user_list():
    return UserView().dispatch_request()
app.add_url_rule('/users', view_func=user_list)



支持多个 HTTP 方法
python 复制代码
from flask.views import View
class LoginView(View):
    methods = ['GET', 'POST']  # 指定支持的方法
    
    def dispatch_request(self):
        if request.method == 'GET':
            return "显示登录表单"
        elif request.method == 'POST':
            username = request.form.get('username')
            return f"用户 {username} 登录成功"

app.add_url_rule('/login', view_func=LoginView.as_view('login'))
python 复制代码
from flask import request, jsonify, render_template

class ArticleView(MethodView):
    def __init__(self):
        # 初始化共享资源
        self.model = Article  # 假设有数据库模型
    
    def get(self, article_id=None):
        """获取文章"""
        if article_id:
            article = self.model.query.get(article_id)
            if not article:
                return jsonify({"error": "文章不存在"}), 404
            return jsonify(article.to_dict())
        else:
            articles = self.model.query.all()
            return jsonify([a.to_dict() for a in articles])
    
    def post(self):
        """创建文章"""
        data = request.get_json()
        title = data.get('title')
        content = data.get('content')
        
        if not title or not content:
            return jsonify({"error": "标题和内容不能为空"}), 400
        
        article = self.model(title=title, content=content)
        # 保存到数据库
        # db.session.add(article)
        # db.session.commit()
        
        return jsonify(article.to_dict()), 201
    
    def put(self, article_id):
        """更新文章"""
        article = self.model.query.get(article_id)
        if not article:
            return jsonify({"error": "文章不存在"}), 404
        
        data = request.get_json()
        article.title = data.get('title', article.title)
        article.content = data.get('content', article.content)
        # db.session.commit()
        
        return jsonify(article.to_dict())
    
    def delete(self, article_id):
        """删除文章"""
        article = self.model.query.get(article_id)
        if not article:
            return jsonify({"error": "文章不存在"}), 404
        
        # db.session.delete(article)
        # db.session.commit()
        return jsonify({"message": "删除成功"}), 200

# 注册路由
article_view = ArticleView.as_view('article')
app.add_url_rule('/articles/', view_func=article_view, methods=['GET', 'POST'])
app.add_url_rule('/articles/<int:article_id>', view_func=article_view, 
                 methods=['GET', 'PUT', 'DELETE'])

》》》装饰器配置

python 复制代码
# 为整个类视图添加装饰器
from flask import session, abort

def login_required(func):
    """登录验证装饰器"""
    def wrapper(*args, **kwargs):
        if not session.get('user_id'):
            abort(401)
        return func(*args, **kwargs)
    return wrapper

class DashboardView(View):
    decorators = [login_required]  # 所有请求都会经过这个装饰器
    
    def dispatch_request(self):
        return "管理员面板"

app.add_url_rule('/admin', view_func=DashboardView.as_view('admin'))
python 复制代码
# MethodView 的装饰器
class ProfileView(MethodView):
    decorators = [login_required]
    
    def get(self):
        return "用户资料页面"
    
    def post(self):
        return "更新用户资料"
相关推荐
长栎20 分钟前
写 for 循环写了十年,你却从没用过迭代器模式最狠的那一面
后端
LiaCode24 分钟前
Redis 在生产项目的使用
前端·后端
用户5598224812228 分钟前
Docker Compose Down 导致容器数据误删——ext4 日志恢复全记录
后端
LiaCode29 分钟前
一天学完 redis 的爽翻版核心知识总结
前端·后端
大刚测试开发实战30 分钟前
如何内网穿透访问本地私有化部署的TestHub
前端·后端·github
xiaodaoluanzha1 小时前
迄今為止,最簡單的編程語言 Nolang
前端·后端
Csvn1 小时前
Docker 容器管理入门 — 从镜像到容器编排
后端
用户762352425911 小时前
ShardingJDBC
后端
行者全栈架构师1 小时前
IDEA 中 Maven 项目的 15 个红色报错快速解决方法
java·后端
Colin草率地做慢慢地改1 小时前
关于QuickStore这个项目的重构(2)- 数据库建表文件
后端·面试·架构