|
@@ -601,7 +601,7 @@ class Model(AltersData, metaclass=ModelBase):
|
|
|
return my_pk == other.pk
|
|
|
|
|
|
def __hash__(self):
|
|
|
- if self.pk is None:
|
|
|
+ if not self._is_pk_set():
|
|
|
raise TypeError("Model instances without primary key value are unhashable")
|
|
|
return hash(self.pk)
|
|
|
|
|
@@ -662,6 +662,9 @@ class Model(AltersData, metaclass=ModelBase):
|
|
|
|
|
|
pk = property(_get_pk_val, _set_pk_val)
|
|
|
|
|
|
+ def _is_pk_set(self, meta=None):
|
|
|
+ return self._get_pk_val(meta) is not None
|
|
|
+
|
|
|
def get_deferred_fields(self):
|
|
|
"""
|
|
|
Return a set containing names of deferred fields for this instance.
|
|
@@ -1094,11 +1097,10 @@ class Model(AltersData, metaclass=ModelBase):
|
|
|
if f.name in update_fields or f.attname in update_fields
|
|
|
]
|
|
|
|
|
|
- pk_val = self._get_pk_val(meta)
|
|
|
- if pk_val is None:
|
|
|
+ if not self._is_pk_set(meta):
|
|
|
pk_val = meta.pk.get_pk_value_on_save(self)
|
|
|
setattr(self, meta.pk.attname, pk_val)
|
|
|
- pk_set = pk_val is not None
|
|
|
+ pk_set = self._is_pk_set(meta)
|
|
|
if not pk_set and (force_update or update_fields):
|
|
|
raise ValueError("Cannot force an update in save() with no primary key.")
|
|
|
updated = False
|
|
@@ -1126,6 +1128,7 @@ class Model(AltersData, metaclass=ModelBase):
|
|
|
for f in non_pks_non_generated
|
|
|
]
|
|
|
forced_update = update_fields or force_update
|
|
|
+ pk_val = self._get_pk_val(meta)
|
|
|
updated = self._do_update(
|
|
|
base_qs, using, pk_val, values, update_fields, forced_update
|
|
|
)
|
|
@@ -1226,7 +1229,7 @@ class Model(AltersData, metaclass=ModelBase):
|
|
|
# database to raise an IntegrityError if applicable. If
|
|
|
# constraints aren't supported by the database, there's the
|
|
|
# unavoidable risk of data corruption.
|
|
|
- if obj.pk is None:
|
|
|
+ if not obj._is_pk_set():
|
|
|
# Remove the object from a related instance cache.
|
|
|
if not field.remote_field.multiple:
|
|
|
field.remote_field.delete_cached_value(obj)
|
|
@@ -1254,14 +1257,14 @@ class Model(AltersData, metaclass=ModelBase):
|
|
|
and hasattr(field, "fk_field")
|
|
|
):
|
|
|
obj = field.get_cached_value(self, default=None)
|
|
|
- if obj and obj.pk is None:
|
|
|
+ if obj and not obj._is_pk_set():
|
|
|
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:
|
|
|
+ if not self._is_pk_set():
|
|
|
raise ValueError(
|
|
|
"%s object can't be deleted because its %s attribute is set "
|
|
|
"to None." % (self._meta.object_name, self._meta.pk.attname)
|
|
@@ -1367,7 +1370,7 @@ class Model(AltersData, metaclass=ModelBase):
|
|
|
return field_map
|
|
|
|
|
|
def prepare_database_save(self, field):
|
|
|
- if self.pk is None:
|
|
|
+ if not self._is_pk_set():
|
|
|
raise ValueError(
|
|
|
"Unsaved model instance %r cannot be used in an ORM query." % self
|
|
|
)
|
|
@@ -1497,7 +1500,7 @@ class Model(AltersData, metaclass=ModelBase):
|
|
|
# allows single model to have effectively multiple primary keys.
|
|
|
# Refs #17615.
|
|
|
model_class_pk = self._get_pk_val(model_class._meta)
|
|
|
- if not self._state.adding and model_class_pk is not None:
|
|
|
+ if not self._state.adding and self._is_pk_set(model_class._meta):
|
|
|
qs = qs.exclude(pk=model_class_pk)
|
|
|
if qs.exists():
|
|
|
if len(unique_check) == 1:
|
|
@@ -1532,7 +1535,7 @@ class Model(AltersData, metaclass=ModelBase):
|
|
|
qs = model_class._default_manager.filter(**lookup_kwargs)
|
|
|
# Exclude the current object from the query if we are editing an
|
|
|
# instance (as opposed to creating a new one)
|
|
|
- if not self._state.adding and self.pk is not None:
|
|
|
+ if not self._state.adding and self._is_pk_set():
|
|
|
qs = qs.exclude(pk=self.pk)
|
|
|
|
|
|
if qs.exists():
|