Python 为什么Django自定义管理器中不显示此方法?

Python 为什么Django自定义管理器中不显示此方法?,python,django,django-models,Python,Django,Django Models,我有两个Django模型,一个存储促销代码,另一个跟踪谁兑换了特定的促销代码。我正在尝试创建一个实例方法,用于确定特定用户是否兑换了特定代码。问题是我没有看到我的PromotionManager方法之一“由用户赎回”。以下是我的课程: from django.contrib.auth.models import User from django.db import models class PromotionManager(models.Manager): def redeemed_b

我有两个Django模型,一个存储促销代码,另一个跟踪谁兑换了特定的促销代码。我正在尝试创建一个实例方法,用于确定特定用户是否兑换了特定代码。问题是我没有看到我的PromotionManager方法之一“由用户赎回”。以下是我的课程:

from django.contrib.auth.models import User
from django.db import models

class PromotionManager(models.Manager):
    def redeemed_by_user(self, promotion, user):
        redemption_count = PromotionRedeemed.objects.filter(promotion=promotion, redeemer=user).count()
        if redemption_count == 1:
            return True
        elif redemption_count == 0;
            return False
        else:
            raise ValueError('Invalid redemption count')

class Promotion(models.Model):
    code = models.CharField(max_length=16)
    objects = PromotionManager()

class PromotionRedeemed(models.Model):
    promotion = models.ForeignKey('Promotion')
    user = models.ManyToManyField(User)
如果启动Django扩展shell_plus并执行以下操作:

In [1]: user = User.objects.get(username='smith')
In [2]: promotion = Promotion.objects.get(code='bigsale')
然后我做这个:

In [3]: dir(promotion)

我没有看到“按用户赎回”方法。我的印象是,我可以将这样的方法从我的类移动到自定义管理器类。不是这样吗?如果是,有人能解释原因吗?据我所知,类管理器方法应该作用于表级查询,类维护方法作用于行级对象。objects.filter不是在表级别上运行吗?我试着将方法移回升级类,我可以在那里看到它,但我只是想理解为什么我在manager类中看不到它

无论你看到什么,都是绝对正确的,但是你应该做一些小的修正。当您执行
dir(某个实例)
时,您会看到一个名为objects的属性

objects = PromotionManager()
这一行将所有管理器方法设置为objects属性,因此如果您试图通过
某个\u instance.objects.method\u name
访问该方法,那么您将能够访问它,尽管您无法使用它,因为Django不允许这样做。您将看到一个错误,例如无法从实例访问管理器方法。dir应该只显示那些可以从模型实例访问的方法。

从文档中

管理器是向Django模型提供数据库查询操作的接口。默认情况下,Django向每个Django模型类添加一个名为“objects”的管理器

模型的管理器是Django模型执行数据库查询的对象。每个Django模型至少有一个管理器,您可以创建自定义管理器以自定义数据库访问

添加额外的管理器方法(自定义管理器)是向模型添加“表级”功能的首选方法,而“行级”功能则使用模型方法

对象是一个特殊属性,通过它可以查询数据库。它是类django.db.models.Manager的一个实例;在这里,所有用于对整个模型类执行查询的默认方法-all()、get()、filter()等

带有参数的
dir()
函数尝试返回该对象的有效属性列表

如果您
dir(promotion)
promotion
promotion
模型对象的一个实例。它返回
升级
实例的属性,该实例包括
对象
属性。但是,您将
对象
定义为
PromotionManager()
,并且
由用户赎回的方法()是Manager实例的一种方法

如果您
dir(promotion.objects)
,django将引发一个错误,
AttributeError:Manager无法通过Poke实例访问。因为,这是真的<代码>对象
是类级别上可用的
管理器
,而不是实例

,

管理器只能通过模型类(而不是模型实例)访问,以实现“表级”操作和“记录级”操作之间的分离


因此,如果您
dir(Promotion.objects)
,您可以看到模型的Manager实例中定义的所有自定义方法。

您在错误的对象上使用了
dir

此外,您用自己的管理器替换了默认管理器。 应用于模型类的第一个管理器对Django具有特殊意义,并且是默认的管理器,因此请以这种方式添加自己的管理器:

objects = models.Manager()
<your_custom_name> = PromotionManager()
objects=models.Manager()
=促销经理()

目录(promotion.objects)
呢<代码>由用户赎回-是一个管理器方法,而不是升级对象或类。您是否尝试在shell中打印(升级.code)?是的,我实际上可以看到“升级.objects”,当我尝试“dir”它时,shell告诉我“AttributeError:无法通过升级实例访问管理器”。这就解释了问题所在。谢谢。替换默认的管理器非常好。如果Django需要一个
models.Manager
实例,它将改用基本管理器。@knbk:有结果,第一个管理器(默认值)具有特殊状态。它可能会导致QuerySet产生不可预测的结果,因为该管理器由Django本身使用。我指的是“因此,在选择默认管理器时要小心,以避免覆盖get_queryset()导致无法检索您想要使用的对象的情况。”文档提到了一个非常具体的场景,您必须小心,这在这里不适用。这决不是不可预测的。。。。如果在默认管理器中添加新方法,没有人(至少乍一看)会期望它们出现,那么代码本身就必须说明问题。因此,现在他们必须发现第二个管理器,而不是自定义管理器上的方法?无论哪种方式,他们都必须查看代码和/或项目文档。