尝试将装饰器添加到 models.Manager 时出现 Python Django 错误

Posted

技术标签:

【中文标题】尝试将装饰器添加到 models.Manager 时出现 Python Django 错误【英文标题】:Python Django error when attempting to add decorators to models.Manager 【发布时间】:2012-02-16 08:05:58 【问题描述】:

这是我的问题。我正在尝试向基于 Django 的代码添加检测。这是我的工作:

def trace(func):
  def wrapped(*args, **kwargs):
    print func.__name__
    return func(*args, **kwargs)
  return wrapped

def trace_class_func(kclass, func):
  setattr(kclass, func.__name__, classmethod(trace(func.im_func)))


# Trace all the calls to 'get_query_set' from all the classes or subclasses of Manager
tracer.trace_class_func(models.Manager, models.Manager.get_query_set)

这个类存储在模块“tracer”中,我在 settings.py 的 INSTALLED_APPS 部分添加了“tracer”(注意最后添加了“tracer”模块)。

但是,当我运行我的应用程序时,我收到了这个错误:

异常类型:AttributeError at /settings/integrations/ 异常值:类型对象“UserManager”没有属性“模型”

这发生在 django/db/models/manager.py 的 get_query_set 函数中。

编辑:交易是,当我尝试打印 UserManager 类(派生自 models.Manager)的内容时,只有 UserManager 中定义的字段被识别,而基类中没有任何字段:

self: <class 'django.contrib.auth.models.UserManager'>
keys: '__module__': 'django.contrib.auth.models', 'create_superuser': <function create_superuser at 0x10d44eaa0>, 'create_user': <function create_user at 0x10d44ea28>, 'make_random_password': <function make_random_password at 0x10d44eb18>, '__doc__': None, '__init__': <function __init__ at 0x10d44e9b0>

可以看出,即使是由 UserManager 定义的函数也只是被打印出来,而不是由 models.Manager 定义的那些。不过不知道为什么会这样。

有人知道这里发生了什么吗?因为当我在我的自定义类(包括基类和继承类)上运行这个跟踪器时,它运行良好,所以我猜这是一个 Django 错误,无论是在我的配置中还是在其他地方。

【问题讨论】:

如果你怀疑是 django 配置错误,你能检查一下不使用你的跟踪代码时是否出现同样的错误吗? 是的,当我从 INSTALLED_APPS 禁用跟踪器时不会发生错误。 【参考方案1】:

问题在于get_query_set 不是类方法。实例本身被忽略,因此 self != instance,它是没有模型的类。

A class method receives the class itself as the first argument, not the instance.

class MyClass(object):
   @classmethod
   def foo(cls):
       print "i'm a class: 0".format(cls)
# i'm a class: __main__.MyClass

class MyClass(object):
   def foo(self):
       print "i'm a class instance: 0".format(self)
# i'm a class instance: <__main__.MyClass instance at 0x1064abef0>

【讨论】:

您能详细说明一下吗?为什么 get_query_set 不是类方法? (我可以在 models.Manager 中看到 def get_query_set(self))。这个问题应该怎么解决? @Rajat,已更新 - 解决方案似乎正在删除 classmethod 调用,因此该函数可以访问管理器实例。 PS:顺便说一句很酷!

以上是关于尝试将装饰器添加到 models.Manager 时出现 Python Django 错误的主要内容,如果未能解决你的问题,请参考以下文章

如何使用装饰器将多个 div 或字段集添加到 zend_form?

如何将自定义装饰器添加到 FastAPI 路由?

如何在不复制整个方法的情况下将装饰器添加到 Python 中的继承方法?

如何在python中“事后”将装饰器附加到函数上?

如何在graphql中将装饰器添加到args参数

使用自定义 TS 装饰器的组件方法中未定义角服务