Flask中login_required与admin_required装饰器互相覆盖报错求助
Flask装饰器端点覆盖问题的原因与解决方法
问题原因
你遇到的AssertionError核心原因是装饰器未正确保留原视图函数的元信息:
- 你在装饰器里调用了
wraps(view),但没把它作为装饰器应用到内部包装函数上(缺少@符号)。 - Flask默认用视图函数的名称作为路由的端点标识,当多个视图被同一个装饰器处理后,它们的函数名都变成了装饰器内部的
log_req或adm_req,Flask就会判定这些路由的端点重复,从而抛出“视图函数映射覆盖已有端点”的错误。
另外代码里还有两个隐性问题会导致后续报错:
- 直接访问
session['a_id']或session['role'],如果session中没有对应键会抛出KeyError; url_for('wesite.portal_home')里的wesite是拼写错误,应为website。
解决方法
修改装饰器代码,给内部包装函数加上@wraps(view)装饰,同时修复上述两个小问题:
修正后的装饰器代码
from functools import wraps from flask import session, redirect, url_for # 登录验证装饰器 def login_required(view): @wraps(view) # 用@符号将wraps作为装饰器应用 def log_req(**kwargs): # 使用session.get()避免键不存在的KeyError if session.get('a_id') is None: return redirect(url_for('website.login')) return view(**kwargs) return log_req # 管理员验证装饰器 def admin_required(view): @wraps(view) # 同样添加@wraps(view) def adm_req(**kwargs): if session.get('role') != 'admin': # 修复拼写错误:wesite → website return redirect(url_for('website.portal_home')) return view(**kwargs) return adm_req
路由装饰器顺序优化
虽然修复后装饰器顺序不影响端点问题,但建议调整为先验证登录,再验证管理员,逻辑更合理:
@website.route('/api/register-user', methods=('POST',)) @login_required @admin_required def register_user(): ...
这样修改后,每个被装饰的视图都会保留自己的函数名,Flask就能正确识别不同的路由端点,不会再出现覆盖错误。
内容的提问来源于stack exchange,提问作者Flask Programmer
相关产品推荐
相关产品推荐

