summaryrefslogtreecommitdiff
path: root/docs/ref/models
diff options
context:
space:
mode:
Diffstat (limited to 'docs/ref/models')
-rw-r--r--docs/ref/models/expressions.txt12
-rw-r--r--docs/ref/models/fields.txt33
2 files changed, 45 insertions, 0 deletions
diff --git a/docs/ref/models/expressions.txt b/docs/ref/models/expressions.txt
index b6512bff72..8879ee1a8f 100644
--- a/docs/ref/models/expressions.txt
+++ b/docs/ref/models/expressions.txt
@@ -37,6 +37,12 @@ determine the result's field type, such as complex expressions that mix field
types. For example, adding a ``DecimalField()`` and a ``FloatField()`` requires
an output field, like ``output_field=FloatField()``.
+``output_field`` also allows using custom fields that perform type conversions
+outside a specific model field context. For example, if you frequently need to
+perform date arithmetic with ``timedelta``, you can create a custom field that
+handles the conversion, ensuring consistent results across databases. See
+:doc:`/howto/custom-model-fields`.
+
Some examples
=============
@@ -559,6 +565,12 @@ available on other expressions. ``ExpressionWrapper`` is necessary when using
arithmetic on ``F()`` expressions with different types as described in
:ref:`using-f-with-annotations`.
+.. admonition:: Database casting not performed
+
+ ``ExpressionWrapper`` only sets the output field for the ORM and does not
+ perform any database-level casting. To ensure a specific type is returned
+ from the database, use :class:`~django.db.models.functions.Cast` instead.
+
Conditional expressions
-----------------------
diff --git a/docs/ref/models/fields.txt b/docs/ref/models/fields.txt
index de0b888f82..98efcf6b76 100644
--- a/docs/ref/models/fields.txt
+++ b/docs/ref/models/fields.txt
@@ -841,6 +841,39 @@ Any combination of these options will result in an error.
instance, removing its time component. This is true for both storage and
comparison.
+.. warning::
+
+ On PostgreSQL and MySQL, arithmetic operations on a ``DateField`` with a
+ :class:`~datetime.timedelta` return a ``datetime`` instead of a ``date``.
+ This occurs because Python's ``timedelta`` is converted to SQL
+ ``INTERVAL``, and the SQL operation ``date +/- interval`` returns a
+ ``timestamp`` on these databases.
+
+ To ensure a ``date`` result, use one of the following approaches. Either
+ explicitly cast the result to a date::
+
+ import datetime
+ from django.db.models import DateField, F
+ from django.db.models.functions import Cast
+
+ qs = MyModel.objects.annotate(
+ previous_day=Cast(
+ F("date_field") - datetime.timedelta(days=1),
+ output_field=DateField(),
+ )
+ )
+
+ Or on PostgreSQL only, use integer arithmetic to represent days::
+
+ from django.db.models import DateField, ExpressionWrapper, F
+
+ qs = MyModel.objects.annotate(
+ previous_day=ExpressionWrapper(
+ F("date_field") - 1, # Subtract 1 day as integer
+ output_field=DateField(),
+ )
+ )
+
``DateTimeField``
-----------------