为什么此方法在 Django 自定义管理器中不可见?



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

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 不是在表级别起作用吗? 我尝试将该方法移回升级类,我可以在那里看到它,但我只是想了解为什么我在经理类中看不到它。

你所看到的一切都是绝对正确的,但你应该做一些小的更正。当您执行dir(some_instance)时,您会看到一个名为 对象 的属性。

objects = PromotionManager()

此行将所有管理器方法设置为对象属性,因此如果您尝试通过some_instance.objects.method_name访问该方法,那么您将能够访问它,尽管您不能使用它,因为 Django 不允许这样做。您将看到一个错误,例如无法从实例访问管理器方法。DIR 应该只显示那些可以从模型实例访问的方法。

从文档中,

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

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

添加额外的管理器方法(自定义管理器(是向模型添加"表级"功能的首选方法,而对于"行级"功能,请使用模型方法。

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

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

如果dir(promotion)promotionPromotion模型对象的实例。它返回Promotion实例的属性,其中包括objects属性。但是,您将objects定义为PromotionManager(),并且redeemed_by_user()是管理器实例的方法。

如果你dir(promotion.objects),django 会引发一个错误,AttributeError: Manager isn't accessible via Poke instances。因为,这是真的。objects是在类级别可用的Manager,而不是实例。

从文档中,

只能通过模型类而不是从模型实例访问管理器,以强制分离"表级"操作和"记录级"操作。

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

您在错误的对象上使用dir

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

objects = models.Manager()
<your_custom_name> = PromotionManager()

最新更新