FlexQuery class provides a decorator for functions declared on a custom
from django_flexquery import FlexQuery, Manager, Q, QuerySet # It's crucial to inherit from the QuerySet class of django_flexquery, because # the FlexQuery's wouldn't make it over to a Manager derived using as_manager() # with the stock Django implementation. That's the only difference however. class FruitQuerySet(QuerySet): # Declare a function that generates a Q object. # base is a copy of the base QuerySet instance. It's not needed most of # the time unless you want to embed a sub-query based on the current QuerySet # into the Q object. @FlexQuery.from_func def large(base): return Q(size__gte=10)
FruitQuerySet.large now is a sub-type of
FlexQuery encapsulating the custom
You can then derive a
FruitQuerySet in two ways, using the
known Django API:
# Either use from_queryset() of the Manager class provided with this module. class FruitManager(Manager.from_queryset(FruitQuerySet)): ... # Or, if you don't want to add additional manager-only methods, create a Manager # instance inside your model definition straight away. class Fruit(Model): objects = FruitQuerySet.as_manager() ...
When we assume such a
Manager being the default manager of a
size field, we can now perform the following queries:
Internally, this is made possible by some metaclass and descriptor magic instantiating
FlexQuery type whenever it is accessed as class attribute of a
QuerySet object. The resulting
FlexQuery instance will be tied to its
owner and use that for all its filtering.
FlexQuery instance is directly callable (
Fruit.objects.large()), which just
applies the filters returned by our custom Q function to the base
is a well-known usage pattern you might have come across often when writing custom
Django model managers or querysets.
FlexQuery also comes with an
as_q() method, which lets you access the
Q object directly (
FlexQuery can mediate between these two and deliver what you need in your
Providing a standalone
QuerySet filtered by the
Q from a supplied
function is a cheap operation. The
Q object generated by your custom function is
simply applied to the base using
QuerySet.filter(), resulting in a new
you may either evaluate straight away or use to create a sub-query.
Why do I Need This?¶
This approach enables you to declare logic for filtering once with the
QuerySet of the model it belongs to. When combined with the prefix() method
of the extended Q object implementation, related models can then simply fetch the
generated Q object and prefix it with the related field’s name in order to reuse it
in their own filtering code, without needing sub-queries. Think of something like:
class TreeQuerySet(QuerySet): @FlexQuery.from_func def having_ripe_apples(base): return Q(kind="apple") & Fruid.objects.large.as_q().prefix("fruits")
This module provides a convenient way to declare custom filtering logic with Django’s model managers in a reusable fashion using Q objects.
Flexibly provides model-specific query constraints as an attribute of Manager or QuerySet objects.
When a sub-type of FlexQuery is accessed as class attribute of a Manager or QuerySet object, its metaclass, which is implemented as a descriptor, will automatically initialize and return an instance of the FlexQuery type bound to the holding Manager or QuerySet.
Filters the base queryset using the provided function, relaying arguments.
- Returns QuerySet
Returns the result of the configured function, relaying arguments.
- Returns Q
Calls the provided function with
self.base.all()as first argument.
This may be overwritten if arguments need to be preprocessed in some way before being passed to the custom function.
- Returns Q
FlexQuerysub-type from a function.
This classmethod can be used as decorator. As long as
functools.partialwith the given keyword arguments is returned.
func (function | None) – function taking a base
QuerySetand returning a
attrs – additional attributes to set on the newly created type
- Returns InitializedFlexQueryType | functools.partial
TypeError – if
funcis no function
Use this class’
from_querysetmethod if you want to derive a
FlexQuerymembers. If Django’s native
Manager.from_querysetwas used instead, those members would be lost.
QuerySet(model=None, query=None, using=None, hints=None)¶
Adds support for deriving a