简体   繁体   English

如果由QuerySet.as_manager()创建,则修改Django Manager get_queryset()方法

[英]Modify Django Manager get_queryset() method if created by QuerySet.as_manager()

I have following setup: 我有以下设置:

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

I'm using Django 1.8 and Python 2.7. 我正在使用Django 1.8和Python 2.7。

What I want to achieve is to be able to use # option 1 but all methods in BaseInfoQuerySet should use modified get_queryset() from BUManager . 我想要实现的是能够使用BaseInfoQuerySet # option 1BaseInfoQuerySet所有方法BaseInfoQuerySet应该使用来自BUManager修改后的get_queryset() BaseInfoQuerySet is used as base class on multiple querysets for other models, so I don't want to get rid of it and use only models.Manager . BaseInfoQuerySet用作其他模型的多个查询集的基类,因此我不想删除它并仅使用models.Manager And I also want to have ability to chain QuerySet filters (for example BU.objects.public().not_grouped() ). 我还希望能够链接QuerySet过滤器(例如BU.objects.public().not_grouped() )。

The way I see it the solution would be to modify somehow method as_manager() to return modified Manager with overriden get_queryset method. 我认为解决方案的方法是修改某种方法as_manager()以使用overriden get_queryset方法返回修改后的Manager

I tested this with Python3 and Django1.10 cause that's the environment I have available right now. 我用Python3和Django1.10测试了这个,因为这是我现在可用的环境。 Let me know if there's anything I should change to make it work in your environment. 让我知道是否有任何我应该改变以使其在您的环境中工作。

You could set a new get_queryset method on the manager instance at run time like this: 您可以在运行时在管理器实例上设置一个新的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

But that looks unnecessarily complex to me. 但这对我来说看起来不那么复杂。 I finally went with your option #2. 我终于选择了#2选项。

If you do go with option #2, remember to clone the methods of your QuerySet onto your Manager or use a common mixin. 如果您选择#2选项,请记住将QuerySet的方法克隆到Manager或使用常见的mixin。

Try this approach: 试试这种方法:

class BUManager(models.Manager.from_queryset(BaseInfoQuerySet)):
    def get_queryset(self):
        return super().get_queryset().extra(
            select={'null_group': 'bu_group_id IS NULL'},
            order_by=['null_group'])


class BU(models.Model):
    objects = BUManager()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM