[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 ase4b813c
but for reverse relations. Backport ofc3904de
from master
This commit is contained in:
parent
a0ce708c1c
commit
1abd177696
|
@ -506,12 +506,6 @@ class SingleRelatedObjectDescriptor(object):
|
||||||
raise ValueError('Cannot assign "%r": the current database router prevents this relation.' % value)
|
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)
|
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
|
# 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):
|
for index, field in enumerate(self.related.field.local_related_fields):
|
||||||
setattr(value, field.attname, related_pk[index])
|
setattr(value, field.attname, related_pk[index])
|
||||||
|
|
|
@ -39,3 +39,7 @@ Bugfixes
|
||||||
|
|
||||||
* Fixed custom queryset chaining with ``values()`` and ``values_list()``
|
* Fixed custom queryset chaining with ``values()`` and ``values_list()``
|
||||||
(:ticket:`20625`).
|
(: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`).
|
||||||
|
|
|
@ -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'.
|
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`,
|
Assigning unsaved objects to a :class:`~django.db.models.ForeignKey`,
|
||||||
:class:`~django.contrib.contenttypes.fields.GenericForeignKey`, and
|
:class:`~django.contrib.contenttypes.fields.GenericForeignKey`, and
|
||||||
:class:`~django.db.models.OneToOneField` now raises a :exc:`ValueError`.
|
:class:`~django.db.models.OneToOneField` now raises a :exc:`ValueError`.
|
||||||
|
|
|
@ -371,13 +371,15 @@ class OneToOneTests(TestCase):
|
||||||
"""
|
"""
|
||||||
p = Place()
|
p = Place()
|
||||||
b = UndergroundBar.objects.create()
|
b = UndergroundBar.objects.create()
|
||||||
msg = (
|
|
||||||
'Cannot assign "<UndergroundBar: UndergroundBar object>": "Place" '
|
# Assigning a reverse relation on an unsaved object is allowed.
|
||||||
'instance isn\'t saved in the database.'
|
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.assertNumQueries(0):
|
||||||
with self.assertRaisesMessage(ValueError, msg):
|
with self.assertRaisesMessage(ValueError, msg):
|
||||||
p.undergroundbar = b
|
b.save()
|
||||||
|
|
||||||
def test_nullable_o2o_delete(self):
|
def test_nullable_o2o_delete(self):
|
||||||
u = UndergroundBar.objects.create(place=self.p1)
|
u = UndergroundBar.objects.create(place=self.p1)
|
||||||
|
|
Loading…
Reference in New Issue