Simple annotation-based properties
The properties in this category are all Annotation-based properties, which means their getter
implementation will also perform a database query.
All of the listed properties therefore also take an additional cached argument in their initializer that allows
to mark individual properties as having a Cached getter.
This can improve performance since the query will only be executed on the first getter access at the cost of
potentially not working with an up-to-date value.
AnnotationProperty
The property class queryable_properties.properties.AnnotationProperty represents the most simple common
annotation-based property.
It can be instanciated using any annotation and will use that annotation both in queries as well as to provide its
getter value.
This, however, means that the AnnotationProperty is only intended to be used with static/fixed annotations without
any dynamic components as its objects are set up by passing the annotation to the initializer.
As an example, the version_str property from the annotation Implementation section could be
reduced to (not recommended):
from django.db.models import Model, Value
from django.db.models.functions import Concat
from queryable_properties.properties import AnnotationProperty
class ApplicationVersion(Model):
... # other fields/properties
version_str = AnnotationProperty(Concat('major', Value('.'), 'minor'))
Note
This example is only supposed to demonstrate how to set up an AnnotationProperty.
Implementing a Concat annotation like this is not recommended as even the getter will perform a query, even
though concatenating field values on the object level could simply be done without involving the database.
Arguments and supported features
Refer to the documentation of the AnnotationProperty initializer for a list of arguments:
__init__
AnnotationProperty offers the following queryable property features:
Feature |
Supported |
|---|---|
Getter |
✅ (all supported Django versions) |
Setter |
❌ |
Filtering |
✅ (all supported Django versions) |
Annotation |
✅ (all supported Django versions) |
Updating |
❌ |
AggregateProperty
django-queryable-properties also comes with a property class for simple aggregates that simply takes an aggregate
object and uses it for both queryset annotations as well as the getter.
This is therefore not entirely different from the AnnotationProperty class shown above.
The main difference between the two is that while AnnotationProperty uses QuerySet.annotate to query the getter
value, AggregateProperty uses QuerySet.aggregate, which is slightly more efficient.
Using AggregateProperty for aggregate annotations might also make code more clear/readable.
As an example, the Application model could receive a simple property that returns the number of versions like the
one in the Implementation section of annotation-based properties.
queryable_properties.properties.AggregateProperty allows to implement this in an even more condensed form:
from django.db.models import Count, Model
from queryable_properties.properties import AggregateProperty
class Application(Model):
... # other fields/properties
version_count = AggregateProperty(Count('versions'))
Note
Since this property deals with aggregates, the notes Regarding aggregate annotations across relations apply when using such properties across relations in querysets.
Arguments and supported features
Refer to the documentation of the AggregateProperty initializer for a list of arguments:
__init__
AggregateProperty offers the following queryable property features:
Feature |
Supported |
|---|---|
Getter |
✅ (all supported Django versions) |
Setter |
❌ |
Filtering |
✅ (all supported Django versions) |
Annotation |
✅ (all supported Django versions) |
Updating |
❌ |