我有以下设置:

from django.db import models

class BaseInfoQuerySet(models.query.QuerySet):

    def public(self):
        return self.filter(public=True)

    def not_grouped(self):
        return self.filter(bu_group=True)


class BUManager(models.Manager):

    def get_queryset(self):
        return BaseInfoQuerySet(self.model, using=self._db).extra(
            select={'null_group': 'bu_group_id IS NULL'},
            order_by=['null_group'])


class BU(models.Model):
    # some field definitions

    # option 1 (preferred)
    objects = BaseInfoQuerySet.as_manager()
    # option 2
    objects = BUManager()

我正在使用Django 1.8和Python 2.7。

我想要实现的是能够使用# option 1,但是BaseInfoQuerySet中的所有方法都应该使用get_queryset()中经过修改的BUManagerBaseInfoQuerySet用作其他模型的多个查询集的基类,因此我不想摆脱它,而只使用models.Manager。而且我还希望能够链接QuerySet过滤器(例如BU.objects.public().not_grouped())。

我认为解决方案的方式是修改某种方法as_manager()以使用重写的Manager方法返回修改后的get_queryset

最佳答案

我使用Python3和Django1.10对此进行了测试,因为这是我现在可用的环境。让我知道是否需要更改以使其在您的环境中正常工作。

您可以在运行时在管理器实例上设置一个新的get_queryset方法,如下所示:

import types
from django.db import models

class BaseInfoQuerySet(models.query.QuerySet):

    def public(self):
        return self.filter(public=True)

    def not_grouped(self):
        return self.filter(bu_group=True)

    @classmethod
    def as_manager(cls):

        def get_queryset(self):
            return BaseInfoQuerySet(self.model, using=self._db).extra(
                select={'null_group': 'bu_group_id IS NULL'},
                order_by=['null_group'])

        manager = super(BaseInfoQuerySet, cls).as_manager()
        manager.get_queryset = types.MethodType(get_queryset, manager)
        return manager

但这对我来说似乎不必要地复杂。我终于同意了您的选择#2。

如果您确实选择了选项#2,请记住将QuerySet的方法克隆到Manager上或使用通用的mixin。

09-19 01:26