[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
e4b813c but for reverse relations.

Backport of c3904de from master
This commit is contained in:
Aymeric Augustin 2015-09-19 13:36:38 +02:00
parent a0ce708c1c
commit 1abd177696
4 changed files with 14 additions and 11 deletions

View File

@ -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])

View File

@ -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`).

View File

@ -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`.

View File

@ -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)