在Django中,你可以为查询集添加一个方法吗?

Pau*_*ite 28 python django django-queryset

在Django中,如果我有一个模型类,例如

from django.db import models

class Transaction(models.Model):
    ...
Run Code Online (Sandbox Code Playgroud)

然后,如果我想向模型添加方法,存储例如相当复杂的过滤器,我可以添加自定义模型管理器,例如

class TransactionManager(models.Manager):

    def reasonably_complex_filter(self):
        return self.get_query_set().filter(...)


class Transaction(models.Model):
    objects = TransactionManager()
Run Code Online (Sandbox Code Playgroud)

然后我可以这样做:

>>> Transaction.objects.reasonably_complex_filter()
Run Code Online (Sandbox Code Playgroud)

有什么办法可以添加一个可以链接到模型查询集末尾的自定义方法吗?

即添加自定义方法,以便我可以这样做:

>>> Transaction.objects.filter(...).reasonably_complex_filter()
Run Code Online (Sandbox Code Playgroud)

Bur*_*lid 40

从django 1.7开始,添加了使用查询集作为管理器的能力:

class PersonQuerySet(models.QuerySet):
    def authors(self):
        return self.filter(role='A')

    def editors(self):
        return self.filter(role='E')

class Person(models.Model):
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)
    role = models.CharField(max_length=1, choices=(('A', _('Author')),
                                                   ('E', _('Editor'))))
    people = PersonQuerySet.as_manager()
Run Code Online (Sandbox Code Playgroud)

结果如下:

Person.people.authors(last_name='Dahl')
Run Code Online (Sandbox Code Playgroud)

此外,还添加了添加自定义查找的功能.


Dan*_*mov 15

这是一个完整的解决方案,已知在Django 1.3中工作,由Zach Smith和Ben提供.

class Entry(models.Model):
    objects = EntryManager() # don't forget this

    is_public = models.BooleanField()
    owner = models.ForeignKey(User)


class EntryManager(models.Manager):
    '''Use this class to define methods just on Entry.objects.'''
    def get_query_set(self):
        return EntryQuerySet(self.model)

    def __getattr__(self, name, *args):
        if name.startswith("_"): 
            raise AttributeError
        return getattr(self.get_query_set(), name, *args) 

    def get_stats(self):
        '''A sample custom Manager method.'''
        return { 'public_count': self.get_query_set().public().count() }


class EntryQuerySet(models.query.QuerySet):
    '''Use this class to define methods on queryset itself.'''
    def public(self):
        return self.filter(is_public=True)

    def by(self, owner):
        return self.filter(owner=owner)


stats = Entry.objects.get_stats()    
my_entries = Entry.objects.by(request.user).public()
Run Code Online (Sandbox Code Playgroud)

注意:get_query_set()方法现在在Django 1.6中已弃用 ; get_queryset()在这种情况下应该使用.


Mar*_*row 4

您需要添加QuerySet最终最终的方法.因此,您需要创建和使用一个QuerySet子类,该子类具有您在任何需要此功能的地方定义的方法.

我找到了这个教程,它解释了如何做到这一点以及你可能想要的原因:

http://adam.gomaa.us/blog/2009/feb/16/subclassing-django-querysets/index.html

  • 链接已经死了 (8认同)
  • 有一篇[更新的文章](http://zmsmith.com/2010/04/using-custom-django-querysets/),我发现稍微容易理解.请注意,注释中有一个修复,没有它的代码应该在1.2中断. (2认同)
  • 两个链接都失效了。这就是为什么答案不应该只是博客的链接。博客消失了。 (2认同)