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 "更新用户资料"
相关推荐
weixin_586061462 小时前
Go 中实现无侵入式方法级执行时间监控的完整实践指南
jvm·数据库·python
NotFound4862 小时前
golang如何实现时间格式化_golang时间格式化方法详解
jvm·数据库·python
DaqunChen2 小时前
PHP怎么合并数组_array_merge函数指南【指南】
jvm·数据库·python
InfinteJustice2 小时前
如何在 Laravel Excel 导入时检测并阻止重复列值
jvm·数据库·python
xiaotao1312 小时前
01-编程基础与数学基石: NumPy数值计算库
人工智能·python·numpy
2301_777599372 小时前
Quill 编辑器光标意外跳转至顶部的解决方案
jvm·数据库·python
weixin_586061462 小时前
Quill 编辑器光标跳转到顶部的解决方案
jvm·数据库·python
Hacker_seagull2 小时前
Sqlmap 工具保姆级使用教程
经验分享·python·web安全·网络安全
2301_782659182 小时前
Go 中使用 go-json-rest 时调用 Write 方法的正确方式
jvm·数据库·python