Package: django-predicate
Notice2022-04-27: This library is currently unmaintained, since I no longer use Django. If there is any interest, I’m still happy to review pull requests and consider adding maintainers. - @lucaswimandjango-predicatedjango-predicate provides a Q like object to facilitate the question: “would
this model instance be part of a query” but without running the query or even
saving the object.QuickstartInstall django-predicate:pip install django-predicateThen use thePobject just as you wouldQobjects:frompredicateimportPp=P(some_field__startswith="hello",age__gt=20)You can then call theevalmethod with a model instance to check whether it
passes the conditions:model_instance = MyModel(some_field="hello there", age=21)
other_model_instance = MyModel(some_field="hello there", age=10)
p.eval(model_instance)>>>Truep.eval(other_model_instance)>>>Falseor you can use Python’sinoperator.model_instance in p>>>TrueEven though a predicate is not a true container class - it can be used as (and
was designed as being) a virtual “set” of objects that meets some condiiton.Like Q objects, P objects can be&’ed  and|’ed together to form more
complex logic groupings.In fact, P objects are actually a subclass of Q objects, so you can use them in
queryset filter statements:qs=MyModel.objects.filter(p)P objects also supportQuerySet-like filtering operations that can be
applied to an arbitrary iterable:P.get(iterable),P.filter(iterable),
andP.exclude(iterable):model_instance = MyModel(some_field="hello there", age=21)
other_model_instance = MyModel(some_field="hello there", age=10)
p.filter([model_instance, other_model_instance]) == [model_instance]>>>Truep.get([model_instance, other_model_instance]) == model_instance>>>Truep.exclude([model_instance, other_model_instance]) == [other_model_instance]>>>TrueIf you have a situation where you want to use querysets and predicates based on
the same conditions, it is far better to start with the predicate. Because of
the way querysets assume a SQL context, it is non-trivial to reverse engineer
them back into a predicate. However as seen above, it is very straightforward
to create a queryset based on a predicate.DevelopmentThese instructions assume you have Postgres installed and all referenced Python versions installed and activated, e.g. with Pyenv.To run the tests locally, do the following:Clone this repo.Start Postgres in the background for the Postgres tests withpostgres-D~/postgres.Activate all tested Python versions used in this repo:pyenv local 3.6 3.7 3.10.(Optional) Create a virtualenv and activate it:python-mvenv .venv,source .venv/bin/activate.(Optional) Upgrade pip to prevent platform issuespip install--upgradepipInstall Tox for running tests:pip install tox.Run all tests by issuing commandtoxwith no arguments.Changelog2.0.1Added support for Python 3.7 and 3.10, and Django 2.2, 3.2, and 4.1 (seetox.inifor compatible Python/Django version tuples).Converted test runner from Nose to Pytest.BREAKINGDropped support for Python 2.7, Python 3.5, and Django 1.9.2.0.0 (Unreleased)This version was pushed to Master but was not pushed to PyPI.Added deprecation warning to README.Added Travis CI config.BREAKINGDropped support for Django 1.7 and 1.8.1.4.0This version and below aren’t covered in this changelog.