Commit 1abd1776 authored by Aymeric Augustin's avatar Aymeric Augustin
Browse files

[1.8.x] Fixed #25160 (again) -- Moved data loss check on reverse relations.

Moved data loss check when assigning to a reverse one-to-one relation on
an unsaved instance to Model.save(). This is exactly the same change as
e4b813c0 but for reverse relations.

Backport of c3904deb from master
parent a0ce708c
Loading
Loading
Loading
Loading
+0 −6
Original line number Diff line number Diff line
@@ -506,12 +506,6 @@ class SingleRelatedObjectDescriptor(object):
                    raise ValueError('Cannot assign "%r": the current database router prevents this relation.' % value)

        related_pk = tuple(getattr(instance, field.attname) for field in self.related.field.foreign_related_fields)
        if None in related_pk:
            raise ValueError(
                'Cannot assign "%r": "%s" instance isn\'t saved in the database.' %
                (value, instance._meta.object_name)
            )

        # Set the value of the related field to the value of the related object's related field
        for index, field in enumerate(self.related.field.local_related_fields):
            setattr(value, field.attname, related_pk[index])
+4 −0
Original line number Diff line number Diff line
@@ -39,3 +39,7 @@ Bugfixes

* Fixed custom queryset chaining with ``values()`` and ``values_list()``
  (:ticket:`20625`).

* Moved the :ref:`unsaved model instance assignment data loss check
  <unsaved-model-instance-check-18>` on reverse relations to ``Model.save()``
  (:ticket:`25160`).
+3 −0
Original line number Diff line number Diff line
@@ -701,6 +701,9 @@ Assigning unsaved objects to relations raises an error
        ...
        ValueError: save() prohibited to prevent data loss due to unsaved related object 'author'.

    A similar check on assignment to reverse one-to-one relations was removed
    in Django 1.8.5.

Assigning unsaved objects to a :class:`~django.db.models.ForeignKey`,
:class:`~django.contrib.contenttypes.fields.GenericForeignKey`, and
:class:`~django.db.models.OneToOneField` now raises a :exc:`ValueError`.
+7 −5
Original line number Diff line number Diff line
@@ -371,13 +371,15 @@ class OneToOneTests(TestCase):
        """
        p = Place()
        b = UndergroundBar.objects.create()
        msg = (
            'Cannot assign "<UndergroundBar: UndergroundBar object>": "Place" '
            'instance isn\'t saved in the database.'
        )

        # Assigning a reverse relation on an unsaved object is allowed.
        p.undergroundbar = b

        # However saving the object is not allowed.
        msg = "save() prohibited to prevent data loss due to unsaved related object 'place'."
        with self.assertNumQueries(0):
            with self.assertRaisesMessage(ValueError, msg):
                p.undergroundbar = b
                b.save()

    def test_nullable_o2o_delete(self):
        u = UndergroundBar.objects.create(place=self.p1)