在Django中重用filter()queryset

时间:2015-06-05 02:05:19

标签: python django django-queryset

我想编写一次过滤器并在任何地方重复使用,我该怎么办?

例如:有一个标有Student的模型field。我想写一个过滤器来获得非研究生(flag=0)。但是在许多视图和函数中,我们需要列出非研究生,我很懒,不想在这些视图和函数中反复编写过滤器,因为这会使维护源代码变得困难。

我可以在模特学生中使用meta吗?我没有找到任何与过滤器相关的元选项。或者我可以编写一个函数来过滤模型学生吗?在我看来,模型中的函数只能在一个Student对象而不是list中工作。

2 个答案:

答案 0 :(得分:3)

您可以使用自定义管理器来保持DRY并提高可读性(明确命名的过滤器总是比拖动复杂的过滤器更好)

class GraduateManager(models.Manager):
    def get_queryset(self):
        return super(GraduateManager, self).get_queryset().filter(graduated=True)

class UndergraduateManager(models.Manager):
    def get_queryset(self):
        return super(Undergraduate, self).get_queryset().filter(graduated=False)

class Student(models.Model):
    graduated = BooleanField()

    graduates = GraduateManager()
    undergraduates = UndergraduateManager()

要使用它,您将获得一个可以根据需要操作的普通查询集

Student.graduates.all(), or .filter(), or .count() etc

参考https://docs.djangoproject.com/en/1.8/topics/db/managers/#modifying-initial-manager-querysets

答案 1 :(得分:2)

现在使用自定义QuerySet和QuerySet.as_manager()是最佳解决方案。 Dabapps的Jamie Matthews在他的博文Building a higher-level query API: the right way to use Django's ORM中详细讨论了可重复使用的过滤器。

  

“直接在视图中使用Django的低级ORM查询方法(通常)是一种反模式”
   - 杰米马修斯

博客文章是在Django为QuerySet获取.as_manager() method之前编写的。

我现在使用这样的东西(基于currently accepted answer):

class StudentQuerySet(models.query.QuerySet):
    def graduate(self):
        return self.filter(graduated=True)

    def undergraduate(self):
        return self.filter(graduated=False)

class Student(models.Model):
    graduated = BooleanField()

    objects = StudentQuerySet.as_manager()

在其他更复杂的情况下,能够在自定义查询集中定义复杂过滤器非常有用,因为过滤器在实现时可以链接。

如果您希望其他模型中的相关管理员可以使用此功能(例如,如果您有其他模型引用学生模型并使用otherinstance.student_set.all()),请参阅Django: Using managers for related object access。简而言之,这样做:

class Student(models.Model):
    graduated = BooleanField()

    objects = StudentQuerySet.as_manager()
    objects.use_for_related_fields = True