[Django] #23533: Hook for default QuerySet filtering defined on the QuerySet itself.

30 views
Skip to first unread message

Django

unread,
Sep 22, 2014, 2:39:24 AM9/22/14
to django-...@googlegroups.com
#23533: Hook for default QuerySet filtering defined on the QuerySet itself.
-------------------------------------+-------------------------------------
Reporter: loic | Owner: nobody
Type: New | Status: new
feature | Version: master
Component: Database | Keywords:
layer (models, ORM) | Has patch: 0
Severity: Normal | Needs tests: 0
Triage Stage: | Easy pickings: 0
Unreviewed |
Needs documentation: 0 |
Patch needs improvement: 0 |
UI/UX: 0 |
-------------------------------------+-------------------------------------
Django 1.7 brought managers automatically created from `QuerySet` which
replaces defining a custom manager for the purpose of defining reusable
methods. Refs #20625.

One use-case remains inelegant: using a custom `QuerySet` with default
`QuerySet` customization/filtering:

{{{
BaseCustomManager = Manager.from_queryset(CustomQueryset)

class CustomManager (BaseCustomManager ):
def get_queryset(self):
queryset = super(Manager, self).get_queryset()
return queryset.filter(...)
}}}

This ticket proposes adding a hook on `QuerySet` to enable this without
requiring a custom `Manager`.

--
Ticket URL: <https://code.djangoproject.com/ticket/23533>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

Django

unread,
Sep 22, 2014, 3:49:26 AM9/22/14
to django-...@googlegroups.com
#23533: Hook for default QuerySet filtering defined on the QuerySet itself.
-------------------------------------+-------------------------------------
Reporter: loic | Owner: nobody
Type: New feature | Status: new
Component: Database layer | Version: master
(models, ORM) | Resolution:
Severity: Normal | Triage Stage:
Keywords: | Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by loic):

It's worth noting that `QuerySet.__init__()` can't be used for providing
such initialization/customization:
- QuerySet are often cloned, and the customization should only ever apply
once.
- QuerySet methods return a cloned QuerySet instance and `__init__` can't
return a different instance.

So far the best option I can think of is a hook called externally by the
manager.

POC with a `QuerySet.get_initial_queryset()` method
https://github.com/loic/django/compare/ticket23533

--
Ticket URL: <https://code.djangoproject.com/ticket/23533#comment:1>

Django

unread,
Sep 23, 2014, 8:11:57 AM9/23/14
to django-...@googlegroups.com
#23533: Hook for default QuerySet filtering defined on the QuerySet itself.
-------------------------------------+-------------------------------------
Reporter: loic | Owner: nobody
Type: New feature | Status: new
Component: Database layer | Version: master
(models, ORM) | Resolution:
Severity: Normal | Triage Stage: Accepted
Keywords: | Needs documentation: 0
Has patch: 0 | Patch needs improvement: 0
Needs tests: 0 | UI/UX: 0
Easy pickings: 0 |
-------------------------------------+-------------------------------------
Changes (by timgraham):

* stage: Unreviewed => Accepted


--
Ticket URL: <https://code.djangoproject.com/ticket/23533#comment:2>

Django

unread,
Apr 6, 2024, 1:17:47 PM4/6/24
to django-...@googlegroups.com
#23533: Hook for default QuerySet filtering defined on the QuerySet itself.
-------------------------------------+-------------------------------------
Reporter: Loic Bistuer | Owner: Mariusz
| Felisiak
Type: New feature | Status: assigned
Component: Database layer | Version: dev
(models, ORM) |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Mariusz Felisiak):

* owner: nobody => Mariusz Felisiak
* status: new => assigned

--
Ticket URL: <https://code.djangoproject.com/ticket/23533#comment:3>

Django

unread,
Apr 6, 2024, 3:47:39 PM4/6/24
to django-...@googlegroups.com
#23533: Hook for default QuerySet filtering defined on the QuerySet itself.
-------------------------------------+-------------------------------------
Reporter: Loic Bistuer | Owner: Mariusz
| Felisiak
Type: New feature | Status: assigned
Component: Database layer | Version: dev
(models, ORM) |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Comment (by Simon Charette):

It'd be good to explore other implementations than that
`get_initial_queryset` hook as that bi-directionnaly couples Querysets
with managers (even more than the existing `as_manager` method) and
prevents reuse of the same queryset class for different managers of the
same model.

Approaches such as `CustomQueryset.as_manager(filter=Q(is_active=True))`
and `CustomQueryset.filter(is_active=True).as_manager()` (this would
require marking some methods `class_or_instance_method` at
`__init_subclass__` time to capture the calls and apply them at
`Manager.contribute_to_class` / app readyness time) seem more valuable as
they don't require overriding any methods.

In other words, the `get_initial_queryset` hook saves you from defining a
manager but you still have to define a method. It also ties your queryset
class to a single manager usage with seems wrong? What if you want to use
your custom queryset class with two different filters sets

{{{#!python
class FooQueryset(models.QuerySet):
def is_bar(self):
return self.filter(bar=True)

class FooBazQueryset(FooQueryset):
def get_initial_queryset(self):
return self.filter(baz=True)

class FooBatQueryset(FooQueryset):
def get_initial_queryset(self):
return self.filter(bat=True)

class Foo(models.Model):
bar = models.BooleanField()
baz = models.BooleanField()
bat = models.BooleanField()

objects = FooQueryset.as_manager()
baz_objects = FooBazQueryset.as_manager()
bat_objects = FooBatQueryset.as_manager()
}}}

Compare that with

{{{#!python
class FooQueryset(models.QuerySet):
def is_bar(self):
return self.filter(bar=True)

class Foo(models.Model):
bar = models.BooleanField()
baz = models.BooleanField()
bat = models.BooleanField()

objects = FooQueryset.as_manager()
baz_objects = FooQueryset.filter(baz=True).as_manager()
bat_objects = FooQueryset.filter(bat=True).as_manager()
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/23533#comment:4>

Django

unread,
Nov 27, 2025, 4:40:39 AM (3 days ago) Nov 27
to django-...@googlegroups.com
#23533: Hook for default QuerySet filtering defined on the QuerySet itself.
-------------------------------------+-------------------------------------
Reporter: Loic Bistuer | Owner: Mariusz
| Felisiak
Type: New feature | Status: assigned
Component: Database layer | Version: dev
(models, ORM) |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Comment (by Mariusz Felisiak):

Brilliant idea, thanks Simon. `QuerySet.filter()` already exist so I think
we should use a different name for a class method to avoid confusion,
maybe `QuerySet.init_filter()` or `QuerySet.initial_filter()`.
--
Ticket URL: <https://code.djangoproject.com/ticket/23533#comment:5>

Django

unread,
Nov 27, 2025, 4:52:31 AM (3 days ago) Nov 27
to django-...@googlegroups.com
#23533: Hook for default QuerySet filtering defined on the QuerySet itself.
-------------------------------------+-------------------------------------
Reporter: Loic Bistuer | Owner: Mariusz
| Felisiak
Type: New feature | Status: assigned
Component: Database layer | Version: dev
(models, ORM) |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Comment (by Mariusz Felisiak):

Replying to [comment:5 Mariusz Felisiak]:
> Brilliant idea, thanks Simon. `QuerySet.filter()` already exist so I
think we should use a different name for a class method to avoid
confusion, maybe `QuerySet.init_filter()` or `QuerySet.initial_filter()`.

Ah ok we can use `class_or_instance_method()` hook.
--
Ticket URL: <https://code.djangoproject.com/ticket/23533#comment:6>

Django

unread,
Nov 27, 2025, 5:53:18 AM (3 days ago) Nov 27
to django-...@googlegroups.com
#23533: Hook for default QuerySet filtering defined on the QuerySet itself.
-------------------------------------+-------------------------------------
Reporter: Loic Bistuer | Owner: Mariusz
| Felisiak
Type: New feature | Status: assigned
Component: Database layer | Version: dev
(models, ORM) |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Comment (by Mariusz Felisiak):

I've created a surprisingly small PoC that works for me. Simon, Can you
take a look?
--
Ticket URL: <https://code.djangoproject.com/ticket/23533#comment:7>

Django

unread,
Nov 27, 2025, 5:53:45 AM (3 days ago) Nov 27
to django-...@googlegroups.com
#23533: Hook for default QuerySet filtering defined on the QuerySet itself.
-------------------------------------+-------------------------------------
Reporter: Loic Bistuer | Owner: Mariusz
| Felisiak
Type: New feature | Status: assigned
Component: Database layer | Version: dev
(models, ORM) |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Mariusz Felisiak):

* Attachment "0001-Fixed-23533-Allow-defining-initial-filters-on-
QueryS.patch" added.

Django

unread,
Nov 27, 2025, 3:42:12 PM (3 days ago) Nov 27
to django-...@googlegroups.com
#23533: Hook for default QuerySet filtering defined on the QuerySet itself.
-------------------------------------+-------------------------------------
Reporter: Loic Bistuer | Owner: Mariusz
| Felisiak
Type: New feature | Status: assigned
Component: Database layer | Version: dev
(models, ORM) |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Simon Charette):

* cc: Simon Charette (added)

Comment:

I'll get to it this weekend, thanks for giving it a shot!
--
Ticket URL: <https://code.djangoproject.com/ticket/23533#comment:8>

Django

unread,
Nov 28, 2025, 4:17:38 AM (2 days ago) Nov 28
to django-...@googlegroups.com
#23533: Hook for default QuerySet filtering defined on the QuerySet itself.
-------------------------------------+-------------------------------------
Reporter: Loic Bistuer | Owner: Mariusz
| Felisiak
Type: New feature | Status: assigned
Component: Database layer | Version: dev
(models, ORM) |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 1
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Mariusz Felisiak):

* has_patch: 0 => 1
* needs_docs: 0 => 1

Comment:

[https://github.com/django/django/pull/20336 PR]
--
Ticket URL: <https://code.djangoproject.com/ticket/23533#comment:9>
Reply all
Reply to author
Forward
0 new messages