You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现与被包装方法参数签名不同的Django视图装饰器?

问题分析与解决

原代码的核心问题

  1. 实例化错误:obj = Decorated是直接引用类对象,而非创建类实例。调用obj.mymethod('haha', 'hehe', 'hoho')时,第一个参数'haha'会被当作self传入装饰器的wrapper,但self需要是类实例,导致参数类型不匹配报错。
  2. 参数逻辑缺失:装饰器的wrapper接收了*args, **kwargs但未用于生成slugs,且被装饰方法mymethod只期望接收slugs参数,两者的参数传递逻辑不匹配。

正确实现代码

from functools import wraps

def mydecorator(fn):
    @wraps(fn)
    def wrapper(self, *args, **kwargs):
        # 根据传入的参数生成slugs(这里示例将位置参数转为字典)
        slugs = {f'param_{idx}': val for idx, val in enumerate(args)}
        # 将处理后的slugs传给被装饰方法
        return fn(self, slugs)
    return wrapper

class Decorated:
    @mydecorator
    def mymethod(self, slugs):
        print(slugs)

# 正确创建类实例
obj = Decorated()
# 调用时传入多个参数,装饰器自动处理为slugs
obj.mymethod('haha', 'hehe', 'hoho')

Django视图场景适配(基于类的视图CBV)

如果是用于Django视图,只需调整装饰器的参数签名以匹配CBV的方法规范:

from functools import wraps
from django.views.generic import View
from django.http import HttpResponse

def slug_processor(fn):
    @wraps(fn)
    def wrapper(self, request, *args, **kwargs):
        # 从URL kwargs或request中提取参数生成slugs
        slugs = {
            'category': kwargs.get('category'),
            'product': kwargs.get('product')
        }
        # 传递处理后的slugs给视图方法
        return fn(self, request, slugs)
    return wrapper

class ProductView(View):
    @slug_processor
    def get(self, request, slugs):
        return HttpResponse(f"当前分类: {slugs['category']}, 商品: {slugs['product']}")

关键注意点

  • 必须使用@wraps(fn):保留被装饰方法的元信息,避免Django视图系统因方法签名检测失败报错。
  • 装饰器wrapper的参数签名要匹配被装饰方法的原始签名:比如CBV的get方法默认接收self, request, *args, **kwargs,装饰器需先接收这些参数,再处理生成目标参数传递给被装饰方法。
  • 类方法调用前必须实例化:确保self参数是合法的类实例。

内容的提问来源于stack exchange,提问作者Lex Podgorny

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 23:01:09