在 Django 中重用 filter() 查询集

Reuse filter() queryset in Django

我想写一个过滤器,到处复用,我该怎么做?

例如:有一个模型 Student 带有标志 field。我想写一个过滤器来获取非研究生(flag=0)。但是在很多view和function中我们需要list非研究生,我比较懒,不想在这些view和function中一遍又一遍的写filter,源码很难维护。

我可以在模型 Student 中使用元数据吗?我没有找到任何过滤器相关的元选项。或者我可以写一个函数来过滤模型 Student 吗?在我看来,模型中的函数只适用于一个学生对象而不是列表。

您可以使用自定义管理器来保持内容干燥并增强可读性(明确命名的过滤器总是比拖动复杂的过滤器更好)

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

使用自定义 QuerySet 和 QuerySet.as_manager() 是目前最好的解决方案。 Dabapps 的 Jamie Matthews 在他的博客 post Building a higher-level query API: the right way to use Django's ORM.

中详细讨论了可重复使用的过滤器

“Using Django's low-level ORM query methods directly in a view is (usually) an anti-pattern”
— Jamie Matthews

博客 post 是在 Django 获得 .as_manager() method for QuerySet 之前写的。

我现在会使用这样的东西(基于 ):

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()

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

如果您希望其他模型中的相关经理可以使用它(即,如果您有另一个模型引用 Student 模型并且正在使用 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