在已经过滤的查询集上使用Django自定义管理器功能

时间:2011-04-28 09:07:13

标签: django django-queryset django-managers

考虑以下情况:

class MyModelManager(models.Manager):
    def my_filter(self):
     return [some code here].filter(field_A__gt=3)

class MyModel(models.Model):
    # some fields
    objects = MyModelManager()


# The way I'd like to use it:
qs = MyModel.objects.filter(field_B__lt=1)
# some code
qs = qs.my_filter()

请注意,我想在已过滤的查询集上使用自定义my_filter()函数。我应该在[some code here]上面放置什么代码?整个结构是否正确?

3 个答案:

答案 0 :(得分:2)

我想没有办法这样做。     MyModel.objects.filter(field_B__lt = 1) 将返回QuerySet对象,而不是MyModelManager。 您可以将其传递给my_filter方法,如Ignacio Vazquez-Abrams所述,或者首先将my_filter应用于您的经理,这将返回QuerySet对象,您可以进一步过滤

答案 1 :(得分:1)

您的方法是错误的,因为您只能在从数据库中检索数据时使用Model.Manager,因此使用两个管理器或尝试在查询集上使用管理器会导致错误。

data = SomeModel.objects.my_manager.all()

data = SomeModel.objects.all()
data = data.my_manager.filter(...)

是错误的,因为你不能使用两个经理......

一种可能的方法是定义一个函数,该函数将查询集作为参数并返回已过滤的查询集...

def extra_filter(queryset):
    queryset = queryset.filter(...)

但我不确定这是否有帮助。

最佳方法是定义另一个模型管理器,并在需要时使用对象的instread ...

class SomeManager(models.Manager):
    def get_query_set(self):
        return super(SomeManager, self).get_query_set().filter(<filteer criteria>)

class MyModel(models.Model):
    # some fields
    objects = models.Manager()
    mymanager = SomeManager()

data = MyModel.mymanager.all() 

只使用一个......

更新:在django中,查询集是懒惰的。这意味着,您可以根据需要应用尽可能多的过滤器,并且无法从数据库中检索数据,因为您尝试从过滤中获取特定记录,或者您尝试对其进行切片... Documentation is here

所以,

之间没有差异
qs = MyModel.objects.filter(field_B__lt=1)
qs = qs.filter(field_A__gt=3)

qs = MyModel.objects.filter(field_A__gt=3)
qs = qs.filter(field_B__lt=1)

因此,定义经理应用特定过滤是使用经理的主要原因...

您定义了经理:

class SomeManager(models.Manager):
    def get_query_set(self):
        return super(SomeManager, self).get_query_set().filter(field_A__gt=3)

然后用其他过滤条件调用它:

Somemodel.mymodelmanager.filter(field_B__lt=1, ....)

django会添加所有过滤器并在您希望的时候浏览查询。

因此,如果它是您经常使用的过滤器,那么经理我是最好的选择......

例如,我在大多数数据库模型中都有有效 _字段,而 val 管理器则过滤了无效条目。所以当我希望过滤所有有效数据(90%的时间)时,我使用

Somemodel.val.filter(...)

在我需要所有数据的情况下,我只使用基本的django管理器:

Somemodel.objects.filter(...)

答案 2 :(得分:0)

class MyModelManager(models.Manager):
    def my_filter(self, qs=None):
        if qs is None:
            qs = [however you got it before]
        return qs.filter(field_A__gt=3)

然后将您的查询集传递给它。