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.
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 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. And I also want to have ability to chain QuerySet filters (for example 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.
I tested this with Python3 and Django1.10 cause that's the environment I have available right now. 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:
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.
If you do go with option #2, remember to clone the methods of your QuerySet onto your Manager or use a common 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()
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With