diff --git a/django/db/models/base.py b/django/db/models/base.py
index b679d08..a4aa477 100644
a
|
b
|
class Model(six.with_metaclass(ModelBase)):
|
625 | 625 | that the "save" must be an SQL insert or update (or equivalent for |
626 | 626 | non-SQL backends), respectively. Normally, they should not be set. |
627 | 627 | """ |
| 628 | for field in self._meta.concrete_fields + self._meta.related_objects: |
| 629 | if field.is_relation: |
| 630 | obj = getattr(self, field.name, None) |
| 631 | if obj and obj._state.adding: |
| 632 | raise ValueError( |
| 633 | "save() prohibited to prevent data loss due to " |
| 634 | "unsaved related object '%s'." % field.name |
| 635 | ) |
| 636 | |
628 | 637 | using = using or router.db_for_write(self.__class__, instance=self) |
629 | 638 | if force_insert and (force_update or update_fields): |
630 | 639 | raise ValueError("Cannot force both insert and updating in model saving.") |
diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py
index b038fdf..77a79d4 100644
a
|
b
|
class SingleRelatedObjectDescriptor(object):
|
514 | 514 | raise ValueError('Cannot assign "%r": the current database router prevents this relation.' % value) |
515 | 515 | |
516 | 516 | related_pk = tuple(getattr(instance, field.attname) for field in self.related.field.foreign_related_fields) |
517 | | if not self.related.field.allow_unsaved_instance_assignment and None in related_pk: |
518 | | raise ValueError( |
519 | | 'Cannot assign "%r": "%s" instance isn\'t saved in the database.' % |
520 | | (value, instance._meta.object_name) |
521 | | ) |
522 | 517 | |
523 | 518 | # Set the value of the related field to the value of the related object's related field |
524 | 519 | for index, field in enumerate(self.related.field.local_related_fields): |
… |
… |
class ReverseSingleRelatedObjectDescriptor(object):
|
685 | 680 | else: |
686 | 681 | for lh_field, rh_field in self.field.related_fields: |
687 | 682 | pk = value._get_pk_val() |
688 | | if not self.field.allow_unsaved_instance_assignment and pk is None: |
689 | | raise ValueError( |
690 | | 'Cannot assign "%r": "%s" instance isn\'t saved in the database.' % |
691 | | (value, self.field.remote_field.model._meta.object_name) |
692 | | ) |
693 | 683 | setattr(instance, lh_field.attname, getattr(value, rh_field.attname)) |
694 | 684 | |
695 | 685 | # Since we already know what the related object is, seed the related |
… |
… |
class ForeignObject(RelatedField):
|
1579 | 1569 | one_to_many = False |
1580 | 1570 | one_to_one = False |
1581 | 1571 | |
1582 | | allow_unsaved_instance_assignment = False |
1583 | 1572 | requires_unique_target = True |
1584 | 1573 | related_accessor_class = ForeignRelatedObjectsDescriptor |
1585 | 1574 | rel_class = ForeignObjectRel |
diff --git a/tests/many_to_one/tests.py b/tests/many_to_one/tests.py
index d828abe..c1222ce 100644
a
|
b
|
class ManyToOneTests(TestCase):
|
566 | 566 | with self.assertRaisesMessage(ValueError, |
567 | 567 | 'Cannot assign "%r": "%s" instance isn\'t saved in the database.' |
568 | 568 | % (p, Child.parent.field.remote_field.model._meta.object_name)): |
569 | | Child(parent=p) |
| 569 | Child(parent=p).save() |
570 | 570 | |
571 | 571 | with self.assertRaisesMessage(ValueError, |
572 | 572 | 'Cannot assign "%r": "%s" instance isn\'t saved in the database.' |
diff --git a/tests/one_to_one/tests.py b/tests/one_to_one/tests.py
index 041fe68..01a489d 100644
a
|
b
|
class OneToOneTests(TestCase):
|
134 | 134 | should raise an exception. |
135 | 135 | """ |
136 | 136 | place = Place(name='User', address='London') |
137 | | with self.assertRaisesMessage(ValueError, |
138 | | 'Cannot assign "%r": "%s" instance isn\'t saved in the database.' |
139 | | % (place, Restaurant.place.field.remote_field.model._meta.object_name)): |
| 137 | msg = "save() prohibited to prevent data loss due to unsaved related object 'place'." |
| 138 | with self.assertRaisesMessage(ValueError, msg): |
140 | 139 | Restaurant.objects.create(place=place, serves_hot_dogs=True, serves_pizza=False) |
141 | 140 | bar = UndergroundBar() |
142 | 141 | p = Place(name='User', address='London') |
143 | | with self.assertRaisesMessage(ValueError, |
144 | | 'Cannot assign "%r": "%s" instance isn\'t saved in the database.' |
145 | | % (bar, p._meta.object_name)): |
| 142 | msg = "save() prohibited to prevent data loss due to unsaved related object 'undergroundbar'." |
| 143 | with self.assertRaisesMessage(ValueError, msg): |
146 | 144 | p.undergroundbar = bar |
| 145 | p.save() |
147 | 146 | |
148 | 147 | def test_unsaved_object_check_override(self): |
149 | 148 | """ |