Fixed #25534, Fixed #31639 -- Added support for transform references in expressions.

Thanks Mariusz Felisiak and Simon Charette for reviews.
This commit is contained in:
Ian Foote 2020-11-15 22:43:47 +00:00 committed by Mariusz Felisiak
parent e46ca51c24
commit 8b040e3cbb
14 changed files with 354 additions and 82 deletions

View file

@ -90,10 +90,10 @@ Built-in Expressions
.. class:: F
An ``F()`` object represents the value of a model field or annotated column. It
makes it possible to refer to model field values and perform database
operations using them without actually having to pull them out of the database
into Python memory.
An ``F()`` object represents the value of a model field, transformed value of a
model field, or annotated column. It makes it possible to refer to model field
values and perform database operations using them without actually having to
pull them out of the database into Python memory.
Instead, Django uses the ``F()`` object to generate an SQL expression that
describes the required operation at the database level.
@ -155,6 +155,10 @@ the field value of each one, and saving each one back to the database::
* getting the database, rather than Python, to do work
* reducing the number of queries some operations require
.. versionchanged:: 3.2
Support for transforms of the field was added.
.. _avoiding-race-conditions-using-f:
Avoiding race conditions using ``F()``
@ -406,9 +410,9 @@ The ``Aggregate`` API is as follows:
allows passing a ``distinct`` keyword argument. If set to ``False``
(default), ``TypeError`` is raised if ``distinct=True`` is passed.
The ``expressions`` positional arguments can include expressions or the names
of model fields. They will be converted to a string and used as the
``expressions`` placeholder within the ``template``.
The ``expressions`` positional arguments can include expressions, transforms of
the model field, or the names of model fields. They will be converted to a
string and used as the ``expressions`` placeholder within the ``template``.
The ``output_field`` argument requires a model field instance, like
``IntegerField()`` or ``BooleanField()``, into which Django will load the value
@ -435,6 +439,10 @@ and :ref:`filtering-on-annotations` for example usage.
The ``**extra`` kwargs are ``key=value`` pairs that can be interpolated
into the ``template`` attribute.
.. versionchanged:: 3.2
Support for transforms of the field was added.
Creating your own Aggregate Functions
-------------------------------------
@ -551,9 +559,9 @@ Referencing columns from the outer queryset
.. class:: OuterRef(field)
Use ``OuterRef`` when a queryset in a ``Subquery`` needs to refer to a field
from the outer query. It acts like an :class:`F` expression except that the
check to see if it refers to a valid field isn't made until the outer queryset
is resolved.
from the outer query or its transform. It acts like an :class:`F` expression
except that the check to see if it refers to a valid field isn't made until the
outer queryset is resolved.
Instances of ``OuterRef`` may be used in conjunction with nested instances
of ``Subquery`` to refer to a containing queryset that isn't the immediate
@ -562,6 +570,10 @@ parent. For example, this queryset would need to be within a nested pair of
>>> Book.objects.filter(author=OuterRef(OuterRef('pk')))
.. versionchanged:: 3.2
Support for transforms of the field was added.
Limiting a subquery to a single column
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View file

@ -3525,8 +3525,12 @@ All aggregates have the following parameters in common:
``expressions``
~~~~~~~~~~~~~~~
Strings that reference fields on the model, or :doc:`query expressions
</ref/models/expressions>`.
Strings that reference fields on the model, transforms of the field, or
:doc:`query expressions </ref/models/expressions>`.
.. versionchanged:: 3.2
Support for transforms of the field was added.
``output_field``
~~~~~~~~~~~~~~~~

View file

@ -351,6 +351,11 @@ Models
* Added the :class:`~django.db.models.functions.Random` database function.
* :ref:`aggregation-functions`, :class:`F() <django.db.models.F>`,
:class:`OuterRef() <django.db.models.OuterRef>`, and other expressions now
allow using transforms. See :ref:`using-transforms-in-expressions` for
details.
Pagination
~~~~~~~~~~

View file

@ -669,6 +669,36 @@ The ``F()`` objects support bitwise operations by ``.bitand()``, ``.bitor()``,
Support for ``.bitxor()`` was added.
.. _using-transforms-in-expressions:
Expressions can reference transforms
------------------------------------
.. versionadded: 3.2
Django supports using transforms in expressions.
For example, to find all ``Entry`` objects published in the same year as they
were last modified::
>>> Entry.objects.filter(pub_date__year=F('mod_date__year'))
To find the earliest year an entry was published, we can issue the query::
>>> Entry.objects.aggregate(first_published_year=Min('pub_date__year'))
This example finds the value of the highest rated entry and the total number
of comments on all entries for each year::
>>> Entry.objects.values('pub_date__year').annotate(
... top_rating=Subquery(
... Entry.objects.filter(
... pub_date__year=OuterRef('pub_date__year'),
... ).order_by('-rating').values('rating')[:1]
... ),
... total_comments=Sum('number_of_comments'),
... )
The ``pk`` lookup shortcut
--------------------------