Commit c3904deb authored by Aymeric Augustin's avatar Aymeric Augustin
Browse files

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.
parent a4b80e24
Loading
Loading
Loading
Loading
+0 −6
Original line number Diff line number Diff line
@@ -534,12 +534,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
@@ -702,6 +702,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
@@ -373,13 +373,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)