为什么Django Custom Manager无法看到此方法?

时间:2017-06-30 16:03:28

标签: python django django-models

我有两个Django模型,一个存储促销代码,另一个跟踪兑换特定促销代码的人。我正在尝试创建一个实例方法,用于确定特定用户是否已兑换特定代码。问题是我没有看到我的一个PromotionManager方法,'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)

我没有看到用户方法兑换。我的印象是我可以将类似这样的方法从我的类移到自定义管理器类。那不是这样吗?如果是这样,有人可以解释为什么吗据我所知,类管理器方法应该作用于行级对象的表级查询和类intance方法。 object.filter不是在表级别上行动吗?我尝试将方法移回到Promotion类,我可以在那里看到它,但我只想理解为什么我在管理器类中看不到它。

3 个答案:

答案 0 :(得分:1)

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

objects = PromotionManager()

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

答案 1 :(得分:1)

来自文档,

  

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

     

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

     

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

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

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

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

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

From the docs

  

管理员只能通过模型​​类访问,而不能通过模型​​实例访问,以强制“表级”操作和“记录级”操作之间的分离。

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

答案 2 :(得分:0)

您在错误的对象上使用dir

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

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