From cd4da34fc1f1df08f593e461b2f670bfd61d0d2f Mon Sep 17 00:00:00 2001 From: sarahboyce Date: Tue, 19 Apr 2022 13:21:23 +0200 Subject: Fixed #33004 -- Made saving objects with unsaved GenericForeignKey raise ValueError. This aligns to the behaviour of OneToOneField and ForeignKey fields. Thanks Jonny Park for the initial patch. --- django/db/models/base.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'django') diff --git a/django/db/models/base.py b/django/db/models/base.py index 556e25510c..9aa6d7596a 100644 --- a/django/db/models/base.py +++ b/django/db/models/base.py @@ -1072,8 +1072,9 @@ class Model(metaclass=ModelBase): def _prepare_related_fields_for_save(self, operation_name, fields=None): # Ensure that a model instance without a PK hasn't been assigned to - # a ForeignKey or OneToOneField on this model. If the field is - # nullable, allowing the save would result in silent data loss. + # a ForeignKey, GenericForeignKey or OneToOneField on this model. If + # the field is nullable, allowing the save would result in silent data + # loss. for field in self._meta.concrete_fields: if fields and field not in fields: continue @@ -1107,6 +1108,21 @@ class Model(metaclass=ModelBase): self, field.attname ): field.delete_cached_value(self) + # GenericForeignKeys are private. + for field in self._meta.private_fields: + if fields and field not in fields: + continue + if ( + field.is_relation + and field.is_cached(self) + and hasattr(field, "fk_field") + ): + obj = field.get_cached_value(self, default=None) + if obj and obj.pk is None: + raise ValueError( + f"{operation_name}() prohibited to prevent data loss due to " + f"unsaved related object '{field.name}'." + ) def delete(self, using=None, keep_parents=False): if self.pk is None: -- cgit v1.3