From ba4eef07d74791c5bfcefa3ad24f17fd039a697c Mon Sep 17 00:00:00 2001 From: alec_dev Date: Fri, 8 May 2026 16:30:25 -0500 Subject: [PATCH] Integrate sync_schema_config_fields fixes into main --- .../migration_utils/update_schema_config.py | 11 +++----- .../specify/models_utils/load_datamodel.py | 27 ++++++++++++++----- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/specifyweb/specify/migration_utils/update_schema_config.py b/specifyweb/specify/migration_utils/update_schema_config.py index 5d5e2b89f84..0eee8a23851 100644 --- a/specifyweb/specify/migration_utils/update_schema_config.py +++ b/specifyweb/specify/migration_utils/update_schema_config.py @@ -399,9 +399,7 @@ def update_table_schema_config_with_defaults( pending_itemstr_rows.extend(item_str_rows) - for field in table.all_fields: - if field is table.idField: - continue + for field in table._all_fields(exclude_id_field=True): field_defaults = None if table_defaults.get('items'): field_defaults = table_defaults['items'].get(field.name.lower()) @@ -664,17 +662,16 @@ def find_missing_schema_config_fields(discipline_id: int, apps=global_apps): if table_name_lower not in container_names: missing_tables.append(table_name) missing_fields[table_name] = sorted( - field.name for field in table.all_fields - if field.name and field is not table.idField + field.name for field in table._all_fields(exclude_id_field=True) + if field.name ) continue existing_fields = existing_fields_by_table.get(table_name_lower, set()) missing_in_table = sorted( # sort for better reproducablity field.name - for field in table.all_fields + for field in table._all_fields(exclude_id_field=True) if field.name - and field is not table.idField and field.name.lower() not in existing_fields ) diff --git a/specifyweb/specify/models_utils/load_datamodel.py b/specifyweb/specify/models_utils/load_datamodel.py index dbe2c8f8f72..d82021bf4bc 100644 --- a/specifyweb/specify/models_utils/load_datamodel.py +++ b/specifyweb/specify/models_utils/load_datamodel.py @@ -149,19 +149,32 @@ def name(self) -> str: raise ValueError("classname is required to compute the name") return self.classname.split(".")[-1] + def _all_fields( + self, + exclude_fields: bool = False, + exclude_relationships: bool = False, + exclude_id_field: bool = False, + exclude_virtual_fields: bool = True, + ) -> Iterable[Union["Field", "Relationship"]]: + if not exclude_fields: + yield from self.fields or [] + if not exclude_relationships: + yield from self.relationships or [] + if not exclude_virtual_fields: + yield from self.virtual_fields or [] + if not exclude_id_field and self.idField is not None: + yield self.idField + @property def django_name(self) -> str: return self.name.capitalize() @property def all_fields(self) -> list[Union["Field", "Relationship"]]: - def af() -> Iterable[Union["Field","Relationship"]]: - yield from self.fields or [] # Handle None by using an empty list - yield from self.relationships or [] # Handle None by using an empty list - if self.idField is not None: - yield self.idField - - return list(af()) + """ + A list of all non-virtual fields (including the ID field) and relationships for the table. + """ + return list(self._all_fields()) def is_virtual_field(self, fieldname: str) -> bool: