如何将装饰器中的Queryset传递给函数以避免重复执行数据库查询?
当然可以!这样做不仅能避免重复查询,还能让代码更简洁
你完全可以把装饰器中获取到的Wifi对象直接传递给被装饰的视图函数,这样就能省去视图里重复执行的get_object_or_404查询,同时保持权限验证的逻辑集中在装饰器里。
下面是具体的修改方案:
修改装饰器(decorator.py)
调整装饰器的wrapper函数,在验证权限后,把查询到的wifi对象作为参数传给视图,而不是原有的wifi_id:
def is_wifi_author(func): def wrapper(request, wifi_id, **kwargs): # 只执行一次数据库查询 wifi = get_object_or_404(Wifi, pk=wifi_id) # 权限验证逻辑 if request.user != wifi.author: return redirect('youshallnotpass') # 将查询好的wifi对象传递给视图函数 return func(request, wifi, **kwargs) return wrapper
修改视图函数(views.py)
视图函数不再需要接收wifi_id,而是直接接收装饰器传来的wifi对象,省去重复查询的步骤:
@is_wifi_author def edit(request, wifi): # 参数改为直接接收wifi对象 # 现在可以直接使用这个wifi对象,无需再次查询数据库 # 示例:可以把wifi传给模板 return render(request, 'app/template.html', {'wifi': wifi})
额外的优化建议
- 增加登录验证:如果未登录用户也能访问这个视图,建议在装饰器里先检查用户是否登录,避免后续出现
AnonymousUser和wifi.author对比的错误:
def is_wifi_author(func): def wrapper(request, wifi_id, **kwargs): if not request.user.is_authenticated: return redirect('login') # 替换成你的登录页URL名称 wifi = get_object_or_404(Wifi, pk=wifi_id) if request.user != wifi.author: return redirect('youshallnotpass') return func(request, wifi, **kwargs) return wrapper
保持URL配置不变:你的URLconf不需要做任何修改,因为装饰器的
wrapper函数仍然接收wifi_id作为参数,只是内部把它转换成对象传递给视图,对外部来说完全透明。复用装饰器:这个装饰器可以直接用于其他需要验证Wifi作者权限的视图(比如删除视图),保持权限逻辑的一致性,减少代码冗余。
内容的提问来源于stack exchange,提问作者enchance
相关产品推荐
相关产品推荐

