summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorMariusz Felisiak <felisiak.mariusz@gmail.com>2025-10-18 15:03:50 +0200
committerGitHub <noreply@github.com>2025-10-18 15:03:50 +0200
commit0c487aa3a7b2417481bf48c1e5355c855873e210 (patch)
tree33b92a3bdf11f66d0f67fe4b4338084c7028c709 /docs
parentb1e0262c9f9d11eae6230b51c5aa5d71122d5f05 (diff)
Fixed #21961 -- Added support for database-level delete options for ForeignKey.
Thanks Simon Charette for pair programming. Co-authored-by: Nick Stefan <NickStefan12@gmail.com> Co-authored-by: Akash Kumar Sen <71623442+Akash-Kumar-Sen@users.noreply.github.com> Co-authored-by: Simon Charette <charette.s@gmail.com>
Diffstat (limited to 'docs')
-rw-r--r--docs/ref/checks.txt16
-rw-r--r--docs/ref/models/fields.txt53
-rw-r--r--docs/ref/models/instances.txt10
-rw-r--r--docs/ref/models/querysets.txt29
-rw-r--r--docs/releases/6.1.txt15
5 files changed, 105 insertions, 18 deletions
diff --git a/docs/ref/checks.txt b/docs/ref/checks.txt
index 7735eed478..c297938f45 100644
--- a/docs/ref/checks.txt
+++ b/docs/ref/checks.txt
@@ -299,9 +299,15 @@ Related fields
referenced by a ``ForeignKey``.
* **fields.E312**: The ``to_field`` ``<field name>`` doesn't exist on the
related model ``<app label>.<model>``.
-* **fields.E320**: Field specifies ``on_delete=SET_NULL``, but cannot be null.
-* **fields.E321**: The field specifies ``on_delete=SET_DEFAULT``, but has no
- default value.
+* **fields.E320**: Field specifies ``on_delete=<set null option>``, but cannot
+ be null.
+* **fields.E321**: Field specifies ``on_delete=SET_DEFAULT``, but has no
+ ``default`` value.
+* **fields.E322**: Field specifies ``on_delete=DB_SET_DEFAULT``, but has no
+ ``db_default`` value.
+* **fields.E323**: Field specifies database/Python-level on_delete variant, but
+ referenced model uses python/database-level variant.
+* **fields.E324**: ``<database>`` does not support ``DB_SET_DEFAULT``.
* **fields.E330**: ``ManyToManyField``\s cannot be unique.
* **fields.E331**: Field specifies a many-to-many relation through model
``<model>``, which has not been installed.
@@ -446,6 +452,8 @@ Models
* **models.E049**: ``constraints/indexes/unique_together`` refers to a
``ForeignObject`` ``<field name>`` with multiple ``from_fields``, which is
not supported for that option.
+* **models.E050**: The model cannot have related fields with both
+ database-level and Python-level ``on_delete`` variants.
Management Commands
-------------------
@@ -921,6 +929,8 @@ The following checks are performed when a model contains a
* **contenttypes.E004**: ``<field>`` is not a ``ForeignKey`` to
``contenttypes.ContentType``.
* **contenttypes.E005**: Model names must be at most 100 characters.
+* **contenttypes.E006**: ``<field>`` cannot use the database-level
+ ``on_delete`` variant.
``postgres``
------------
diff --git a/docs/ref/models/fields.txt b/docs/ref/models/fields.txt
index 5988d5dc06..0b62143cc0 100644
--- a/docs/ref/models/fields.txt
+++ b/docs/ref/models/fields.txt
@@ -1699,11 +1699,11 @@ relation works.
.. attribute:: ForeignKey.on_delete
- When an object referenced by a :class:`ForeignKey` is deleted, Django will
- emulate the behavior of the SQL constraint specified by the
- :attr:`on_delete` argument. For example, if you have a nullable
- :class:`ForeignKey` and you want it to be set null when the referenced
- object is deleted::
+ When an object referenced by a :class:`ForeignKey` is deleted, the
+ referring objects need updating. The :attr:`on_delete` argument specifies
+ how this is done, and whether Django or your database makes the updates.
+ For example, if you have a nullable :class:`ForeignKey` and you want Django
+ to set it to ``None`` when the referenced object is deleted::
user = models.ForeignKey(
User,
@@ -1712,8 +1712,21 @@ relation works.
null=True,
)
- ``on_delete`` doesn't create an SQL constraint in the database. Support for
- database-level cascade options :ticket:`may be implemented later <21961>`.
+ The possible values for :attr:`~ForeignKey.on_delete` are listed below.
+ Import them from :mod:`django.db.models`. The ``DB_*`` variants use the
+ database to prevent deletions or update referring objects, whilst the other
+ values make Django perform the relevant actions.
+
+ The database variants are more efficient because they avoid fetching
+ related objects, but ``pre_delete`` and ``post_delete`` signals won't be
+ sent when ``DB_CASCADE`` is used.
+
+ The database variants cannot be mixed with Python variants (other than
+ :attr:`DO_NOTHING`) in the same model and in models related to each other.
+
+.. versionchanged:: 6.1
+
+ Support for ``DB_*`` variants of the ``on_delete`` attribute was added.
The possible values for :attr:`~ForeignKey.on_delete` are found in
:mod:`django.db.models`:
@@ -1729,6 +1742,13 @@ The possible values for :attr:`~ForeignKey.on_delete` are found in
:data:`~django.db.models.signals.post_delete` signals are sent for all
deleted objects.
+* .. attribute:: DB_CASCADE
+
+ .. versionadded:: 6.1
+
+ Cascade deletes. Database-level version of :attr:`CASCADE`: the database
+ deletes referred-to rows and the one containing the ``ForeignKey``.
+
* .. attribute:: PROTECT
Prevent deletion of the referenced object by raising
@@ -1782,11 +1802,30 @@ The possible values for :attr:`~ForeignKey.on_delete` are found in
Set the :class:`ForeignKey` null; this is only possible if
:attr:`~Field.null` is ``True``.
+* .. attribute:: DB_SET_NULL
+
+ .. versionadded:: 6.1
+
+ Set the :class:`ForeignKey` value to ``NULL``. This is only possible if
+ :attr:`~Field.null` is ``True``. Database-level version of
+ :attr:`SET_NULL`.
+
* .. attribute:: SET_DEFAULT
Set the :class:`ForeignKey` to its default value; a default for the
:class:`ForeignKey` must be set.
+* .. attribute:: DB_SET_DEFAULT
+
+ .. versionadded:: 6.1
+
+ Set the :class:`ForeignKey` value to its :attr:`Field.db_default` value,
+ which must be set. If a row in the referenced table is deleted, the foreign
+ key values in the referencing table will be updated to their
+ :attr:`Field.db_default` values.
+
+ ``DB_SET_DEFAULT`` is not supported on MySQL and MariaDB.
+
* .. function:: SET()
Set the :class:`ForeignKey` to the value passed to
diff --git a/docs/ref/models/instances.txt b/docs/ref/models/instances.txt
index 2ce8dc4a36..a8be767aaf 100644
--- a/docs/ref/models/instances.txt
+++ b/docs/ref/models/instances.txt
@@ -695,7 +695,11 @@ Issues an SQL ``DELETE`` for the object. This only deletes the object in the
database; the Python instance will still exist and will still have data in
its fields, except for the primary key set to ``None``. This method returns the
number of objects deleted and a dictionary with the number of deletions per
-object type.
+object type. The return value will count instances from related models if
+Django is emulating cascade behavior via Python :attr:`~ForeignKey.on_delete`
+variants. Otherwise, for database variants such as
+:attr:`~django.db.models.DB_CASCADE`, the return value will report only
+instances of the :class:`.QuerySet`'s model.
For more details, including how to delete objects in bulk, see
:ref:`topics-db-queries-delete`.
@@ -707,6 +711,10 @@ Sometimes with :ref:`multi-table inheritance <multi-table-inheritance>` you may
want to delete only a child model's data. Specifying ``keep_parents=True`` will
keep the parent model's data.
+.. versionchanged:: 6.1
+
+ Support for the ``DB_*`` variants of ``on_delete`` attribute was added.
+
Pickling objects
================
diff --git a/docs/ref/models/querysets.txt b/docs/ref/models/querysets.txt
index 3840a2f97e..164bc9ce54 100644
--- a/docs/ref/models/querysets.txt
+++ b/docs/ref/models/querysets.txt
@@ -3036,7 +3036,11 @@ unique field in the order that is specified without conflicts. For example::
Performs an SQL delete query on all rows in the :class:`.QuerySet` and
returns the number of objects deleted and a dictionary with the number of
-deletions per object type.
+deletions per object type. The return value will count instances from related
+models if Django is emulating cascade behavior via Python
+:attr:`~django.db.models.ForeignKey.on_delete` variants. Otherwise, for
+database variants such as :attr:`~django.db.models.DB_CASCADE`, the return
+value will report only instances of the :class:`.QuerySet`'s model.
The ``delete()`` is applied instantly. You cannot call ``delete()`` on a
:class:`.QuerySet` that has had a slice taken or can otherwise no longer be
@@ -3073,13 +3077,20 @@ The ``delete()`` method does a bulk delete and does not call any ``delete()``
methods on your models. It does, however, emit the
:data:`~django.db.models.signals.pre_delete` and
:data:`~django.db.models.signals.post_delete` signals for all deleted objects
-(including cascaded deletions).
+(including cascaded deletions). Signals won't be sent when ``DB_CASCADE`` is
+used. Also, ``delete()`` doesn't return information about objects deleted from
+database variants (``DB_*``) of the
+:attr:`~django.db.models.ForeignKey.on_delete` argument, e.g. ``DB_CASCADE``.
-Django needs to fetch objects into memory to send signals and handle cascades.
-However, if there are no cascades and no signals, then Django may take a
-fast-path and delete objects without fetching into memory. For large
-deletes this can result in significantly reduced memory usage. The amount of
-executed queries can be reduced, too.
+Django won’t need to fetch objects into memory when deleting them in the
+following cases:
+
+#. If related fields use ``DB_*`` options.
+#. If there are no cascades and no delete signal receivers.
+
+In these cases, Django may take a fast path and delete objects without fetching
+them, which can result in significantly reduced memory usage and fewer executed
+queries.
ForeignKeys which are set to :attr:`~django.db.models.ForeignKey.on_delete`
``DO_NOTHING`` do not prevent taking the fast-path in deletion.
@@ -3087,6 +3098,10 @@ ForeignKeys which are set to :attr:`~django.db.models.ForeignKey.on_delete`
Note that the queries generated in object deletion is an implementation
detail subject to change.
+.. versionchanged:: 6.1
+
+ Support for the ``DB_*`` variants of ``on_delete`` attribute was added.
+
``as_manager()``
~~~~~~~~~~~~~~~~
diff --git a/docs/releases/6.1.txt b/docs/releases/6.1.txt
index 80470dbcd6..d199423176 100644
--- a/docs/releases/6.1.txt
+++ b/docs/releases/6.1.txt
@@ -71,6 +71,21 @@ queries:
See :doc:`fetch modes </topics/db/fetch-modes>` for more details.
+Database-level delete options for ``ForeignKey.on_delete``
+----------------------------------------------------------
+
+:attr:`.ForeignKey.on_delete` now supports database-level delete options:
+
+* :attr:`~django.db.models.DB_CASCADE`
+* :attr:`~django.db.models.DB_SET_NULL`
+* :attr:`~django.db.models.DB_SET_DEFAULT`
+
+These options handle deletion logic entirely within the database, using the SQL
+``ON DELETE`` clause. They are thus more efficient than the existing
+Python-level options, as Django does not need to load objects before deleting
+them. As a consequence, the :attr:`~django.db.models.DB_CASCADE` option does
+not trigger the ``pre_delete`` or ``post_delete`` signals.
+
Minor features
--------------