3

I have a QuerySetMixin in a model manager:

models.py:

class MyModel(models.Model):
    objects = SoftDeletableManager()

managers.py:

class SoftDeletableManager(SoftDeletableManagerMixin, models.Manager):
    pass

class SoftDeletableQuerySet(QuerySet):
    pass

class SoftDeletableManagerMixin:
    _queryset_class = SoftDeletableQuerySet

    def get_queryset(self):
         return self._queryset_class(
             model=self.model, 
             using=self._db,
             **kwargs).filter(is_removed=False)

I want to define a second QuerySetMixin that inheits the results of the SoftDeletableManagerMixin and filters them. How do I do this?

E.g.

class MyManagerMixin:

    def get_queryset(self):
        return self.[inherit other querysets].filter(mynewfilter=True)
alias51
  • 8,178
  • 22
  • 94
  • 166

1 Answers1

1

If you inherit it, you might want to use the super() proxy object:

class SoftDeletableManagerMixin:
    _queryset_class = SoftDeletableQuerySet

    def get_queryset(self):
         return super().get_queryset().filter(is_removed=False)

the same for your second mixin:

class MyManagerMixin:

    def get_queryset(self):
        return super().get_queryset().filter(mynewfilter=True)

You can then make a manager with:

class MyNewManager(MyManagerMixin, SoftDeletableManagerMixin, Manager):
    pass
Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
  • Thanks. In this example wouldn't `super()` override the `_queryset_class`? – alias51 Jan 08 '20 at 11:05
  • 1
    @alias51: no. The method will simply fetch the `._queryset_class` attribute. Since the MRO will put `SoftDeletableManagerMixin` before the `Manager`, it will thus resolve to `SoftDeletableQuerySet`. – Willem Van Onsem Jan 08 '20 at 11:08
  • Is there a reason why the Django source code doesn't use this method? It would seem a lot simpler (https://github.com/django/django/blob/master/django/db/models/manager.py#L139) – alias51 Jan 08 '20 at 11:30
  • 1
    @alias51: because that is the first time it defines `get_queryset`, so there is no `get_queryset` method yet in the `super()` proxy :) – Willem Van Onsem Jan 08 '20 at 11:31
  • Yes, not enough coffee!! How would I filter on `self.request.user` in a Manger mixin? Is this possible as `def get_queryset(self)` doesn't return an object with attribute `request`...? – alias51 Jan 08 '20 at 12:00
  • 1
    @alias51: no, managers are "request-unaware". You can of course make a method in your manager/queryset that takes a parameter for the request. But you can use models/managers/... without a request (for example a management task), and thus there is not *per se* even a request. – Willem Van Onsem Jan 08 '20 at 12:05
  • Where would I pull the `request` from? Is there a method for `self` under `get_queryset`? – alias51 Jan 08 '20 at 12:17
  • @alias51: no, you could for example make an extra method `def extra_filtering(self, request): ...`. – Willem Van Onsem Jan 08 '20 at 12:19