From 65f3cfce59395131f318cf1ecba144530ed6609e Mon Sep 17 00:00:00 2001 From: Clifford Gama <53076065+cliff688@users.noreply.github.com> Date: Thu, 17 Oct 2024 16:39:40 +0200 Subject: [PATCH] Fixed #26322 -- Consolidated lazy relationships details in docs/ref/models/fields.txt. Reorganized docs to list and explain the types of lazy relationships that can be defined in related fields. Co-authored-by: Natalia <124304+nessita@users.noreply.github.com> --- docs/ref/models/fields.txt | 195 ++++++++++++++++++++++++------------- 1 file changed, 127 insertions(+), 68 deletions(-) diff --git a/docs/ref/models/fields.txt b/docs/ref/models/fields.txt index 899947c17f..febb45108d 100644 --- a/docs/ref/models/fields.txt +++ b/docs/ref/models/fields.txt @@ -1628,80 +1628,25 @@ Django also defines a set of fields that represent relations. .. class:: ForeignKey(to, on_delete, **options) A many-to-one relationship. Requires two positional arguments: the class to -which the model is related and the :attr:`~ForeignKey.on_delete` option. - -.. _recursive-relationships: - -To create a recursive relationship -- an object that has a many-to-one -relationship with itself -- use ``models.ForeignKey('self', -on_delete=models.CASCADE)``. - -.. _lazy-relationships: - -If you need to create a relationship on a model that has not yet been defined, -you can use the name of the model, rather than the model object itself:: +which the model is related and the :attr:`~ForeignKey.on_delete` option:: from django.db import models - class Car(models.Model): - manufacturer = models.ForeignKey( - "Manufacturer", - on_delete=models.CASCADE, - ) - # ... - - class Manufacturer(models.Model): - # ... - pass + name = models.TextField() -Relationships defined this way on :ref:`abstract models -` are resolved when the model is subclassed as a -concrete model and are not relative to the abstract model's ``app_label``: - -.. code-block:: python - :caption: ``products/models.py`` - - from django.db import models - - - class AbstractCar(models.Model): - manufacturer = models.ForeignKey("Manufacturer", on_delete=models.CASCADE) - - class Meta: - abstract = True - -.. code-block:: python - :caption: ``production/models.py`` - - from django.db import models - from products.models import AbstractCar - - - class Manufacturer(models.Model): - pass - - - class Car(AbstractCar): - pass - - - # Car.manufacturer will point to `production.Manufacturer` here. - -To refer to models defined in another application, you can explicitly specify -a model with the full application label. For example, if the ``Manufacturer`` -model above is defined in another application called ``production``, you'd -need to use:: class Car(models.Model): - manufacturer = models.ForeignKey( - "production.Manufacturer", - on_delete=models.CASCADE, - ) + manufacturer = models.ForeignKey(Manufacturer, on_delete=models.CASCADE) -This sort of reference, called a lazy relationship, can be useful when -resolving circular import dependencies between two applications. +The first positional argument can be either a concrete model class or a +:ref:`lazy reference ` to a model class. +:ref:`Recursive relationships `, where a model has a +relationship with itself, are also supported. + +See :attr:`ForeignKey.on_delete` for details on the second positional +argument. A database index is automatically created on the ``ForeignKey``. You can disable this by setting :attr:`~Field.db_index` to ``False``. You may want to @@ -1714,9 +1659,9 @@ Database Representation Behind the scenes, Django appends ``"_id"`` to the field name to create its database column name. In the above example, the database table for the ``Car`` -model will have a ``manufacturer_id`` column. (You can change this explicitly by -specifying :attr:`~Field.db_column`) However, your code should never have to -deal with the database column name, unless you write custom SQL. You'll always +model will have a ``manufacturer_id`` column. You can change this explicitly by +specifying :attr:`~Field.db_column`, however, your code should never have to +deal with the database column name (unless you write custom SQL). You'll always deal with the field names of your model object. .. _foreign-key-arguments: @@ -2266,6 +2211,120 @@ accepted by :class:`ForeignKey`, plus one extra argument: See :doc:`One-to-one relationships ` for usage examples of ``OneToOneField``. +.. _lazy-relationships: + +Lazy relationships +------------------ + +Lazy relationships allow referencing models by their names (as strings) or +creating recursive relationships. Strings can be used as the first argument in +any relationship field to reference models lazily. A lazy reference can be +either :ref:`recursive `, +:ref:`relative ` or +:ref:`absolute `. + +.. _recursive-relationships: + +Recursive +~~~~~~~~~ + +To define a relationship where a model references itself, use ``"self"`` as the +first argument of the relationship field:: + + from django.db import models + + + class Manufacturer(models.Model): + name = models.TextField() + suppliers = models.ManyToManyField("self", symmetrical=False) + + +When used in an :ref:`abstract model `, the recursive +relationship resolves such that each concrete subclass references itself. + +.. _relative-relationships: + +Relative +~~~~~~~~ + +When a relationship needs to be created with a model that has not been defined +yet, it can be referenced by its name rather than the model object itself:: + + from django.db import models + + + class Car(models.Model): + manufacturer = models.ForeignKey( + "Manufacturer", + on_delete=models.CASCADE, + ) + + + class Manufacturer(models.Model): + name = models.TextField() + suppliers = models.ManyToManyField("self", symmetrical=False) + +Relationships defined this way on :ref:`abstract models +` are resolved when the model is subclassed as a +concrete model and are not relative to the abstract model's ``app_label``: + +.. code-block:: python + :caption: ``products/models.py`` + + from django.db import models + + + class AbstractCar(models.Model): + manufacturer = models.ForeignKey("Manufacturer", on_delete=models.CASCADE) + + class Meta: + abstract = True + +.. code-block:: python + :caption: ``production/models.py`` + + from django.db import models + from products.models import AbstractCar + + + class Manufacturer(models.Model): + name = models.TextField() + + + class Car(AbstractCar): + pass + +In this example, the ``Car.manufacturer`` relationship will resolve to +``production.Manufacturer``, as it points to the concrete model defined +within the ``production/models.py`` file. + +.. admonition:: Reusable models with relative references + + Relative references allow the creation of reusable abstract models with + relationships that can resolve to different implementations of the + referenced models in various subclasses across different applications. + +.. _absolute-relationships: + +Absolute +~~~~~~~~ + +Absolute references specify a model using its ``app_label`` and class name, +allowing for model references across different applications. This type of lazy +relationship can also help resolve circular imports. + +For example, if the ``Manufacturer`` model is defined in another application +called ``thirdpartyapp``, it can be referenced as:: + + class Car(models.Model): + manufacturer = models.ForeignKey( + "thirdpartyapp``.Manufacturer", + on_delete=models.CASCADE, + ) + +Absolute references always point to the same model, even when used in an +:ref:`abstract model `. + Field API reference ===================