Python 为什么Django自定义管理器中不显示此方法?
我有两个Django模型,一个存储促销代码,另一个跟踪谁兑换了特定的促销代码。我正在尝试创建一个实例方法,用于确定特定用户是否兑换了特定代码。问题是我没有看到我的PromotionManager方法之一“由用户赎回”。以下是我的课程: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
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()导致无法检索您想要使用的对象的情况。”文档提到了一个非常具体的场景,您必须小心,这在这里不适用。这决不是不可预测的。。。。如果在默认管理器中添加新方法,没有人(至少乍一看)会期望它们出现,那么代码本身就必须说明问题。因此,现在他们必须发现第二个管理器,而不是自定义管理器上的方法?无论哪种方式,他们都必须查看代码和/或项目文档。