在Django中,可以向querysets添加方法吗?
在Django中,如果我有一个模型类,比如说:
from django.db import models
class Transaction(models.Model):
...
那么如果我想给这个模型添加一些方法,比如存储一些比较复杂的筛选条件,我可以添加一个自定义的模型管理器,比如:
class TransactionManager(models.Manager):
def reasonably_complex_filter(self):
return self.get_query_set().filter(...)
class Transaction(models.Model):
objects = TransactionManager()
然后我就可以这样做:
>>> Transaction.objects.reasonably_complex_filter()
有没有什么方法可以让我添加一个自定义的方法,这个方法可以接在模型的查询集后面?
也就是说,我想以这样的方式添加自定义方法,这样我就可以这样做:
>>> Transaction.objects.filter(...).reasonably_complex_filter()
7 个回答
16
这是一个完整的解决方案,适用于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()
注意:在Django 1.6中,get_query_set()
这个方法已经不再推荐使用了;在这种情况下,应该使用get_queryset()
。
46
从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()
这就产生了以下效果:
Person.people.authors(last_name='Dahl')
另外,还新增了一个功能,可以添加自定义查找。
4
你需要给最终得到的 QuerySet
添加一些方法。所以,你需要创建一个 QuerySet
的子类,并在你想要这个功能的地方使用它,这样就能包含你定义的方法。
我找到了一篇教程,里面解释了怎么做以及你可能想这么做的原因: