我试图找到一种方法来实现自定义QuerySet
和自定义Manager
,而不破坏DRY。这是我到目前为止所拥有的:
class MyInquiryManager(models.Manager):
def for_user(self, user):
return self.get_query_set().filter(
Q(assigned_to_user=user) |
Q(assigned_to_group__in=user.groups.all())
)
class Inquiry(models.Model):
ts = models.DateTimeField(auto_now_add=True)
status = models.ForeignKey(InquiryStatus)
assigned_to_user = models.ForeignKey(User, blank=True, null=True)
assigned_to_group = models.ForeignKey(Group, blank=True, null=True)
objects = MyInquiryManager()
字符串
这很好,直到我做了这样的事情:
inquiries = Inquiry.objects.filter(status=some_status)
my_inquiry_count = inquiries.for_user(request.user).count()
型
这很快就破坏了一切,因为QuerySet
没有与Manager
相同的方法。我尝试创建一个自定义的QuerySet
类,并在MyInquiryManager
中实现它,但最终我复制了所有的方法定义。
我还发现this snippet可以工作,但我需要将额外的参数传递给for_user
,所以它会崩溃,因为它严重依赖于重新定义get_query_set
。
有没有一种方法可以在不重新定义QuerySet
和Manager
子类中的所有方法的情况下做到这一点?
8条答案
按热度按时间cwxwcias1#
Django 1.7发布了一个新的简单的方法来创建组合查询集和模型管理器:
字符串
有关更多详细信息,请参见使用QuerySet方法创建管理器。
gab6jxml2#
**Django已经改变了!**在使用2009年编写的答案中的代码之前,请务必查看其余的答案和Django文档,看看是否有更合适的解决方案。
我实现这一点的方法是添加实际的
get_active_for_account
作为自定义QuerySet
的方法。然后,要使它在管理器之外工作,您可以简单地捕获__getattr__
并相应地返回它为了使该模式可重用,我将
Manager
提取到一个单独的模型管理器中:custom_queryset/models.py
字符串
一旦你得到了这些,在你的模型上,你所需要做的就是定义一个
QuerySet
作为一个自定义的内部类,并将管理器设置为你的自定义管理器:your_app/models.py
型
使用此模式,以下任何一项都可以工作:
型
UPD如果您使用自定义用户(
AbstractUser
),则需要更改从
型
至
型
2nbm6dog3#
您可以使用mixin在管理器和查询集上提供方法。
这也避免了使用
__getattr__()
方法。字符串
oo7oh9g94#
现在可以在管理器上使用from_queryset()方法来更改其基础Queryset。
这允许您只定义一次Queryset方法和manager方法
从文档中
对于高级用法,您可能需要自定义Manager和自定义QuerySet。你可以通过调用Manager.from_queryset()来实现这一点,它会返回你的基Manager的一个子类,其中包含一个自定义QuerySet方法的副本:
字符串
kx1ctssn5#
基于
django 3.1.3
源代码,我找到了一个简单的解决方案字符串
cotxawn76#
T. Stone的方法:
字符串
类装饰器的用法很简单:
型
更新:支持非标准的Manager和QuerySet基类,例如。g. @objects_extra(django.contrib.gis.db.models.GeoManager,django.contrib.gis.db.models.query.GeoQuerySet):
型
pod7payv7#
在一些用例中,我们需要从管理器调用自定义QuerySet方法,而不是使用QuerySet的
get_manager
方法。一个mixin基于一个被接受的解决方案评论中发布的解决方案就足够了。
字符串
比如说,
型
有了上面的内容,我们可以像下面这样访问相关对象(Book),而无需在管理器中为每个查询集方法定义新方法。
型
rm5edbpk8#
下面的代码对我很有效。
字符串
这是在默认管理器上;所以我经常做这样的事
型
但没有理由不适合一个二级经理。