diff --git a/django/db/models/base.py b/django/db/models/base.py index 1f7e5f84aa..cb51ed42c4 100644 --- a/django/db/models/base.py +++ b/django/db/models/base.py @@ -799,15 +799,7 @@ class Model(metaclass=ModelBase): return update_fields = frozenset(update_fields) - field_names = set() - - for field in self._meta.concrete_fields: - if not field.primary_key: - field_names.add(field.name) - - if field.name != field.attname: - field_names.add(field.attname) - + field_names = self._meta._non_pk_concrete_field_names non_model_fields = update_fields.difference(field_names) if non_model_fields: diff --git a/django/db/models/options.py b/django/db/models/options.py index bff55011dc..b6b8202802 100644 --- a/django/db/models/options.py +++ b/django/db/models/options.py @@ -89,6 +89,7 @@ class Options: "many_to_many", "concrete_fields", "local_concrete_fields", + "_non_pk_concrete_field_names", "_forward_fields_map", "managers", "managers_map", @@ -982,6 +983,19 @@ class Options: names.append(name) return frozenset(names) + @cached_property + def _non_pk_concrete_field_names(self): + """ + Return a set of the non-pk concrete field names defined on the model. + """ + names = [] + for field in self.concrete_fields: + if not field.primary_key: + names.append(field.name) + if field.name != field.attname: + names.append(field.attname) + return frozenset(names) + @cached_property def db_returning_fields(self): """