From 2a5eda8ad97e06ea5ec95d3beb46fcab4a41fa99 Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Fri, 29 May 2026 11:00:55 +0200 Subject: [PATCH 001/113] fix:reverse_hide_component_fields to be set to Falses (cherry picked from commit ab5b3e3263efd6804b456a8dd5af2df485d103ec) --- specifyweb/specify/migration_utils/update_schema_config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specifyweb/specify/migration_utils/update_schema_config.py b/specifyweb/specify/migration_utils/update_schema_config.py index b91927b90a6..93b7678454d 100644 --- a/specifyweb/specify/migration_utils/update_schema_config.py +++ b/specifyweb/specify/migration_utils/update_schema_config.py @@ -2097,7 +2097,7 @@ def reverse_hide_component_fields(apps, schema_editor=None): container=container, name=field_name.lower() ) - items.update(ishidden=True) + items.update(ishidden=False) # ########################################## # Used in 0042_discipline_type_picklist.py From e8466af65f62979bc71dcf328c35e648e992c6c4 Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Fri, 29 May 2026 11:05:13 +0200 Subject: [PATCH 002/113] fix: Do not dedupe localized strings across all languages (cherry picked from commit 60a6797d678f1dfab94d98ec28adc86855129540) --- specifyweb/specify/migration_utils/update_schema_config.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/specifyweb/specify/migration_utils/update_schema_config.py b/specifyweb/specify/migration_utils/update_schema_config.py index 93b7678454d..37519d63069 100644 --- a/specifyweb/specify/migration_utils/update_schema_config.py +++ b/specifyweb/specify/migration_utils/update_schema_config.py @@ -2019,13 +2019,15 @@ def update_schema_config_field_desc_for_components(apps, schema_editor=None): Splocaleitemstr.objects.filter( itemdesc__container__name=table.lower(), itemdesc__container__schematype=0, - itemdesc__name=field_name.lower() + itemdesc__name=field_name.lower(), + language="en", ).update(text=new_desc) Splocaleitemstr.objects.filter( itemname__container__name=table.lower(), itemname__container__schematype=0, - itemname__name=field_name.lower() + itemname__name=field_name.lower(), + language="en", ).update(text=new_name) def update_hidden_prop_for_compoenents(apps, schema_editor=None): From 25bf8b26d4dab023643811019abebed39eadf3b8 Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Fri, 29 May 2026 11:14:33 +0200 Subject: [PATCH 003/113] fix: Simplify MultipleObjectsReturned (cherry picked from commit f58c7857eb9e811f8dde7730952e34944d74ec76) --- .../migration_utils/update_schema_config.py | 32 ++++++++++++------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/specifyweb/specify/migration_utils/update_schema_config.py b/specifyweb/specify/migration_utils/update_schema_config.py index 37519d63069..bb85e2459d4 100644 --- a/specifyweb/specify/migration_utils/update_schema_config.py +++ b/specifyweb/specify/migration_utils/update_schema_config.py @@ -410,18 +410,22 @@ def update_table_field_schema_config_with_defaults( Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - try: - sp_local_container, _ = Splocalecontainer.objects.get_or_create( + sp_local_container = ( + Splocalecontainer.objects.filter( name=table.name.lower(), discipline_id=discipline_id, schematype=table_config.schema_type, ) - except MultipleObjectsReturned: - sp_local_container = Splocalecontainer.objects.filter( + .order_by('id') + .first() + ) + + if sp_local_container is None: + sp_local_container = Splocalecontainer.objects.create( name=table.name.lower(), discipline_id=discipline_id, - schematype=table_config.schema_type - ).first() + schematype=table_config.schema_type, + ) try: field = table.get_field_strict(field_name) @@ -535,18 +539,22 @@ def update_table_field_schema_config_params( Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - try: - sp_local_container, _ = Splocalecontainer.objects.get_or_create( + sp_local_container = ( + Splocalecontainer.objects.filter( name=table.name.lower(), discipline_id=discipline_id, schematype=table_config.schema_type, ) - except MultipleObjectsReturned: - sp_local_container = Splocalecontainer.objects.filter( + .order_by('id') + .first() + ) + + if sp_local_container is None: + sp_local_container = Splocalecontainer.objects.create( name=table.name.lower(), discipline_id=discipline_id, - schematype=table_config.schema_type - ).first() + schematype=table_config.schema_type, + ) try: field = table.get_field_strict(field_name) From 063a7c6c86c4ede065f4457ee00d16e06c1999e0 Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Fri, 29 May 2026 11:21:01 +0200 Subject: [PATCH 004/113] Fix: Use db_alias for migration db connexion (cherry picked from commit 2c3b7d59a25b7cf5ea48a718d9166d21da0dd00a) --- specifyweb/backend/patches/migration_utils.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/specifyweb/backend/patches/migration_utils.py b/specifyweb/backend/patches/migration_utils.py index a773cb10ad0..9da3812d35b 100644 --- a/specifyweb/backend/patches/migration_utils.py +++ b/specifyweb/backend/patches/migration_utils.py @@ -10,6 +10,8 @@ def apply_migrations(app_registry, schema_editor=None): update_coordinates(app_registry, schema_editor) def update_is_accepted(app_registry, schema_editor=None): + db_alias = schema_editor.connection.alias if schema_editor is not None else "default" + for tree in SPECIFY_TREES: tree_filters = { "isaccepted": False, @@ -17,20 +19,22 @@ def update_is_accepted(app_registry, schema_editor=None): } tree_model = app_registry.get_model("specify", tree) - tree_model.objects.filter(**tree_filters).update(isaccepted=True) + tree_model._base_manager.using(db_alias).filter(**tree_filters).update(isaccepted=True) def update_coordinates(app_registry, schema_editor=None): + db_alias = schema_editor.connection.alias if schema_editor is not None else "default" + Locality = app_registry.get_model("specify", "Locality") - Locality.objects.filter(lat1text__isnull=True, latitude1__isnull=False) \ + Locality._base_manager.using(db_alias).filter(lat1text__isnull=True, latitude1__isnull=False) \ .update(lat1text=F("latitude1")) - Locality.objects.filter(long1text__isnull=True, longitude1__isnull=False) \ + Locality._base_manager.using(db_alias).filter(long1text__isnull=True, longitude1__isnull=False) \ .update(long1text=F("longitude1")) - Locality.objects.filter(lat2text__isnull=True, latitude2__isnull=False) \ + Locality._base_manager.using(db_alias).filter(lat2text__isnull=True, latitude2__isnull=False) \ .update(lat2text=F("latitude2")) - Locality.objects.filter(long2text__isnull=True, longitude2__isnull=False) \ + Locality._base_manager.using(db_alias).filter(long2text__isnull=True, longitude2__isnull=False) \ .update(long2text=F("longitude2")) From 6cc5ffa23ac98b75e312a961e8baa64c6de90690 Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Fri, 29 May 2026 11:22:18 +0200 Subject: [PATCH 005/113] Fix: flips existing row back to isDatabaseConstraint=True (cherry picked from commit c452f7d57ebc56d6aaa655b3be34eff8c85a3fa7) --- specifyweb/backend/businessrules/migration_utils.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/specifyweb/backend/businessrules/migration_utils.py b/specifyweb/backend/businessrules/migration_utils.py index c490dcfbe41..b8d82ba994a 100644 --- a/specifyweb/backend/businessrules/migration_utils.py +++ b/specifyweb/backend/businessrules/migration_utils.py @@ -47,6 +47,7 @@ def catnum_rule_uneditable(apps, schema_editor=None): model_rules = UniquenessRule.objects.filter(modelName="Collectionobject", discipline_id=discipline.id, isDatabaseConstraint=False) has_catalognumber_rule = False + matching_rule_ids: List[int] = [] for rule in model_rules: rule_fields = rule.uniquenessrulefield_set.all() @@ -59,8 +60,11 @@ def catnum_rule_uneditable(apps, schema_editor=None): # exception if more than one result is returned if (len(fields) == 1 and len(scopes) == 1) and (fields.get().fieldPath.lower() == "catalognumber" and scopes.get().fieldPath.lower() == "collection"): has_catalognumber_rule = True + matching_rule_ids.append(rule.id) - if not has_catalognumber_rule: + if has_catalognumber_rule: + UniquenessRule.objects.filter(id__in=matching_rule_ids).update(isDatabaseConstraint=True) + else: create_uniqueness_rule( model_name="Collectionobject", discipline=discipline, From 1ee0f1ef873603096a6a45bd1373e21bdce2faab Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Fri, 29 May 2026 11:27:07 +0200 Subject: [PATCH 006/113] @CarolineDenis Fix: compare full rule definitions before deleting anything in uniqueness (cherry picked from commit c61a530bedfc3afba20762b52266c3fc550f2b35) --- .../backend/businessrules/uniqueness_rules.py | 65 +++++++------------ 1 file changed, 24 insertions(+), 41 deletions(-) diff --git a/specifyweb/backend/businessrules/uniqueness_rules.py b/specifyweb/backend/businessrules/uniqueness_rules.py index 34ec4af7857..21ff660ffa5 100644 --- a/specifyweb/backend/businessrules/uniqueness_rules.py +++ b/specifyweb/backend/businessrules/uniqueness_rules.py @@ -493,24 +493,19 @@ def fix_global_default_rules(registry=None): UniquenessRule = registry.get_model('businessrules', 'UniquenessRule') \ if registry \ else models.UniquenessRule - UniquenessRuleField = registry.get_model('businessrules', 'UniquenessRuleField') \ - if registry \ - else models.UniquenessRuleField - - global_rule_fields = UniquenessRuleField.objects.filter( - uniquenessrule__discipline__isnull=True - ).values( - "uniquenessrule__modelName", - "uniquenessrule__isDatabaseConstraint", - "fieldPath", - "isScope", - ) - global_rule_exists = UniquenessRule.objects.filter( - discipline__isnull=True, - modelName=OuterRef("modelName"), - isDatabaseConstraint=OuterRef("isDatabaseConstraint"), - ) + global_rule_signatures = { + ( + rule.modelName, + rule.isDatabaseConstraint, + frozenset( + rule.uniquenessrulefield_set.values_list("fieldPath", "isScope") + ), + ) + for rule in UniquenessRule.objects.filter( + discipline__isnull=True + ).prefetch_related("uniquenessrulefield_set") + } discipline_ids = ( UniquenessRule.objects.exclude(discipline__isnull=True) @@ -520,28 +515,16 @@ def fix_global_default_rules(registry=None): for discipline_id in discipline_ids: with transaction.atomic(): - # Delete matching fields for this discipline - matching_fields_qs = UniquenessRuleField.objects.filter( - uniquenessrule__discipline_id=discipline_id - ).filter( - Exists( - global_rule_fields.filter( - **{ - "uniquenessrule__modelName": OuterRef("uniquenessrule__modelName"), - "uniquenessrule__isDatabaseConstraint": OuterRef("uniquenessrule__isDatabaseConstraint"), - "fieldPath": OuterRef("fieldPath"), - "isScope": OuterRef("isScope"), - } - ) + for rule in UniquenessRule.objects.filter( + discipline_id=discipline_id + ).prefetch_related("uniquenessrulefield_set"): + signature = ( + rule.modelName, + rule.isDatabaseConstraint, + frozenset( + rule.uniquenessrulefield_set.values_list("fieldPath", "isScope") + ), ) - ) - matching_fields_qs.delete() - - # Delete UniquenessRule rows for this discipline that are now empty - empty_rules_qs = ( - UniquenessRule.objects.filter(discipline_id=discipline_id) - .annotate(field_count=Count("uniquenessrulefield")) - .filter(field_count=0) # now empty after field deletions - .filter(Exists(global_rule_exists)) - ) - empty_rules_qs.delete() + if signature in global_rule_signatures: + rule.uniquenessrulefield_set.all().delete() + rule.delete() From f0dd766955fa918ae75619655e86c2793ef8c2f4 Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Fri, 29 May 2026 11:29:08 +0200 Subject: [PATCH 007/113] Fix: verify existing user permissions (cherry picked from commit ef0eed0c66220207d1d47d2e665224aba2edd42c) --- specifyweb/backend/permissions/initialize.py | 24 ++++++++------------ 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/specifyweb/backend/permissions/initialize.py b/specifyweb/backend/permissions/initialize.py index a9cf2c62d5b..ac5e2cc3c94 100644 --- a/specifyweb/backend/permissions/initialize.py +++ b/specifyweb/backend/permissions/initialize.py @@ -53,13 +53,14 @@ def create_admins(apps=apps) -> None: UserPolicy = apps.get_model('permissions', 'UserPolicy') Specifyuser = apps.get_model('specify', 'Specifyuser') - if UserPolicy.objects.filter(collection__isnull=True, resource='%', action='%').exists(): - # don't do anything if there is already any admin. - return - users = Specifyuser.objects.all() for user in users: - if is_sp6_user_permissions_migrated(user, apps): + if UserPolicy.objects.filter( + collection__isnull=True, + specifyuser_id=user.id, + resource="%", + action="%", + ).exists(): continue if is_legacy_admin(user): UserPolicy.objects.get_or_create( @@ -112,17 +113,12 @@ def assign_users_to_roles(apps=apps) -> None: JOIN spprincipal p ON p.SpPrincipalID = up.SpPrincipalID JOIN collection c ON c.UserGroupScopeId = p.userGroupScopeID WHERE p.groupType IS NULL - AND u.SpecifyUserID NOT IN ( - SELECT ur.specifyuser_id + AND NOT EXISTS ( + SELECT 1 FROM spuserrole ur JOIN sprole r ON r.id = ur.role_id - WHERE r.collection_id = p.usergroupscopeid - ) - AND c.UserGroupScopeId NOT IN ( - SELECT DISTINCT r.collection_id - FROM spuserrole ur - JOIN sprole r ON r.id = ur.role_id - JOIN collection c ON c.UserGroupScopeId = r.collection_id + WHERE r.collection_id = c.UserGroupScopeId + AND ur.specifyuser_id = u.SpecifyUserID ); """) From 6dfe4eba4249b6c10d4af06e6cc9c40715e1549a Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Fri, 29 May 2026 11:30:24 +0200 Subject: [PATCH 008/113] Fix: Remove the use of f-string (cherry picked from commit b1f0346290518b29ee27dfb06518f8d5599e528b) --- .../management/commands/run_key_migration_functions.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/specifyweb/specify/management/commands/run_key_migration_functions.py b/specifyweb/specify/management/commands/run_key_migration_functions.py index 3c12ab336ed..29dd22cd285 100644 --- a/specifyweb/specify/management/commands/run_key_migration_functions.py +++ b/specifyweb/specify/management/commands/run_key_migration_functions.py @@ -221,7 +221,7 @@ def add_arguments(self, parser): nargs="*", type=str, choices=tuple(self.funcs.keys()), - help=f"Optional: specify one or more functions to run", + help="Optional: specify one or more functions to run", ) parser.add_argument( "--verbose", @@ -254,6 +254,6 @@ def handle(self, *args, **options): self.stdout.write(self.style.SUCCESS(f"Applying {func_name}...")) func(self.stdout.write if verbose else None) self.stdout.write(self.style.SUCCESS(f"Applied {func_name}")) - except Exception as e: - logger.error(f"An error occurred: {e}") + except Exception: + logger.exception("An error occurred while running key migrations") raise From 8893687d31ea2c05acb03b702b65f69867657de4 Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Fri, 29 May 2026 11:32:08 +0200 Subject: [PATCH 009/113] fix: prevent incorrect reuse when pairing tree defs and disciplines (cherry picked from commit 00fe897dcf3faa3eaaecb257461c72606db92ef8) --- .../specify/migration_utils/default_cots.py | 41 ++++++++++--------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/specifyweb/specify/migration_utils/default_cots.py b/specifyweb/specify/migration_utils/default_cots.py index 1259f18b55e..4ddd5cb1049 100644 --- a/specifyweb/specify/migration_utils/default_cots.py +++ b/specifyweb/specify/migration_utils/default_cots.py @@ -137,22 +137,25 @@ def fix_tectonic_unit_treedef_discipline_links(apps): Discipline = apps.get_model('specify', 'Discipline') Tectonicunittreedef = apps.get_model('specify', 'Tectonicunittreedef') - empty_tectonic_unit_treedefs = Tectonicunittreedef.objects.filter(discipline__isnull=True) - empty_disciplines = Discipline.objects.filter(tectonicunittreedef__isnull=True) - for empty_discipline in empty_disciplines: - if not empty_tectonic_unit_treedefs.exists(): - new_tectonic_unit_treedef = Tectonicunittreedef.objects.create( - name=f'{empty_discipline.name} Tectonic Unit Tree', - discipline=empty_discipline - ) - else: - empty_discipline.tectonicunittreedef = empty_tectonic_unit_treedefs.first() - empty_discipline.save() - - for empty_tectonic_unit_treedef in empty_tectonic_unit_treedefs: - if empty_disciplines.exists(): - empty_tectonic_unit_treedef.discipline = empty_disciplines.first() - empty_tectonic_unit_treedef.save() - else: - empty_tectonic_unit_treedef.discipline = empty_disciplines.last() - empty_tectonic_unit_treedef.save() + empty_tectonic_unit_treedefs = list( + Tectonicunittreedef.objects.filter(discipline__isnull=True) + ) + empty_disciplines = list( + Discipline.objects.filter(tectonicunittreedef__isnull=True) + ) + + for discipline, tectonic_unit_treedef in zip( + empty_disciplines, empty_tectonic_unit_treedefs + ): + tectonic_unit_treedef.discipline = discipline + tectonic_unit_treedef.save() + discipline.tectonicunittreedef = tectonic_unit_treedef + discipline.save() + + for discipline in empty_disciplines[len(empty_tectonic_unit_treedefs):]: + tectonic_unit_treedef = Tectonicunittreedef.objects.create( + name=f'{discipline.name} Tectonic Unit Tree', + discipline=discipline + ) + discipline.tectonicunittreedef = tectonic_unit_treedef + discipline.save() \ No newline at end of file From 32e297237d68ca331724872b3bc1389daa1ab0b8 Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Fri, 29 May 2026 11:35:50 +0200 Subject: [PATCH 010/113] fix: remove exclusion so partially migrated disciplines are repaired (cherry picked from commit c63318084977f8e669d2e0a5f2cdc5cce985d0c5) --- .../specify/migration_utils/tectonic_ranks.py | 38 ++++++++++++------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/specifyweb/specify/migration_utils/tectonic_ranks.py b/specifyweb/specify/migration_utils/tectonic_ranks.py index ac4c199e91c..b8f92b44788 100644 --- a/specifyweb/specify/migration_utils/tectonic_ranks.py +++ b/specifyweb/specify/migration_utils/tectonic_ranks.py @@ -6,14 +6,13 @@ def create_default_tectonic_ranks(apps): TectonicTreeDef = apps.get_model('specify', 'TectonicUnitTreeDef') Discipline = apps.get_model('specify', 'Discipline') - disciplines = Discipline.objects.filter(tectonicunittreedef__isnull=True).exclude( - id__in=TectonicTreeDef.objects.values_list('discipline_id', flat=True) - ) + disciplines = Discipline.objects.filter(tectonicunittreedef__isnull=True) for discipline in disciplines: - tectonic_tree_def = TectonicTreeDef.objects.filter(discipline=discipline).first() - if not tectonic_tree_def: - tectonic_tree_def, _ = TectonicTreeDef.objects.get_or_create(name="Tectonic Unit", discipline=discipline) + tectonic_tree_def, _ = TectonicTreeDef.objects.get_or_create( + name="Tectonic Unit", + discipline=discipline, + ) root, root_created = TectonicUnitTreeDefItem.objects.get_or_create( rankid=0, @@ -107,16 +106,27 @@ def create_root_tectonic_node(apps): tectonic_tree_def = TectonicUnitTreeDef.objects.filter(discipline=discipline).first() if not tectonic_tree_def: - tectonic_tree_def, is_created = TectonicUnitTreeDef.objects.get_or_create( + tectonic_tree_def, _ = TectonicUnitTreeDef.objects.get_or_create( name="Tectonic Unit", discipline=discipline ) - tectonic_tree_def_item = TectonicUnitTreeDefItem.objects.filter(treedef=tectonic_tree_def, rankid=0, parent=None).first() - if not tectonic_tree_def_item: - tectonic_tree_def_item, is_created = TectonicUnitTreeDefItem.objects.get_or_create( + tectonic_tree_def_item = TectonicUnitTreeDefItem.objects.filter( + treedef=tectonic_tree_def, + name="Root", + ).first() + + if tectonic_tree_def_item: + tectonic_tree_def_item.rankid = 0 + tectonic_tree_def_item.parent = None + tectonic_tree_def_item.isenforced = True + tectonic_tree_def_item.save() + else: + tectonic_tree_def_item, _ = TectonicUnitTreeDefItem.objects.get_or_create( name="Root", title="Root", + rankid=0, + parent=None, treedef=tectonic_tree_def, rankid=0, parent=None, @@ -151,7 +161,9 @@ def revert_create_root_tectonic_node(apps, schema_editor=None): tectonic_tree_def = TectonicTreeDef.objects.filter(name="Tectonic Unit", discipline=discipline).first() if tectonic_tree_def: - TectonicUnitTreeDefItem.objects.filter(treedef=tectonic_tree_def).delete() TectonicUnit.objects.filter( - name="Root" - ).delete() \ No newline at end of file + name="Root", + definition=tectonic_tree_def, + parent__isnull=True, + ).delete() + TectonicUnitTreeDefItem.objects.filter(treedef=tectonic_tree_def).delete() \ No newline at end of file From 6d1403c3098bb801d55d96b633229da98ab80966 Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Fri, 29 May 2026 11:39:16 +0200 Subject: [PATCH 011/113] Fix: Update splocalecontainer items (cherry picked from commit d4c0231b65f30db8c464d69a46f98f802fba3b0c) --- .../migration_utils/update_schema_config.py | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/specifyweb/specify/migration_utils/update_schema_config.py b/specifyweb/specify/migration_utils/update_schema_config.py index bb85e2459d4..d9092c0bbb0 100644 --- a/specifyweb/specify/migration_utils/update_schema_config.py +++ b/specifyweb/specify/migration_utils/update_schema_config.py @@ -976,7 +976,7 @@ def update_cog_type_fields(apps): container_items = Splocalecontaineritem.objects.filter( name="collectionObjectType", picklistname=None, - container__name="CollectionObject", + container__name="Collectionobject", ) for container_item in container_items: Splocaleitemstr.objects.filter(itemname=container_item).delete() @@ -1391,7 +1391,7 @@ def update_schema_config_field_desc(apps, schema_editor=None): #i.e: COType items = Splocalecontaineritem.objects.filter( container=container, - name=field_name.lower() + name__iexact=field_name ) for item in items: @@ -1593,7 +1593,7 @@ def update_schema_config_field_desc(apps): #i.e: COType items = Splocalecontaineritem.objects.filter( container=container, - name=field_name.lower() + name__iexact=field_name ) for item in items: @@ -1669,7 +1669,7 @@ def update_schema_config_field_desc(apps): #i.e: COType items = Splocalecontaineritem.objects.filter( container=container, - name=field_name.lower() + name__iexact=field_name ) for item in items: @@ -1795,7 +1795,7 @@ def update_schema_config_field_desc(apps): #i.e: COType items = Splocalecontaineritem.objects.filter( container=container, - name=field_name.lower() + name__iexact=field_name ) for item in items: @@ -1888,19 +1888,19 @@ def update_0034_schema_config_field_desc(apps): for (field_name, new_name, new_desc) in fields: items = Splocalecontaineritem.objects.filter( container=container, - name=field_name.lower() + name__iexact=field_name ) for item in items: item.ishidden = True item.save() desc_str = Splocaleitemstr.objects.filter(itemdesc_id=item.id).first() name_str = Splocaleitemstr.objects.filter(itemname_id=item.id).first() - if not desc_str or not name_str: - continue - desc_str.text = new_desc - desc_str.save() - name_str.text = new_name - name_str.save() + if desc_str is not None: + desc_str.text = new_desc + desc_str.save() + if name_str is not None: + name_str.text = new_name + name_str.save() update_0034_fields(apps) update_0034_schema_config_field_desc(apps) @@ -1927,7 +1927,7 @@ def revert_0034_schema_config_field_desc(apps): for (field_name, _, _) in fields: items = Splocalecontaineritem.objects.filter( container=container, - name=field_name.lower() + name__iexact=field_name ) # If needed, reset ishidden or revert text From d60939de2239af3d69b9eeb4b8dfc1697575d730 Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Fri, 29 May 2026 11:40:22 +0200 Subject: [PATCH 012/113] Fix: Remove shadowing import in geo migration (cherry picked from commit 9953d6a651703c2d21ff9de273f1865dc6b870a5) --- specifyweb/specify/migrations/0002_geo.py | 1 - 1 file changed, 1 deletion(-) diff --git a/specifyweb/specify/migrations/0002_geo.py b/specifyweb/specify/migrations/0002_geo.py index 58cffd3a12f..b0a523d4316 100644 --- a/specifyweb/specify/migrations/0002_geo.py +++ b/specifyweb/specify/migrations/0002_geo.py @@ -16,7 +16,6 @@ create_default_discipline_for_tree_defs, set_discipline_for_taxon_treedefs, ) -from specifyweb.specify.api.utils import create_default_collection_types logger = logging.getLogger(__name__) From 470d99dd7228dcea6cfab6e8a35a1d4a766d5a79 Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Fri, 29 May 2026 11:41:00 +0200 Subject: [PATCH 013/113] Fix: Revert relative age migration instead of applying again (cherry picked from commit 8c9cc13452968f4ac0933d68e530df7c16eae2e1) --- specifyweb/specify/migrations/0008_ageCitations_fix.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specifyweb/specify/migrations/0008_ageCitations_fix.py b/specifyweb/specify/migrations/0008_ageCitations_fix.py index 479d9dae005..9f058e2dbf3 100644 --- a/specifyweb/specify/migrations/0008_ageCitations_fix.py +++ b/specifyweb/specify/migrations/0008_ageCitations_fix.py @@ -15,7 +15,7 @@ def apply_migration(apps, schema_editor): usc.update_relative_age_fields(apps) def revert_migration(apps, schema_editor): - usc.update_relative_age_fields(apps) + usc.revert_relative_age_fields(apps) operations = [ migrations.AddField( From befb73beaffc264cdd6bb25d46c918e408387b6d Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Fri, 29 May 2026 11:41:36 +0200 Subject: [PATCH 014/113] Fix fix order of revert migration in tectonic migration (cherry picked from commit 6381382c1a6ecfc587e93cb2f215c4808c7c2eab) --- specifyweb/specify/migrations/0009_tectonic_ranks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specifyweb/specify/migrations/0009_tectonic_ranks.py b/specifyweb/specify/migrations/0009_tectonic_ranks.py index 54182060ebe..f97c7560a19 100644 --- a/specifyweb/specify/migrations/0009_tectonic_ranks.py +++ b/specifyweb/specify/migrations/0009_tectonic_ranks.py @@ -18,8 +18,8 @@ def consolidated_python_django_migration_operations(apps, schema_editor): create_root_tectonic_node(apps) def revert_cosolidated_python_django_migration_operations(apps, schema_editor): - revert_default_tectonic_ranks(apps, schema_editor) revert_create_root_tectonic_node(apps, schema_editor) + revert_default_tectonic_ranks(apps, schema_editor) operations = [ migrations.RunPython( From 8a1e35bd7bd5c65264f93b10ce6c14290fc96692 Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Fri, 29 May 2026 11:42:51 +0200 Subject: [PATCH 015/113] Fix: Indentation (cherry picked from commit bab508301ff6614ab16aee186668e6442952a2c0) --- specifyweb/backend/businessrules/uniqueness_rules.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/specifyweb/backend/businessrules/uniqueness_rules.py b/specifyweb/backend/businessrules/uniqueness_rules.py index 21ff660ffa5..d5c389480f6 100644 --- a/specifyweb/backend/businessrules/uniqueness_rules.py +++ b/specifyweb/backend/businessrules/uniqueness_rules.py @@ -525,6 +525,6 @@ def fix_global_default_rules(registry=None): rule.uniquenessrulefield_set.values_list("fieldPath", "isScope") ), ) - if signature in global_rule_signatures: - rule.uniquenessrulefield_set.all().delete() - rule.delete() + if signature in global_rule_signatures: + rule.uniquenessrulefield_set.all().delete() + rule.delete() From 82bb52062e92236fd3329d6fd643c5318361a2c2 Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Fri, 29 May 2026 11:43:43 +0200 Subject: [PATCH 016/113] Fix: Use deterministic ordering before positional pairing (cherry picked from commit 28b9f5bcb54bb96f4339a9a7485da1ede03c31d4) --- specifyweb/specify/migration_utils/default_cots.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/specifyweb/specify/migration_utils/default_cots.py b/specifyweb/specify/migration_utils/default_cots.py index 4ddd5cb1049..d6545d9484c 100644 --- a/specifyweb/specify/migration_utils/default_cots.py +++ b/specifyweb/specify/migration_utils/default_cots.py @@ -138,10 +138,10 @@ def fix_tectonic_unit_treedef_discipline_links(apps): Tectonicunittreedef = apps.get_model('specify', 'Tectonicunittreedef') empty_tectonic_unit_treedefs = list( - Tectonicunittreedef.objects.filter(discipline__isnull=True) + Tectonicunittreedef.objects.filter(discipline__isnull=True).order_by('id') ) empty_disciplines = list( - Discipline.objects.filter(tectonicunittreedef__isnull=True) + Discipline.objects.filter(tectonicunittreedef__isnull=True).order_by('id') ) for discipline, tectonic_unit_treedef in zip( From 8edb1128c0deb94f8df776c172e67b79a068e73b Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Fri, 29 May 2026 11:46:35 +0200 Subject: [PATCH 017/113] Fix: Log only on debug (cherry picked from commit 11b6608b337fb428a3f37a4e14b1d606a4301015) --- specifyweb/backend/stored_queries/execution.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/specifyweb/backend/stored_queries/execution.py b/specifyweb/backend/stored_queries/execution.py index 5dbb4228052..3d56426f047 100644 --- a/specifyweb/backend/stored_queries/execution.py +++ b/specifyweb/backend/stored_queries/execution.py @@ -858,7 +858,9 @@ def execute( - log_sqlalchemy_query(query) # Debugging + if settings.DEBUG: + log_sqlalchemy_query(query) + return {"results": apply_special_post_query_processing(query, tableid, field_specs, collection, user)} def build_query( @@ -1065,7 +1067,8 @@ def series_post_query(query, limit=40, offset=0, sort_type=0, co_id_cat_num_pair and adding a co_id colum and formatted catnum range column. Sort the results by the first catnum in the range.""" - log_sqlalchemy_query(query) # Debugging + if settings.DEBUG: + log_sqlalchemy_query(query) def parse_catalog_for_comparing(s): def check_for_decimal(s): From efc82285d60b5ce79caca64a191ecf65f6ff812e Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Fri, 29 May 2026 11:47:16 +0200 Subject: [PATCH 018/113] Fix: Fix age type (cherry picked from commit af4c963614bfdc699b2bfae116fd7ecef6caad00) --- specifyweb/specify/migration_utils/sp7_schemaconfig.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specifyweb/specify/migration_utils/sp7_schemaconfig.py b/specifyweb/specify/migration_utils/sp7_schemaconfig.py index 38e5ba48a88..7e331639d17 100644 --- a/specifyweb/specify/migration_utils/sp7_schemaconfig.py +++ b/specifyweb/specify/migration_utils/sp7_schemaconfig.py @@ -148,7 +148,7 @@ 'RelativeAge': ['number2', 'yesno2', 'relativeAgeId', 'relativeAgePeriod', 'text1', 'agent1', 'collectionDate', 'text2', 'agent2', 'date1', 'date2', 'collectionObject', 'relativeAgeCitations', 'number1', 'yesno1'], 'CollectionObject': ['collectionObjectType', 'relativeAges', 'absoluteAges', 'cojo'], 'AbsoluteAgeCitation': ['collectionMember', 'absoluteAgeCitationId'], - 'RelativeAgeCitation': ['absoluteAgeCitationId', 'collectionMember'], + 'RelativeAgeCitation': ['relativeAgeCitationId', 'collectionMember'], 'TectonicUnit': ['collectionMember', 'nodeNumber', 'yesno1', 'tectonicUnitId', 'number1', 'yesno2', 'number2', 'rankId', 'text1'], 'TectonicUnitTreeDefItem': ['children', 'rankId', 'parent', 'treeDef', 'treeEntries', 'tectonicUnitTreeDefItemId'], 'TectonicUnitTreeDef': ['discipline', 'treeEntries', 'tectonicUnitTreeDefId'] From 23666641af1446e13f2aa42b62611b1bbd121b51 Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Fri, 29 May 2026 11:48:32 +0200 Subject: [PATCH 019/113] Fix: Improve logger (cherry picked from commit 57bca6460a94c8fc89a22e9128492ee9e5475cf6) --- specifyweb/specify/api/utils.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/specifyweb/specify/api/utils.py b/specifyweb/specify/api/utils.py index 1b53ff42bd7..51a49c534e0 100644 --- a/specifyweb/specify/api/utils.py +++ b/specifyweb/specify/api/utils.py @@ -2,6 +2,8 @@ from specifyweb.specify import models as spmodels from specifyweb.backend.businessrules.exceptions import BusinessRuleException +from specifyweb import settings + logger = logging.getLogger(__name__) @@ -19,9 +21,11 @@ def get_spmodel_class(model_name: str): raise AttributeError(f"Model '{model_name}' not found in models module.") def log_sqlalchemy_query(query): - # Call this function to debug the raw SQL query generated by SQLAlchemy + if not settings.DEBUG: + return + from sqlalchemy.dialects import mysql - compiled_query = query.statement.compile(dialect=mysql.dialect(), compile_kwargs={"literal_binds": True}) + compiled_query = query.statement.compile(dialect=mysql.dialect()) raw_sql = str(compiled_query).replace('\n', ' ') + ';' logger.debug('='.join(['' for _ in range(80)])) logger.debug(raw_sql) From 4c0f9f8424eac093b47bedcf51d9bd85f7fe3927 Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Fri, 29 May 2026 11:49:47 +0200 Subject: [PATCH 020/113] Fix: Remove unecessary param in def migration (cherry picked from commit 00a21ef441f1a2db53f49f1d2e5df5ba946715e4) --- specifyweb/specify/migrations/0002_geo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specifyweb/specify/migrations/0002_geo.py b/specifyweb/specify/migrations/0002_geo.py index b0a523d4316..a3c32bc4b2c 100644 --- a/specifyweb/specify/migrations/0002_geo.py +++ b/specifyweb/specify/migrations/0002_geo.py @@ -72,7 +72,7 @@ class Migration(migrations.Migration): def consolidated_python_django_migration_operations(apps, schema_editor): db_alias = schema_editor.connection.alias or 'migrator' - create_default_collection_types(apps, using=db_alias) + create_default_collection_types(apps) create_default_discipline_for_tree_defs(apps, using=db_alias) usc.create_geo_table_schema_config_with_defaults(apps) create_cogtype_type_picklist(apps, using=db_alias) From fac87e9759604cd7bd0f5e9cb40c17b242a32b19 Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Fri, 29 May 2026 11:50:31 +0200 Subject: [PATCH 021/113] Fix: Remove projects from legacy tests (cherry picked from commit 3da57613203f5e1927a599f6e05cfd28865e784c) --- specifyweb/backend/stored_queries/tests/tests_legacy.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/specifyweb/backend/stored_queries/tests/tests_legacy.py b/specifyweb/backend/stored_queries/tests/tests_legacy.py index cb34b27ae22..1090b60f30b 100644 --- a/specifyweb/backend/stored_queries/tests/tests_legacy.py +++ b/specifyweb/backend/stored_queries/tests/tests_legacy.py @@ -841,9 +841,6 @@ def test_sqlalchemy_model_errors(self): ] }, "CollectionObject": { - "not_found": [ - "projects" - ], "incorrect_direction": { "cojo": [ "onetomany", From c8663e9555d550b28c7c83570de30b92d948dff9 Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Fri, 29 May 2026 11:51:17 +0200 Subject: [PATCH 022/113] Fix: Change settings import (cherry picked from commit e07aaeb1bfc9d995397c5b5f316b9e1bc4fb747c) --- specifyweb/specify/api/utils.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/specifyweb/specify/api/utils.py b/specifyweb/specify/api/utils.py index 51a49c534e0..d35fb93147b 100644 --- a/specifyweb/specify/api/utils.py +++ b/specifyweb/specify/api/utils.py @@ -2,8 +2,7 @@ from specifyweb.specify import models as spmodels from specifyweb.backend.businessrules.exceptions import BusinessRuleException -from specifyweb import settings - +from django.conf import settings logger = logging.getLogger(__name__) From a940612541563cc1f59288f0c8ce203aa408f930 Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Fri, 29 May 2026 12:18:01 +0200 Subject: [PATCH 023/113] Fix:Incomplete field initialization in conditional createt (cherry picked from commit 36b307c593984c58100875823c556eccf99b9ed1) --- specifyweb/specify/migration_utils/update_schema_config.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/specifyweb/specify/migration_utils/update_schema_config.py b/specifyweb/specify/migration_utils/update_schema_config.py index d9092c0bbb0..57f53508398 100644 --- a/specifyweb/specify/migration_utils/update_schema_config.py +++ b/specifyweb/specify/migration_utils/update_schema_config.py @@ -425,6 +425,9 @@ def update_table_field_schema_config_with_defaults( name=table.name.lower(), discipline_id=discipline_id, schematype=table_config.schema_type, + ishidden=False, + issystem=table.system, + version=0, ) try: From 4e1d45a941aa2b87f1aac27a11b569e22f161a65 Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Fri, 29 May 2026 12:18:51 +0200 Subject: [PATCH 024/113] Fix: Incomplete field initialization in conditional create (cherry picked from commit d97acbdc546986eb90c5e2d9bc51bffd5eec1908) --- specifyweb/specify/migration_utils/update_schema_config.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/specifyweb/specify/migration_utils/update_schema_config.py b/specifyweb/specify/migration_utils/update_schema_config.py index 57f53508398..a7b0879b53f 100644 --- a/specifyweb/specify/migration_utils/update_schema_config.py +++ b/specifyweb/specify/migration_utils/update_schema_config.py @@ -557,6 +557,9 @@ def update_table_field_schema_config_params( name=table.name.lower(), discipline_id=discipline_id, schematype=table_config.schema_type, + ishidden=False, + issystem=table.system, + version=0, ) try: From e228051ef44f204f3ec2bc1f4f8297715578874f Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Fri, 29 May 2026 12:41:11 +0200 Subject: [PATCH 025/113] Fix: Put model name in lower case for consistency and reversability (cherry picked from commit d3c6c98ff850fb801189d029644bd4accda74bd6) --- specifyweb/specify/migration_utils/update_schema_config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specifyweb/specify/migration_utils/update_schema_config.py b/specifyweb/specify/migration_utils/update_schema_config.py index a7b0879b53f..75591205613 100644 --- a/specifyweb/specify/migration_utils/update_schema_config.py +++ b/specifyweb/specify/migration_utils/update_schema_config.py @@ -982,7 +982,7 @@ def update_cog_type_fields(apps): container_items = Splocalecontaineritem.objects.filter( name="collectionObjectType", picklistname=None, - container__name="Collectionobject", + container__name="collectionobject", ) for container_item in container_items: Splocaleitemstr.objects.filter(itemname=container_item).delete() From aff97b8fcf097c39b2559101937e6700ebbc31b2 Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Fri, 29 May 2026 12:42:01 +0200 Subject: [PATCH 026/113] Fix: Revert chnages (cherry picked from commit b183031a5f9c4aba4d8cdc0714081bf2c07d5c3b) --- specifyweb/specify/migrations/0002_geo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specifyweb/specify/migrations/0002_geo.py b/specifyweb/specify/migrations/0002_geo.py index a3c32bc4b2c..b0a523d4316 100644 --- a/specifyweb/specify/migrations/0002_geo.py +++ b/specifyweb/specify/migrations/0002_geo.py @@ -72,7 +72,7 @@ class Migration(migrations.Migration): def consolidated_python_django_migration_operations(apps, schema_editor): db_alias = schema_editor.connection.alias or 'migrator' - create_default_collection_types(apps) + create_default_collection_types(apps, using=db_alias) create_default_discipline_for_tree_defs(apps, using=db_alias) usc.create_geo_table_schema_config_with_defaults(apps) create_cogtype_type_picklist(apps, using=db_alias) From 1e13637e34e9f75bfb0e59d9908d6a2f0ccd4a9a Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Fri, 29 May 2026 12:43:45 +0200 Subject: [PATCH 027/113] Fix: Remove double id rank (cherry picked from commit 2e9e4ada672d04c115c198f584358cf59970a4eb) --- specifyweb/specify/migration_utils/tectonic_ranks.py | 1 - 1 file changed, 1 deletion(-) diff --git a/specifyweb/specify/migration_utils/tectonic_ranks.py b/specifyweb/specify/migration_utils/tectonic_ranks.py index b8f92b44788..34dd0e8baa0 100644 --- a/specifyweb/specify/migration_utils/tectonic_ranks.py +++ b/specifyweb/specify/migration_utils/tectonic_ranks.py @@ -125,7 +125,6 @@ def create_root_tectonic_node(apps): tectonic_tree_def_item, _ = TectonicUnitTreeDefItem.objects.get_or_create( name="Root", title="Root", - rankid=0, parent=None, treedef=tectonic_tree_def, rankid=0, From 624deeed2489286817d3a18a621d2e4f70ce9e47 Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Fri, 29 May 2026 13:01:01 +0200 Subject: [PATCH 028/113] Fix: Indentation (cherry picked from commit 2254fc4a5f418d254bd26ccfd18f1c24d0dc95f0) --- specifyweb/backend/stored_queries/execution.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specifyweb/backend/stored_queries/execution.py b/specifyweb/backend/stored_queries/execution.py index 3d56426f047..8450de1f3aa 100644 --- a/specifyweb/backend/stored_queries/execution.py +++ b/specifyweb/backend/stored_queries/execution.py @@ -1068,7 +1068,7 @@ def series_post_query(query, limit=40, offset=0, sort_type=0, co_id_cat_num_pair Sort the results by the first catnum in the range.""" if settings.DEBUG: - log_sqlalchemy_query(query) + log_sqlalchemy_query(query) def parse_catalog_for_comparing(s): def check_for_decimal(s): From cd740a7785b98aa0a7dd9d7c34e7727d1e654558 Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Fri, 29 May 2026 13:03:02 +0200 Subject: [PATCH 029/113] Fix: Add strict=False to allow diff length (cherry picked from commit 39b001a6a96c67855e0ff79809e4b0c7137554d7) --- specifyweb/specify/migration_utils/default_cots.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specifyweb/specify/migration_utils/default_cots.py b/specifyweb/specify/migration_utils/default_cots.py index d6545d9484c..74535e42926 100644 --- a/specifyweb/specify/migration_utils/default_cots.py +++ b/specifyweb/specify/migration_utils/default_cots.py @@ -145,7 +145,7 @@ def fix_tectonic_unit_treedef_discipline_links(apps): ) for discipline, tectonic_unit_treedef in zip( - empty_disciplines, empty_tectonic_unit_treedefs + empty_disciplines, empty_tectonic_unit_treedefs, strict=False ): tectonic_unit_treedef.discipline = discipline tectonic_unit_treedef.save() From 05f6298e7a1479810a85f74a6f98888667568291 Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Fri, 29 May 2026 13:07:46 +0200 Subject: [PATCH 030/113] Fix: Remove duplicate (cherry picked from commit d8bd82d0a63bcb2860bbb6f410570748c875fdf5) --- specifyweb/specify/migration_utils/tectonic_ranks.py | 1 - 1 file changed, 1 deletion(-) diff --git a/specifyweb/specify/migration_utils/tectonic_ranks.py b/specifyweb/specify/migration_utils/tectonic_ranks.py index 34dd0e8baa0..55dff146350 100644 --- a/specifyweb/specify/migration_utils/tectonic_ranks.py +++ b/specifyweb/specify/migration_utils/tectonic_ranks.py @@ -128,7 +128,6 @@ def create_root_tectonic_node(apps): parent=None, treedef=tectonic_tree_def, rankid=0, - parent=None, isenforced=True ) From cf79196a3ac0a783fbe64d82e0aa4cd20fef5edb Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Fri, 29 May 2026 13:17:04 +0200 Subject: [PATCH 031/113] Fix: Remove using from geo migration (cherry picked from commit 10ef24f93a6d90dffd7d1bb619109023535859d3) --- specifyweb/specify/migrations/0002_geo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specifyweb/specify/migrations/0002_geo.py b/specifyweb/specify/migrations/0002_geo.py index b0a523d4316..a3c32bc4b2c 100644 --- a/specifyweb/specify/migrations/0002_geo.py +++ b/specifyweb/specify/migrations/0002_geo.py @@ -72,7 +72,7 @@ class Migration(migrations.Migration): def consolidated_python_django_migration_operations(apps, schema_editor): db_alias = schema_editor.connection.alias or 'migrator' - create_default_collection_types(apps, using=db_alias) + create_default_collection_types(apps) create_default_discipline_for_tree_defs(apps, using=db_alias) usc.create_geo_table_schema_config_with_defaults(apps) create_cogtype_type_picklist(apps, using=db_alias) From c341f551699e1ff17ae1ee61c5c2cc4416bcadcd Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Fri, 29 May 2026 13:47:19 +0200 Subject: [PATCH 032/113] Fix: Bring back legacy project test (cherry picked from commit 8064ea1294f036cacadbb108085cb4f54ad79129) --- specifyweb/backend/stored_queries/tests/tests_legacy.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/specifyweb/backend/stored_queries/tests/tests_legacy.py b/specifyweb/backend/stored_queries/tests/tests_legacy.py index 1090b60f30b..cb34b27ae22 100644 --- a/specifyweb/backend/stored_queries/tests/tests_legacy.py +++ b/specifyweb/backend/stored_queries/tests/tests_legacy.py @@ -841,6 +841,9 @@ def test_sqlalchemy_model_errors(self): ] }, "CollectionObject": { + "not_found": [ + "projects" + ], "incorrect_direction": { "cojo": [ "onetomany", From 72414b6a049ff8b78c193797e3864cf1c8336098 Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Fri, 29 May 2026 14:31:13 +0200 Subject: [PATCH 033/113] Fix: Remove values_list() in favor of .all (cherry picked from commit 58265337a629e1d4dff948c8989bec48d83aa753) --- specifyweb/backend/businessrules/uniqueness_rules.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/specifyweb/backend/businessrules/uniqueness_rules.py b/specifyweb/backend/businessrules/uniqueness_rules.py index d5c389480f6..a5154fac24c 100644 --- a/specifyweb/backend/businessrules/uniqueness_rules.py +++ b/specifyweb/backend/businessrules/uniqueness_rules.py @@ -499,7 +499,8 @@ def fix_global_default_rules(registry=None): rule.modelName, rule.isDatabaseConstraint, frozenset( - rule.uniquenessrulefield_set.values_list("fieldPath", "isScope") + (field.fieldPath, field.isScope) + for field in rule.uniquenessrulefield_set.all() ), ) for rule in UniquenessRule.objects.filter( @@ -522,7 +523,8 @@ def fix_global_default_rules(registry=None): rule.modelName, rule.isDatabaseConstraint, frozenset( - rule.uniquenessrulefield_set.values_list("fieldPath", "isScope") + (field.fieldPath, field.isScope) + for field in rule.uniquenessrulefield_set.all() ), ) if signature in global_rule_signatures: From 7112c8476ae710b39f7dda73f8003aa20f455b55 Mon Sep 17 00:00:00 2001 From: melton-jason Date: Tue, 2 Jun 2026 12:14:50 -0500 Subject: [PATCH 034/113] fix: stop shadowing catnum unique in collection function for migration --- .../backend/businessrules/migration_utils.py | 70 ++++--------------- .../migrations/0004_catnum_uniquerule.py | 66 ++++++++++------- 2 files changed, 55 insertions(+), 81 deletions(-) diff --git a/specifyweb/backend/businessrules/migration_utils.py b/specifyweb/backend/businessrules/migration_utils.py index b8d82ba994a..8c132f7d334 100644 --- a/specifyweb/backend/businessrules/migration_utils.py +++ b/specifyweb/backend/businessrules/migration_utils.py @@ -1,75 +1,33 @@ -from typing import Tuple, List - -from specifyweb.backend.businessrules.uniqueness_rules import create_uniqueness_rule - - def catnum_rule_editable(apps, schema_editor=None): """ Find any CollectionObject catalogNumber must be unique to Collection rules which are readonly on the frontend (have isDatabaseConstraint=True) and set their isDatabaseConstraint=False. - + Generally should be run only after migration businessrules/0003 has been applied """ UniquenessRule = apps.get_model("businessrules", "UniquenessRule") - - model_rules = UniquenessRule.objects.filter(modelName="Collectionobject", isDatabaseConstraint=True) - catalog_number_rules: List[int] = [] - for rule in model_rules: + model_rules = UniquenessRule.objects.filter( + modelName="Collectionobject", + isDatabaseConstraint=True + ) + + catalog_number_rules: list[int] = [] + for rule in model_rules: rule_fields = rule.uniquenessrulefield_set.all() fields = rule_fields.filter(isScope=False) scopes = rule_fields.filter(isScope=True) - # We're only interested in the rule "CollectionObject catalogNumber + # We're only interested in the rule "CollectionObject catalogNumber # must be unique to Collection" - # We check for length of fields and scopes because get() raises an + # We check for length of fields and scopes because get() raises an # exception if more than one result is returned - if (len(fields) == 1 and len(scopes) == 1) and (fields.get().fieldPath.lower() == "catalognumber" and scopes.get().fieldPath.lower() == "collection"): + if (len(fields) == 1 and len(scopes) == 1) and ( + fields.get().fieldPath.lower() == "catalognumber" + and scopes.get().fieldPath.lower() == "collection"): catalog_number_rules.append(rule.id) - + rules_to_update = UniquenessRule.objects.filter(id__in=catalog_number_rules) rules_to_update.update(isDatabaseConstraint=False) - - -def catnum_rule_uneditable(apps, schema_editor=None): - """ Find any CollectionObject catalogNumber must be unique to Collection - rules which are editable on the frontend (have isDatabaseConstraint=False) - and set their isDatabaseConstraint=True. - - Generally should be run when migration businessrules/0003 is being reverted - """ - Discipline = apps.get_model("specify", "Discipline") - UniquenessRule = apps.get_model("businessrules", "UniquenessRule") - - for discipline in Discipline.objects.all(): - model_rules = UniquenessRule.objects.filter(modelName="Collectionobject", discipline_id=discipline.id, isDatabaseConstraint=False) - - has_catalognumber_rule = False - matching_rule_ids: List[int] = [] - for rule in model_rules: - rule_fields = rule.uniquenessrulefield_set.all() - - fields = rule_fields.filter(isScope=False) - scopes = rule_fields.filter(isScope=True) - - # We're only interested in the rule "CollectionObject catalogNumber - # must be unique to Collection" - # We check for length of fields and scopes because get() raises an - # exception if more than one result is returned - if (len(fields) == 1 and len(scopes) == 1) and (fields.get().fieldPath.lower() == "catalognumber" and scopes.get().fieldPath.lower() == "collection"): - has_catalognumber_rule = True - matching_rule_ids.append(rule.id) - - if has_catalognumber_rule: - UniquenessRule.objects.filter(id__in=matching_rule_ids).update(isDatabaseConstraint=True) - else: - create_uniqueness_rule( - model_name="Collectionobject", - discipline=discipline, - is_database_constraint=True, - fields=["catalogNumber"], - scopes=["collection"], - registry=apps, - ) diff --git a/specifyweb/backend/businessrules/migrations/0004_catnum_uniquerule.py b/specifyweb/backend/businessrules/migrations/0004_catnum_uniquerule.py index 77f61d74103..b35a3283d67 100644 --- a/specifyweb/backend/businessrules/migrations/0004_catnum_uniquerule.py +++ b/specifyweb/backend/businessrules/migrations/0004_catnum_uniquerule.py @@ -1,42 +1,57 @@ from django.db import migrations -from specifyweb.backend.businessrules.migration_utils import catnum_rule_editable, catnum_rule_uneditable +from specifyweb.backend.businessrules.migration_utils import catnum_rule_editable from specifyweb.backend.businessrules.uniqueness_rules import create_uniqueness_rule -def catnum_rule_editable(apps, schema_editor): - UniquenessRule = apps.get_model('businessrules', 'UniquenessRule') - UniquenessRuleField = apps.get_model('businessrules', 'UniquenessRuleField') - - candidate_rules_with_field: tuple[int] = tuple(UniquenessRuleField.objects.filter(uniquenessrule__modelName__iexact='collectionobject', uniquenessrule__isDatabaseConstraint=True, fieldPath__iexact='catalognumber', isScope=False).values_list('uniquenessrule_id', flat=True)) +def catnum_rule_uneditable(apps, schema_editor): + """ Find any CollectionObject catalogNumber must be unique to Collection + rules which are editable on the frontend (have isDatabaseConstraint=False) + and set their isDatabaseConstraint=True. - candidate_rules_with_scope: tuple[int] = tuple(UniquenessRuleField.objects.filter(uniquenessrule_id__in=candidate_rules_with_field, fieldPath__iexact='collection', isScope=True).values_list('uniquenessrule_id', flat=True)) + Generally should be run when migration businessrules/0003 is being reverted + """ + Discipline = apps.get_model("specify", "Discipline") + UniquenessRule = apps.get_model("businessrules", "UniquenessRule") - candidate_rules = UniquenessRule.objects.filter(id__in=candidate_rules_with_scope) - candidate_rules.update(isDatabaseConstraint=False) + for discipline in Discipline.objects.all(): + # REFACTOR: Some of these queries should be able to be combined to + # improve performance and limit how often we need to hit the database + model_rules = UniquenessRule.objects.filter( + modelName="Collectionobject", + discipline_id=discipline.id, + isDatabaseConstraint=False + ) -def catnum_rule_uneditable(apps, schema_editor): - Discipline = apps.get_model('specify', 'Discipline') - UniquenessRule = apps.get_model('businessrules', 'UniquenessRule') - UniquenessRuleField = apps.get_model('businessrules', 'UniquenessRuleField') + has_catalognumber_rule = False + matching_rule_ids: list[int] = [] + for rule in model_rules: + rule_fields = rule.uniquenessrulefield_set.all() - for discipline in Discipline.objects.all(): - candidate_rules_with_field: tuple[int] = tuple(UniquenessRuleField.objects.filter(uniquenessrule__modelName__iexact='collectionobject', uniquenessrule__discipline=discipline.id, uniquenessrule__isDatabaseConstraint=False, fieldPath__iexact='catalognumber', isScope=False).values_list('uniquenessrule_id', flat=True)) + fields = rule_fields.filter(isScope=False) + scopes = rule_fields.filter(isScope=True) - candidate_rules_with_scope: tuple[int] = tuple(UniquenessRuleField.objects.filter(uniquenessrule_id__in=candidate_rules_with_field, fieldPath__iexact='collection', isScope=True).values_list('uniquenessrule_id', flat=True)) + # We're only interested in the rule "CollectionObject catalogNumber + # must be unique to Collection" + # We check for length of fields and scopes because get() raises an + # exception if more than one result is returned + if (len(fields) == 1 and len(scopes) == 1) and (fields.get().fieldPath.lower() == "catalognumber" and scopes.get().fieldPath.lower() == "collection"): + has_catalognumber_rule = True + matching_rule_ids.append(rule.id) - candidate_rules = UniquenessRule.objects.filter(id__in=candidate_rules_with_scope) - if len(candidate_rules) == 0: + if has_catalognumber_rule: + UniquenessRule.objects.filter( + id__in=matching_rule_ids).update(isDatabaseConstraint=True) + else: create_uniqueness_rule( - model_name='Collectionobject', + model_name="Collectionobject", discipline=discipline, is_database_constraint=True, - fields=['catalogNumber'], - scopes=['collection'], - registry=apps + fields=["catalogNumber"], + scopes=["collection"], + registry=apps, ) - else: - candidate_rules.update(isDatabaseConstraint=True) + class Migration(migrations.Migration): dependencies = [ @@ -44,5 +59,6 @@ class Migration(migrations.Migration): ] operations = [ - migrations.RunPython(catnum_rule_editable, catnum_rule_uneditable, atomic=True) + migrations.RunPython(catnum_rule_editable, + catnum_rule_uneditable, atomic=True) ] From eda65ab4553ddd7775ddfb0a93c5234b46af247c Mon Sep 17 00:00:00 2001 From: melton-jason Date: Tue, 2 Jun 2026 12:19:14 -0500 Subject: [PATCH 035/113] refactor: improve readability of condition when enabling editable uniqueness rule --- specifyweb/backend/businessrules/migration_utils.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/specifyweb/backend/businessrules/migration_utils.py b/specifyweb/backend/businessrules/migration_utils.py index 8c132f7d334..0bea9455998 100644 --- a/specifyweb/backend/businessrules/migration_utils.py +++ b/specifyweb/backend/businessrules/migration_utils.py @@ -24,9 +24,7 @@ def catnum_rule_editable(apps, schema_editor=None): # must be unique to Collection" # We check for length of fields and scopes because get() raises an # exception if more than one result is returned - if (len(fields) == 1 and len(scopes) == 1) and ( - fields.get().fieldPath.lower() == "catalognumber" - and scopes.get().fieldPath.lower() == "collection"): + if (len(fields) == 1 and len(scopes) == 1) and (fields.get().fieldPath.lower() == "catalognumber" and scopes.get().fieldPath.lower() == "collection"): catalog_number_rules.append(rule.id) rules_to_update = UniquenessRule.objects.filter(id__in=catalog_number_rules) From 6e37e1e9e43d141270637061c5f66c5fa27c03a0 Mon Sep 17 00:00:00 2001 From: melton-jason Date: Wed, 3 Jun 2026 09:06:50 -0500 Subject: [PATCH 036/113] fix: simplify fix_global_rules helper function --- .../backend/businessrules/uniqueness_rules.py | 49 ++++++++++--------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/specifyweb/backend/businessrules/uniqueness_rules.py b/specifyweb/backend/businessrules/uniqueness_rules.py index a5154fac24c..24b3cc39bc6 100644 --- a/specifyweb/backend/businessrules/uniqueness_rules.py +++ b/specifyweb/backend/businessrules/uniqueness_rules.py @@ -490,6 +490,15 @@ def rule_is_global(scopes: Iterable[str]) -> bool: def fix_global_default_rules(registry=None): + """ + Removes UniquenessRules that are scoped to Discipline that already exist + globally. + + There were historically cases where UniquenessRules were incorrectly + created in two places: globally and scoped to a particular discipline. + + See https://github.com/specify/specify7/pull/6308#issuecomment-3247556491 + """ UniquenessRule = registry.get_model('businessrules', 'UniquenessRule') \ if registry \ else models.UniquenessRule @@ -508,25 +517,21 @@ def fix_global_default_rules(registry=None): ).prefetch_related("uniquenessrulefield_set") } - discipline_ids = ( - UniquenessRule.objects.exclude(discipline__isnull=True) - .values_list("discipline_id", flat=True) - .distinct() - ) - - for discipline_id in discipline_ids: - with transaction.atomic(): - for rule in UniquenessRule.objects.filter( - discipline_id=discipline_id - ).prefetch_related("uniquenessrulefield_set"): - signature = ( - rule.modelName, - rule.isDatabaseConstraint, - frozenset( - (field.fieldPath, field.isScope) - for field in rule.uniquenessrulefield_set.all() - ), - ) - if signature in global_rule_signatures: - rule.uniquenessrulefield_set.all().delete() - rule.delete() + with transaction.atomic(): + # REFACTOR: See if we can simplify this even further. We should be able + # to collapse this query -> iteration -> check workflow to a single + # query. + # That would eliminate the N + 1 problem with this current approach, + # where every scoped rule needs to be evaluated. + for rule in UniquenessRule.objects.exclude(discipline__isnull=True).prefetch_related("uniquenessrulefield_set"): + signature = ( + rule.modelName, + rule.isDatabaseConstraint, + frozenset( + (field.fieldPath, field.isScope) + for field in rule.uniquenessrulefield_set.all() + ), + ) + if signature in global_rule_signatures: + rule.uniquenessrulefield_set.all().delete() + rule.delete() From 48face1bab8e85eb87e3c439e077914913abde84 Mon Sep 17 00:00:00 2001 From: melton-jason Date: Wed, 3 Jun 2026 09:28:26 -0500 Subject: [PATCH 037/113] fix: use manager over base manager for tree patches --- specifyweb/backend/patches/migration_utils.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/specifyweb/backend/patches/migration_utils.py b/specifyweb/backend/patches/migration_utils.py index 9da3812d35b..bd69198bf6f 100644 --- a/specifyweb/backend/patches/migration_utils.py +++ b/specifyweb/backend/patches/migration_utils.py @@ -19,7 +19,7 @@ def update_is_accepted(app_registry, schema_editor=None): } tree_model = app_registry.get_model("specify", tree) - tree_model._base_manager.using(db_alias).filter(**tree_filters).update(isaccepted=True) + tree_model.objects.using(db_alias).filter(**tree_filters).update(isaccepted=True) def update_coordinates(app_registry, schema_editor=None): @@ -27,14 +27,18 @@ def update_coordinates(app_registry, schema_editor=None): Locality = app_registry.get_model("specify", "Locality") - Locality._base_manager.using(db_alias).filter(lat1text__isnull=True, latitude1__isnull=False) \ + Locality.objects.using(db_alias) \ + .filter(lat1text__isnull=True, latitude1__isnull=False) \ .update(lat1text=F("latitude1")) - Locality._base_manager.using(db_alias).filter(long1text__isnull=True, longitude1__isnull=False) \ + Locality.objects.using(db_alias) \ + .filter(long1text__isnull=True, longitude1__isnull=False) \ .update(long1text=F("longitude1")) - Locality._base_manager.using(db_alias).filter(lat2text__isnull=True, latitude2__isnull=False) \ + Locality.objects.using(db_alias) \ + .filter(lat2text__isnull=True, latitude2__isnull=False) \ .update(lat2text=F("latitude2")) - Locality._base_manager.using(db_alias).filter(long2text__isnull=True, longitude2__isnull=False) \ + Locality.objects.using(db_alias) \ + .filter(long2text__isnull=True, longitude2__isnull=False) \ .update(long2text=F("longitude2")) From fdfe21beb7c9370d31d5ec155be8fc7bbb2fd7ea Mon Sep 17 00:00:00 2001 From: melton-jason Date: Wed, 3 Jun 2026 10:21:39 -0500 Subject: [PATCH 038/113] fix: remove check for old newly created DBs in specify 7 --- specifyweb/backend/permissions/initialize.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/specifyweb/backend/permissions/initialize.py b/specifyweb/backend/permissions/initialize.py index ac5e2cc3c94..2e7df7fd301 100644 --- a/specifyweb/backend/permissions/initialize.py +++ b/specifyweb/backend/permissions/initialize.py @@ -99,8 +99,6 @@ def assign_users_to_roles(apps=apps) -> None: WHERE table_name IN ('specifyuser_spprincipal', 'spuserrole') AND table_schema = DATABASE(); """) - if cursor.fetchone()[0] < 2: - return # Newly created sp7 databases don't have these sp6 specific tables. cursor.execute(""" SELECT u.SpecifyUserID as user_id, From 96bf0ccb5153fe0435d8372058ba3984a5eedc01 Mon Sep 17 00:00:00 2001 From: melton-jason Date: Wed, 3 Jun 2026 10:35:35 -0500 Subject: [PATCH 039/113] fix: bring back is_sp6_user_permissions_migrated --- specifyweb/backend/permissions/initialize.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/specifyweb/backend/permissions/initialize.py b/specifyweb/backend/permissions/initialize.py index 2e7df7fd301..f2374ab4d8f 100644 --- a/specifyweb/backend/permissions/initialize.py +++ b/specifyweb/backend/permissions/initialize.py @@ -55,6 +55,14 @@ def create_admins(apps=apps) -> None: users = Specifyuser.objects.all() for user in users: + # REFACTOR: Try and fold the following checks into a single query to + # avoid making multiple queries per user. + # Ideally, we only make a single query to fetch all users that: + # - Are not already Institution Admins + # - Have not already seen activity in Sp 7 (don't have Sp7 permissions) + # - (The Institution Admin permission could have been intentionally + # removed) + # - Are admins in Sp 6 if UserPolicy.objects.filter( collection__isnull=True, specifyuser_id=user.id, @@ -62,6 +70,8 @@ def create_admins(apps=apps) -> None: action="%", ).exists(): continue + if is_sp6_user_permissions_migrated(user=user, apps=apps): + continue if is_legacy_admin(user): UserPolicy.objects.get_or_create( collection=None, @@ -123,7 +133,7 @@ def assign_users_to_roles(apps=apps) -> None: results = cursor.fetchall() for user_id, user_name, user_type, collection_id, collection_name in results: - if user_type not in {'Manager', 'FullAccess', 'LimitedAccess', 'Guest'}: + if user_type not in ROLE_NAMES.keys(): continue role_name = ROLE_NAMES.get(user_type, f"{user_type} - {collection_name}") From cfad41f6c632adfb0791643807a50a10b5702392 Mon Sep 17 00:00:00 2001 From: melton-jason Date: Wed, 3 Jun 2026 10:51:38 -0500 Subject: [PATCH 040/113] fix: change ordering of admin checks to evaluate more common first --- specifyweb/backend/permissions/initialize.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/specifyweb/backend/permissions/initialize.py b/specifyweb/backend/permissions/initialize.py index f2374ab4d8f..3cef7a1b157 100644 --- a/specifyweb/backend/permissions/initialize.py +++ b/specifyweb/backend/permissions/initialize.py @@ -63,6 +63,12 @@ def create_admins(apps=apps) -> None: # - (The Institution Admin permission could have been intentionally # removed) # - Are admins in Sp 6 + + # The ordering here for checks here is intentional: it's more likely a + # user has Sp 7 permissions than being an admin, so we do the former + # check first + if is_sp6_user_permissions_migrated(user=user, apps=apps): + continue if UserPolicy.objects.filter( collection__isnull=True, specifyuser_id=user.id, @@ -70,8 +76,6 @@ def create_admins(apps=apps) -> None: action="%", ).exists(): continue - if is_sp6_user_permissions_migrated(user=user, apps=apps): - continue if is_legacy_admin(user): UserPolicy.objects.get_or_create( collection=None, From 2e1835ef0b666cc8b16e9a0f886624fc7b44ecfe Mon Sep 17 00:00:00 2001 From: melton-jason Date: Wed, 3 Jun 2026 11:02:18 -0500 Subject: [PATCH 041/113] fix: remove unused query --- specifyweb/backend/permissions/initialize.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/specifyweb/backend/permissions/initialize.py b/specifyweb/backend/permissions/initialize.py index 3cef7a1b157..a85653bda9d 100644 --- a/specifyweb/backend/permissions/initialize.py +++ b/specifyweb/backend/permissions/initialize.py @@ -107,12 +107,6 @@ def assign_users_to_roles(apps=apps) -> None: results = [] with connection.cursor() as cursor: - cursor.execute(""" - SELECT COUNT(*) - FROM information_schema.tables - WHERE table_name IN ('specifyuser_spprincipal', 'spuserrole') - AND table_schema = DATABASE(); - """) cursor.execute(""" SELECT u.SpecifyUserID as user_id, From f4d6491a2b8f2556480668a0c5c226c9a80543c5 Mon Sep 17 00:00:00 2001 From: melton-jason Date: Wed, 3 Jun 2026 11:08:15 -0500 Subject: [PATCH 042/113] refactor: use defaults in get_or_create for Roles --- specifyweb/backend/permissions/initialize.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/specifyweb/backend/permissions/initialize.py b/specifyweb/backend/permissions/initialize.py index a85653bda9d..b0339e27887 100644 --- a/specifyweb/backend/permissions/initialize.py +++ b/specifyweb/backend/permissions/initialize.py @@ -138,13 +138,13 @@ def assign_users_to_roles(apps=apps) -> None: role_description = ROLE_DESCRIPTIONS.get(user_type, "No description available.") logger.info(f"Assigned user {user_name} to role {role_name} for collection {collection_name}.") - role, is_new_role = Role.objects.get_or_create( + role, _ = Role.objects.get_or_create( collection_id=collection_id, - name=role_name + name=role_name, + defaults={ + "description": role_description + } ) - if is_new_role: - role.description = role_description - role.save() UserRole.objects.get_or_create( specifyuser_id=user_id, role=role From f792d5eadf01f7d7d49f536d85ae0578f86c0fbb Mon Sep 17 00:00:00 2001 From: melton-jason Date: Wed, 3 Jun 2026 11:09:56 -0500 Subject: [PATCH 043/113] chore: add refactor note --- specifyweb/backend/permissions/initialize.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/specifyweb/backend/permissions/initialize.py b/specifyweb/backend/permissions/initialize.py index b0339e27887..85fdf8f210d 100644 --- a/specifyweb/backend/permissions/initialize.py +++ b/specifyweb/backend/permissions/initialize.py @@ -131,6 +131,8 @@ def assign_users_to_roles(apps=apps) -> None: results = cursor.fetchall() for user_id, user_name, user_type, collection_id, collection_name in results: + # REFACTOR: If we want to exlcude all other roles, why don't we write + # the exlcusion in the query rather than evaluate in Python? if user_type not in ROLE_NAMES.keys(): continue From 91aaf387a33583f9ad0172717fdef76232c80d71 Mon Sep 17 00:00:00 2001 From: melton-jason Date: Wed, 3 Jun 2026 12:54:14 -0500 Subject: [PATCH 044/113] refactor: move DEBUG check into log_sqlalchemy_query --- specifyweb/backend/stored_queries/execution.py | 8 ++------ specifyweb/backend/stored_queries/utils.py | 4 +++- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/specifyweb/backend/stored_queries/execution.py b/specifyweb/backend/stored_queries/execution.py index 8450de1f3aa..0aa0c33ea18 100644 --- a/specifyweb/backend/stored_queries/execution.py +++ b/specifyweb/backend/stored_queries/execution.py @@ -856,10 +856,7 @@ def execute( if limit: query = query.limit(limit) - - - if settings.DEBUG: - log_sqlalchemy_query(query) + log_sqlalchemy_query(query) return {"results": apply_special_post_query_processing(query, tableid, field_specs, collection, user)} @@ -1067,8 +1064,7 @@ def series_post_query(query, limit=40, offset=0, sort_type=0, co_id_cat_num_pair and adding a co_id colum and formatted catnum range column. Sort the results by the first catnum in the range.""" - if settings.DEBUG: - log_sqlalchemy_query(query) + log_sqlalchemy_query(query) def parse_catalog_for_comparing(s): def check_for_decimal(s): diff --git a/specifyweb/backend/stored_queries/utils.py b/specifyweb/backend/stored_queries/utils.py index 64cd49b1944..f25921f3023 100644 --- a/specifyweb/backend/stored_queries/utils.py +++ b/specifyweb/backend/stored_queries/utils.py @@ -7,6 +7,8 @@ from sqlalchemy.sql.selectable import Select from sqlalchemy.sql.sqltypes import NullType +from django.conf import settings + logger = logging.getLogger(__name__) def _coerce_statement(obj: Any) -> ClauseElement: @@ -50,7 +52,7 @@ def log_sqlalchemy_query( Run in the stored_queries.execute file, in the execute function, right before the return statement: from specifyweb.specify.utils import log_sqlalchemy_query; log_sqlalchemy_query(query) """ - if not logger.isEnabledFor(level): + if not logger.isEnabledFor(level) or not settings.DEBUG: return None # skip compiling and logging if we're not logging at this level dialect = dialect or mysql_dialect.dialect() From 6b4d796c281b7d2bb54f7257770db9dafc185d22 Mon Sep 17 00:00:00 2001 From: melton-jason Date: Wed, 3 Jun 2026 12:56:24 -0500 Subject: [PATCH 045/113] fix: remove unused log_sqlalchemy_query function --- specifyweb/specify/api/utils.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/specifyweb/specify/api/utils.py b/specifyweb/specify/api/utils.py index d35fb93147b..0bd8afe81fd 100644 --- a/specifyweb/specify/api/utils.py +++ b/specifyweb/specify/api/utils.py @@ -19,19 +19,6 @@ def get_spmodel_class(model_name: str): return getattr(spmodels, attr_name) raise AttributeError(f"Model '{model_name}' not found in models module.") -def log_sqlalchemy_query(query): - if not settings.DEBUG: - return - - from sqlalchemy.dialects import mysql - compiled_query = query.statement.compile(dialect=mysql.dialect()) - raw_sql = str(compiled_query).replace('\n', ' ') + ';' - logger.debug('='.join(['' for _ in range(80)])) - logger.debug(raw_sql) - logger.debug('='.join(['' for _ in range(80)])) - # Run in the storred_queries.execute file, in the execute function, right before the return statement, line 546 - # from specifyweb.specify.utils import log_sqlalchemy_query; log_sqlalchemy_query(query) - def create_default_collection_types(apps, using="default"): db = using or "default" From ab8320b77c4f537a76625dfccfcaa7eac9c8bf6e Mon Sep 17 00:00:00 2001 From: melton-jason Date: Wed, 3 Jun 2026 15:18:34 -0500 Subject: [PATCH 046/113] fix: incorrect Discipline -> tectonicunittreedef pairing when resolving links --- .../specify/migration_utils/default_cots.py | 64 +++++++++++++------ 1 file changed, 45 insertions(+), 19 deletions(-) diff --git a/specifyweb/specify/migration_utils/default_cots.py b/specifyweb/specify/migration_utils/default_cots.py index 74535e42926..c074ce2c27e 100644 --- a/specifyweb/specify/migration_utils/default_cots.py +++ b/specifyweb/specify/migration_utils/default_cots.py @@ -1,5 +1,5 @@ import logging -from django.db.models import F +from django.db.models import F, OuterRef, Subquery logger = logging.getLogger(__name__) @@ -137,25 +137,51 @@ def fix_tectonic_unit_treedef_discipline_links(apps): Discipline = apps.get_model('specify', 'Discipline') Tectonicunittreedef = apps.get_model('specify', 'Tectonicunittreedef') - empty_tectonic_unit_treedefs = list( - Tectonicunittreedef.objects.filter(discipline__isnull=True).order_by('id') + # Fetches Discipline objects with an empty TectonicUnitTreeDef relationship + # and no TectonicUnitTreeDef objects with a set discipline + # Most commonly, this would be in the case of creating a Discipline in + # Specify 6 after the TectonicUnitTreeDef migrations have been run in + # Specify 7 + disciplines_missing_tectonicunit = Discipline.objects.filter( + tectonicunittreedef__isnull=True, + tectonicunittreedefs__isnull=True + ).values_list("pk", "name") + + Tectonicunittreedef.objects.bulk_create( + [ + Tectonicunittreedef( + name=f"{discipline_name} Tectonic Unit Tree", + discipline_id=disciplineid + ) for disciplineid, discipline_name in disciplines_missing_tectonicunit + ], + batch_size=1000 ) - empty_disciplines = list( - Discipline.objects.filter(tectonicunittreedef__isnull=True).order_by('id') + + # If there are cases where Discipline -> tectonicunittreedef is not set, + # but there is at least one TectonicUnitTreeDef pointing to the Discipline, + # then set the Discipline -> tectonicunittreedef relationship to the "first" + # TectonicUnitTreeDef -> discipline + Discipline.objects.filter( + tectonicunittreedef__isnull=True, + tectonicunittreedefs__isnull=False + ).update( + tectonicunittreedef=Subquery( + Tectonicunittreedef.objects.filter( + discipline=OuterRef("pk") + ).order_by("pk").values("pk")[:1] + ) ) - for discipline, tectonic_unit_treedef in zip( - empty_disciplines, empty_tectonic_unit_treedefs, strict=False - ): - tectonic_unit_treedef.discipline = discipline - tectonic_unit_treedef.save() - discipline.tectonicunittreedef = tectonic_unit_treedef - discipline.save() - - for discipline in empty_disciplines[len(empty_tectonic_unit_treedefs):]: - tectonic_unit_treedef = Tectonicunittreedef.objects.create( - name=f'{discipline.name} Tectonic Unit Tree', - discipline=discipline + # Finally, if there's any remaining TectonicUnitTreeDef objects with a NULL + # discipline, set the discipline relationship to the + # Discipline -> tectonicunittreedef (which must be set at this point) + Tectonicunittreedef.objects.filter( + discipline__isnull=True, + disciplines__isnull=False + ).update( + discipline=Subquery( + Discipline.objects.filter( + tectonicunittreedef=OuterRef("pk") + ).order_by("pk").values("pk")[:1] ) - discipline.tectonicunittreedef = tectonic_unit_treedef - discipline.save() \ No newline at end of file + ) From 4196c1e0859de2e876441c535e5d8abe6fef710b Mon Sep 17 00:00:00 2001 From: melton-jason Date: Wed, 3 Jun 2026 15:54:04 -0500 Subject: [PATCH 047/113] refactor: optimize fix_taxon_treedef_discipline_links to one query --- .../specify/migration_utils/default_cots.py | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/specifyweb/specify/migration_utils/default_cots.py b/specifyweb/specify/migration_utils/default_cots.py index c074ce2c27e..0b027d98bfe 100644 --- a/specifyweb/specify/migration_utils/default_cots.py +++ b/specifyweb/specify/migration_utils/default_cots.py @@ -125,13 +125,22 @@ def fix_taxon_treedef_discipline_links(apps): Discipline = apps.get_model('specify', 'Discipline') Taxontreedef = apps.get_model('specify', 'Taxontreedef') - empty_taxon_treedefs = Taxontreedef.objects.filter(discipline__isnull=True) - disciplines = Discipline.objects.all() - for empty_taxon_treedef in empty_taxon_treedefs: - for discipline in disciplines: - if discipline.taxontreedef_id == empty_taxon_treedef.id: - empty_taxon_treedef.discipline = discipline - empty_taxon_treedef.save() + # If a TaxonTreeDef has a NULL DisciplineID but there's a non-NULL + # Discipline pointing to the TaxonTreeDef via Discipline -> TaxonTreeDefID, + # then set the discipline on the TaxonTreeDef to the referencing Discipline + Taxontreedef.objects.filter( + discipline__isnull=True + ).update( + discipline=Subquery( + Discipline.objects.filter( + taxontreedef=OuterRef("pk") + ).order_by("pk").values("pk")[:1] + ) + ) + + # BUG?: We're not handling the case here when Discipline has a NULL + # TaxonTreeDefID but there's a TaxonTreeDef pointing to the Discipline via + # TaxonTreeDef -> discipline def fix_tectonic_unit_treedef_discipline_links(apps): Discipline = apps.get_model('specify', 'Discipline') From 6e1902eb13bab9fbce89cd7d18139001622139ce Mon Sep 17 00:00:00 2001 From: melton-jason Date: Wed, 3 Jun 2026 16:01:54 -0500 Subject: [PATCH 048/113] refactor: move fix_tectonic_links to TectonicUnit file --- .../commands/run_key_migration_functions.py | 5 +- .../specify/migration_utils/default_cots.py | 53 ----------------- .../specify/migration_utils/tectonic_ranks.py | 58 ++++++++++++++++++- 3 files changed, 59 insertions(+), 57 deletions(-) diff --git a/specifyweb/specify/management/commands/run_key_migration_functions.py b/specifyweb/specify/management/commands/run_key_migration_functions.py index 29dd22cd285..789573eb801 100644 --- a/specifyweb/specify/management/commands/run_key_migration_functions.py +++ b/specifyweb/specify/management/commands/run_key_migration_functions.py @@ -17,13 +17,12 @@ create_default_collection_types, create_default_discipline_for_tree_defs, fix_taxon_treedef_discipline_links, - set_discipline_for_taxon_treedefs, - fix_tectonic_unit_treedef_discipline_links + set_discipline_for_taxon_treedefs ) from specifyweb.backend.permissions.initialize import initialize from specifyweb.specify.migration_utils import update_schema_config as usc from specifyweb.specify.migration_utils.misc_migrations import make_selectseries_false -from specifyweb.specify.migration_utils.tectonic_ranks import create_default_tectonic_ranks, create_root_tectonic_node +from specifyweb.specify.migration_utils.tectonic_ranks import create_default_tectonic_ranks, create_root_tectonic_node, fix_tectonic_unit_treedef_discipline_links from specifyweb.backend.patches.migration_utils import apply_migrations as apply_patches logger = logging.getLogger(__name__) diff --git a/specifyweb/specify/migration_utils/default_cots.py b/specifyweb/specify/migration_utils/default_cots.py index 0b027d98bfe..7f144eca95d 100644 --- a/specifyweb/specify/migration_utils/default_cots.py +++ b/specifyweb/specify/migration_utils/default_cots.py @@ -141,56 +141,3 @@ def fix_taxon_treedef_discipline_links(apps): # BUG?: We're not handling the case here when Discipline has a NULL # TaxonTreeDefID but there's a TaxonTreeDef pointing to the Discipline via # TaxonTreeDef -> discipline - -def fix_tectonic_unit_treedef_discipline_links(apps): - Discipline = apps.get_model('specify', 'Discipline') - Tectonicunittreedef = apps.get_model('specify', 'Tectonicunittreedef') - - # Fetches Discipline objects with an empty TectonicUnitTreeDef relationship - # and no TectonicUnitTreeDef objects with a set discipline - # Most commonly, this would be in the case of creating a Discipline in - # Specify 6 after the TectonicUnitTreeDef migrations have been run in - # Specify 7 - disciplines_missing_tectonicunit = Discipline.objects.filter( - tectonicunittreedef__isnull=True, - tectonicunittreedefs__isnull=True - ).values_list("pk", "name") - - Tectonicunittreedef.objects.bulk_create( - [ - Tectonicunittreedef( - name=f"{discipline_name} Tectonic Unit Tree", - discipline_id=disciplineid - ) for disciplineid, discipline_name in disciplines_missing_tectonicunit - ], - batch_size=1000 - ) - - # If there are cases where Discipline -> tectonicunittreedef is not set, - # but there is at least one TectonicUnitTreeDef pointing to the Discipline, - # then set the Discipline -> tectonicunittreedef relationship to the "first" - # TectonicUnitTreeDef -> discipline - Discipline.objects.filter( - tectonicunittreedef__isnull=True, - tectonicunittreedefs__isnull=False - ).update( - tectonicunittreedef=Subquery( - Tectonicunittreedef.objects.filter( - discipline=OuterRef("pk") - ).order_by("pk").values("pk")[:1] - ) - ) - - # Finally, if there's any remaining TectonicUnitTreeDef objects with a NULL - # discipline, set the discipline relationship to the - # Discipline -> tectonicunittreedef (which must be set at this point) - Tectonicunittreedef.objects.filter( - discipline__isnull=True, - disciplines__isnull=False - ).update( - discipline=Subquery( - Discipline.objects.filter( - tectonicunittreedef=OuterRef("pk") - ).order_by("pk").values("pk")[:1] - ) - ) diff --git a/specifyweb/specify/migration_utils/tectonic_ranks.py b/specifyweb/specify/migration_utils/tectonic_ranks.py index 55dff146350..abc50ef358b 100644 --- a/specifyweb/specify/migration_utils/tectonic_ranks.py +++ b/specifyweb/specify/migration_utils/tectonic_ranks.py @@ -1,4 +1,7 @@ import logging + +from django.db.models import OuterRef, Subquery + logger = logging.getLogger(__name__) def create_default_tectonic_ranks(apps): @@ -164,4 +167,57 @@ def revert_create_root_tectonic_node(apps, schema_editor=None): definition=tectonic_tree_def, parent__isnull=True, ).delete() - TectonicUnitTreeDefItem.objects.filter(treedef=tectonic_tree_def).delete() \ No newline at end of file + TectonicUnitTreeDefItem.objects.filter(treedef=tectonic_tree_def).delete() + +def fix_tectonic_unit_treedef_discipline_links(apps): + Discipline = apps.get_model('specify', 'Discipline') + Tectonicunittreedef = apps.get_model('specify', 'Tectonicunittreedef') + + # Fetches Discipline objects with an empty TectonicUnitTreeDef relationship + # and no TectonicUnitTreeDef objects with a set discipline + # Most commonly, this would be in the case of creating a Discipline in + # Specify 6 after the TectonicUnitTreeDef migrations have been run in + # Specify 7 + disciplines_missing_tectonicunit = Discipline.objects.filter( + tectonicunittreedef__isnull=True, + tectonicunittreedefs__isnull=True + ).values_list("pk", "name") + + Tectonicunittreedef.objects.bulk_create( + [ + Tectonicunittreedef( + name=f"{discipline_name} Tectonic Unit Tree", + discipline_id=disciplineid + ) for disciplineid, discipline_name in disciplines_missing_tectonicunit + ], + batch_size=1000 + ) + + # If there are cases where Discipline -> tectonicunittreedef is not set, + # but there is at least one TectonicUnitTreeDef pointing to the Discipline, + # then set the Discipline -> tectonicunittreedef relationship to the "first" + # TectonicUnitTreeDef -> discipline + Discipline.objects.filter( + tectonicunittreedef__isnull=True, + tectonicunittreedefs__isnull=False + ).update( + tectonicunittreedef=Subquery( + Tectonicunittreedef.objects.filter( + discipline=OuterRef("pk") + ).order_by("pk").values("pk")[:1] + ) + ) + + # Finally, if there's any remaining TectonicUnitTreeDef objects with a NULL + # discipline, set the discipline relationship to the + # Discipline -> tectonicunittreedef (which must be set at this point) + Tectonicunittreedef.objects.filter( + discipline__isnull=True, + disciplines__isnull=False + ).update( + discipline=Subquery( + Discipline.objects.filter( + tectonicunittreedef=OuterRef("pk") + ).order_by("pk").values("pk")[:1] + ) + ) From 39ec0121331ebadaf04f1e15ddfc1bc9c23bd303 Mon Sep 17 00:00:00 2001 From: melton-jason Date: Thu, 4 Jun 2026 11:02:31 -0500 Subject: [PATCH 049/113] fix: forward tectonic unit migration functions --- .../specify/migration_utils/tectonic_ranks.py | 142 ++++++++---------- 1 file changed, 63 insertions(+), 79 deletions(-) diff --git a/specifyweb/specify/migration_utils/tectonic_ranks.py b/specifyweb/specify/migration_utils/tectonic_ranks.py index abc50ef358b..462891fe508 100644 --- a/specifyweb/specify/migration_utils/tectonic_ranks.py +++ b/specifyweb/specify/migration_utils/tectonic_ranks.py @@ -1,6 +1,6 @@ import logging -from django.db.models import OuterRef, Subquery +from django.db.models import OuterRef, Subquery, Exists logger = logging.getLogger(__name__) @@ -9,15 +9,19 @@ def create_default_tectonic_ranks(apps): TectonicTreeDef = apps.get_model('specify', 'TectonicUnitTreeDef') Discipline = apps.get_model('specify', 'Discipline') - disciplines = Discipline.objects.filter(tectonicunittreedef__isnull=True) + # Create empty TectonicUnit trees for Disciplines which don't have already them + _create_tectonic_unit_for_discipline( + Discipline_Model=Discipline, + Tectonicunittreedef_Model=TectonicTreeDef + ) - for discipline in disciplines: - tectonic_tree_def, _ = TectonicTreeDef.objects.get_or_create( - name="Tectonic Unit", - discipline=discipline, - ) + trees_missing_ranks = TectonicTreeDef.objects.filter(treedefitems__isnull=True) - root, root_created = TectonicUnitTreeDefItem.objects.get_or_create( + for tectonic_tree_def in trees_missing_ranks: + # At this point, these get_or_create calls should always be the + # equivalent of create (as we know these nodes didn't exist). + # But keeping the get_or_create here just because + root, _ = TectonicUnitTreeDefItem.objects.get_or_create( rankid=0, parent=None, treedef=tectonic_tree_def, @@ -27,18 +31,7 @@ def create_default_tectonic_ranks(apps): "isenforced": True } ) - if discipline.tectonicunittreedef_id != tectonic_tree_def.id: - discipline.tectonicunittreedef = tectonic_tree_def - discipline.save(update_fields=["tectonicunittreedef"]) - if not root_created: - # BUG?: handle setting the tectonicunittreedef on the Discipline - # here? We can probably practically assume it's already set if the - # root node exists. - continue - # At this point, these get_or_create calls should always be the - # equivalent of create (as we know the root node didn't exist). - # But keeping the get_or_create here just because superstructure, _ = TectonicUnitTreeDefItem.objects.get_or_create( name="Superstructure", title="Superstructure", @@ -75,9 +68,6 @@ def create_default_tectonic_ranks(apps): treedef=tectonic_tree_def, ) - discipline.tectonicunittreedef = tectonic_tree_def - discipline.save() - def revert_default_tectonic_ranks(apps, schema_editor=None): TectonicUnit = apps.get_model('specify', 'TectonicUnit') TectonicUnitTreeDefItem = apps.get_model('specify', 'TectonicUnitTreeDefItem') @@ -103,52 +93,40 @@ def create_root_tectonic_node(apps): TectonicUnit = apps.get_model('specify', 'TectonicUnit') TectonicUnitTreeDefItem = apps.get_model('specify', 'TectonicUnitTreeDefItem') TectonicUnitTreeDef = apps.get_model('specify', 'TectonicUnitTreeDef') - Discipline = apps.get_model('specify', 'Discipline') - for discipline in Discipline.objects.all(): - - tectonic_tree_def = TectonicUnitTreeDef.objects.filter(discipline=discipline).first() - if not tectonic_tree_def: - tectonic_tree_def, _ = TectonicUnitTreeDef.objects.get_or_create( - name="Tectonic Unit", - discipline=discipline - ) - - tectonic_tree_def_item = TectonicUnitTreeDefItem.objects.filter( - treedef=tectonic_tree_def, - name="Root", - ).first() - - if tectonic_tree_def_item: - tectonic_tree_def_item.rankid = 0 - tectonic_tree_def_item.parent = None - tectonic_tree_def_item.isenforced = True - tectonic_tree_def_item.save() - else: - tectonic_tree_def_item, _ = TectonicUnitTreeDefItem.objects.get_or_create( - name="Root", - title="Root", - parent=None, - treedef=tectonic_tree_def, - rankid=0, - isenforced=True - ) - - root = TectonicUnit.objects.filter(definition=tectonic_tree_def, definitionitem=tectonic_tree_def_item, rankid=0, parent=None).first() - if not root: - root, is_created = TectonicUnit.objects.get_or_create( - name="Root", - fullname="Root", - isaccepted=1, - nodenumber=1, - rankid=0, + trees_missing_root_node = TectonicUnitTreeDef.objects.annotate( + root_node_exists=Exists( + TectonicUnit.objects.filter( parent=None, - definition=tectonic_tree_def, - definitionitem=tectonic_tree_def_item + definition=OuterRef("pk") ) + ) + ).filter( + root_node_exists=False + ) - if is_created: - logger.info(f"Created root tectonic unit for discipline {discipline.name}") + for tree in trees_missing_root_node: + root_rank, _ = TectonicUnitTreeDefItem.objects.get_or_create( + rankid=0, + parent=None, + treedef=tree, + defaults={ + "name": "Root", + "title": "Root", + "isenforced": True + } + ) + TectonicUnit.objects.create( + name="Root", + fullname="Root", + isaccepted=1, + nodenumber=1, + rankid=0, + parent=None, + definition=tree, + definitionitem=root_rank + ) + logger.info(f"Created root tectonic unit for discipline {tree.discipline_id}") TectonicUnitTreeDefItem.objects.filter(parent=None,rankid=0, isenforced__isnull=True).update(isenforced=True) @@ -160,7 +138,7 @@ def revert_create_root_tectonic_node(apps, schema_editor=None): for discipline in Discipline.objects.all(): tectonic_tree_def = TectonicTreeDef.objects.filter(name="Tectonic Unit", discipline=discipline).first() - + if tectonic_tree_def: TectonicUnit.objects.filter( name="Root", @@ -169,26 +147,23 @@ def revert_create_root_tectonic_node(apps, schema_editor=None): ).delete() TectonicUnitTreeDefItem.objects.filter(treedef=tectonic_tree_def).delete() -def fix_tectonic_unit_treedef_discipline_links(apps): - Discipline = apps.get_model('specify', 'Discipline') - Tectonicunittreedef = apps.get_model('specify', 'Tectonicunittreedef') - +def _create_tectonic_unit_for_discipline(Discipline_Model, Tectonicunittreedef_Model): # Fetches Discipline objects with an empty TectonicUnitTreeDef relationship # and no TectonicUnitTreeDef objects with a set discipline # Most commonly, this would be in the case of creating a Discipline in # Specify 6 after the TectonicUnitTreeDef migrations have been run in # Specify 7 - disciplines_missing_tectonicunit = Discipline.objects.filter( + disciplines_missing_tectonicunit = Discipline_Model.objects.filter( tectonicunittreedef__isnull=True, tectonicunittreedefs__isnull=True - ).values_list("pk", "name") + ).values_list("pk", flat=True) - Tectonicunittreedef.objects.bulk_create( + Tectonicunittreedef_Model.objects.bulk_create( [ - Tectonicunittreedef( - name=f"{discipline_name} Tectonic Unit Tree", + Tectonicunittreedef_Model( + name="Tectonic Unit", discipline_id=disciplineid - ) for disciplineid, discipline_name in disciplines_missing_tectonicunit + ) for disciplineid in disciplines_missing_tectonicunit ], batch_size=1000 ) @@ -197,20 +172,29 @@ def fix_tectonic_unit_treedef_discipline_links(apps): # but there is at least one TectonicUnitTreeDef pointing to the Discipline, # then set the Discipline -> tectonicunittreedef relationship to the "first" # TectonicUnitTreeDef -> discipline - Discipline.objects.filter( + Discipline_Model.objects.filter( tectonicunittreedef__isnull=True, tectonicunittreedefs__isnull=False ).update( tectonicunittreedef=Subquery( - Tectonicunittreedef.objects.filter( + Tectonicunittreedef_Model.objects.filter( discipline=OuterRef("pk") ).order_by("pk").values("pk")[:1] ) ) - # Finally, if there's any remaining TectonicUnitTreeDef objects with a NULL +def fix_tectonic_unit_treedef_discipline_links(apps): + Discipline = apps.get_model('specify', 'Discipline') + Tectonicunittreedef = apps.get_model('specify', 'Tectonicunittreedef') + + _create_tectonic_unit_for_discipline( + Discipline_Model=Discipline, + Tectonicunittreedef_Model=Tectonicunittreedef + ) + + # If there's any TectonicUnitTreeDef objects with a NULL # discipline, set the discipline relationship to the - # Discipline -> tectonicunittreedef (which must be set at this point) + # Discipline -> tectonicunittreedef Tectonicunittreedef.objects.filter( discipline__isnull=True, disciplines__isnull=False From 9f9df797b631157353253296059e5cb7f2ec73fd Mon Sep 17 00:00:00 2001 From: melton-jason Date: Fri, 5 Jun 2026 10:21:28 -0500 Subject: [PATCH 050/113] fix: use Migrator user for all run_key_migration operations --- specifyweb/backend/patches/migration_utils.py | 18 ++----- specifyweb/settings/__init__.py | 2 + .../commands/run_key_migration_functions.py | 6 ++- .../specify/migration_utils/default_cots.py | 30 ++++++------ .../migration_utils/misc_migrations.py | 2 - specifyweb/specify/migration_utils/router.py | 49 +++++++++++++++++++ specifyweb/specify/migrations/0002_geo.py | 2 +- 7 files changed, 77 insertions(+), 32 deletions(-) create mode 100644 specifyweb/specify/migration_utils/router.py diff --git a/specifyweb/backend/patches/migration_utils.py b/specifyweb/backend/patches/migration_utils.py index bd69198bf6f..a773cb10ad0 100644 --- a/specifyweb/backend/patches/migration_utils.py +++ b/specifyweb/backend/patches/migration_utils.py @@ -10,8 +10,6 @@ def apply_migrations(app_registry, schema_editor=None): update_coordinates(app_registry, schema_editor) def update_is_accepted(app_registry, schema_editor=None): - db_alias = schema_editor.connection.alias if schema_editor is not None else "default" - for tree in SPECIFY_TREES: tree_filters = { "isaccepted": False, @@ -19,26 +17,20 @@ def update_is_accepted(app_registry, schema_editor=None): } tree_model = app_registry.get_model("specify", tree) - tree_model.objects.using(db_alias).filter(**tree_filters).update(isaccepted=True) + tree_model.objects.filter(**tree_filters).update(isaccepted=True) def update_coordinates(app_registry, schema_editor=None): - db_alias = schema_editor.connection.alias if schema_editor is not None else "default" - Locality = app_registry.get_model("specify", "Locality") - Locality.objects.using(db_alias) \ - .filter(lat1text__isnull=True, latitude1__isnull=False) \ + Locality.objects.filter(lat1text__isnull=True, latitude1__isnull=False) \ .update(lat1text=F("latitude1")) - Locality.objects.using(db_alias) \ - .filter(long1text__isnull=True, longitude1__isnull=False) \ + Locality.objects.filter(long1text__isnull=True, longitude1__isnull=False) \ .update(long1text=F("longitude1")) - Locality.objects.using(db_alias) \ - .filter(lat2text__isnull=True, latitude2__isnull=False) \ + Locality.objects.filter(lat2text__isnull=True, latitude2__isnull=False) \ .update(lat2text=F("latitude2")) - Locality.objects.using(db_alias) \ - .filter(long2text__isnull=True, longitude2__isnull=False) \ + Locality.objects.filter(long2text__isnull=True, longitude2__isnull=False) \ .update(long2text=F("longitude2")) diff --git a/specifyweb/settings/__init__.py b/specifyweb/settings/__init__.py index 990c5ed8ce0..5a21e5ebeed 100644 --- a/specifyweb/settings/__init__.py +++ b/specifyweb/settings/__init__.py @@ -82,6 +82,8 @@ }, } +DATABASE_ROUTERS = ["specifyweb.specify.migration_utils.router.MigrationRouter"] + DB_ALIAS = os.getenv("DJANGO_DB_ALIAS", "default") # Might want to set to "app" in the future if DB_ALIAS != "default": from copy import deepcopy diff --git a/specifyweb/specify/management/commands/run_key_migration_functions.py b/specifyweb/specify/management/commands/run_key_migration_functions.py index 789573eb801..0f61164f704 100644 --- a/specifyweb/specify/management/commands/run_key_migration_functions.py +++ b/specifyweb/specify/management/commands/run_key_migration_functions.py @@ -21,6 +21,7 @@ ) from specifyweb.backend.permissions.initialize import initialize from specifyweb.specify.migration_utils import update_schema_config as usc +from specifyweb.specify.migration_utils.router import use_migration_connection from specifyweb.specify.migration_utils.misc_migrations import make_selectseries_false from specifyweb.specify.migration_utils.tectonic_ranks import create_default_tectonic_ranks, create_root_tectonic_node, fix_tectonic_unit_treedef_discipline_links from specifyweb.backend.patches.migration_utils import apply_migrations as apply_patches @@ -234,7 +235,10 @@ def handle(self, *args, **options): verbose = options.get("verbose", False) try: - with transaction.atomic(): + with (transaction.atomic(), + # WARNING: With this context manager, all functions will be run + # with the Migration connection and use the Migrator user + use_migration_connection()): if len(functions) > 0: for function in functions: if function: diff --git a/specifyweb/specify/migration_utils/default_cots.py b/specifyweb/specify/migration_utils/default_cots.py index 7f144eca95d..a5f64baec65 100644 --- a/specifyweb/specify/migration_utils/default_cots.py +++ b/specifyweb/specify/migration_utils/default_cots.py @@ -30,45 +30,45 @@ def create_default_collection_types(apps): collection.collectionobjecttype = cot collection.save() -def create_default_discipline_for_tree_defs(apps, using='default'): +def create_default_discipline_for_tree_defs(apps): Discipline = apps.get_model('specify', 'Discipline') Institution = apps.get_model('specify', 'Institution') # Use the specified DB alias for all queries - for discipline in Discipline.objects.using(using).all(): + for discipline in Discipline.objects.all(): geography_tree_def = discipline.geographytreedef if geography_tree_def and geography_tree_def.discipline_id is None: geography_tree_def.discipline = discipline - geography_tree_def.save(using=using) + geography_tree_def.save() geologic_time_period_tree_def = discipline.geologictimeperiodtreedef if geologic_time_period_tree_def and geologic_time_period_tree_def.discipline_id is None: geologic_time_period_tree_def.discipline = discipline - geologic_time_period_tree_def.save(using=using) + geologic_time_period_tree_def.save() lithostrat_tree_def = discipline.lithostrattreedef if lithostrat_tree_def and lithostrat_tree_def.discipline_id is None: lithostrat_tree_def.discipline = discipline - lithostrat_tree_def.save(using=using) + lithostrat_tree_def.save() taxon_tree_def = discipline.taxontreedef if taxon_tree_def and taxon_tree_def.discipline_id is None: taxon_tree_def.discipline = discipline - taxon_tree_def.save(using=using) + taxon_tree_def.save() - for institution in Institution.objects.using(using).all(): + for institution in Institution.objects.all(): storage_tree_def = institution.storagetreedef if storage_tree_def and storage_tree_def.institution_id is None: storage_tree_def.institution = institution - storage_tree_def.save(using=using) + storage_tree_def.save() -def create_cogtype_type_picklist(apps, using='default'): +def create_cogtype_type_picklist(apps): Collection = apps.get_model('specify', 'Collection') Picklist = apps.get_model('specify', 'Picklist') Picklistitem = apps.get_model('specify', 'Picklistitem') - for collection in Collection.objects.using(using).all(): - cog_type_picklist, picklist_created = Picklist.objects.using(using).get_or_create( + for collection in Collection.objects.all(): + cog_type_picklist, picklist_created = Picklist.objects.get_or_create( name='SystemCOGTypes', # Default Collection Object Group Types type=0, collection=collection, @@ -79,7 +79,7 @@ def create_cogtype_type_picklist(apps, using='default'): ) if picklist_created: for cog_type in DEFAULT_COG_TYPES: - Picklistitem.objects.using(using).get_or_create( + Picklistitem.objects.get_or_create( title=cog_type, value=cog_type, picklist=cog_type_picklist @@ -108,18 +108,18 @@ def create_cotype_picklist(apps): } ) -def set_discipline_for_taxon_treedefs(apps, using='default'): +def set_discipline_for_taxon_treedefs(apps): Collectionobjecttype = apps.get_model('specify', 'Collectionobjecttype') Taxontreedef = apps.get_model('specify', 'Taxontreedef') - collection_object_types = Collectionobjecttype.objects.using(using).filter( + collection_object_types = Collectionobjecttype.objects.filter( taxontreedef__discipline__isnull=True ).annotate( discipline=F('collection__discipline') ) for cot in collection_object_types: - Taxontreedef.objects.using(using).filter(id=cot.taxontreedef_id).update(discipline=cot.discipline) + Taxontreedef.objects.filter(id=cot.taxontreedef_id).update(discipline=cot.discipline) def fix_taxon_treedef_discipline_links(apps): Discipline = apps.get_model('specify', 'Discipline') diff --git a/specifyweb/specify/migration_utils/misc_migrations.py b/specifyweb/specify/migration_utils/misc_migrations.py index f7c95092346..0554a476067 100644 --- a/specifyweb/specify/migration_utils/misc_migrations.py +++ b/specifyweb/specify/migration_utils/misc_migrations.py @@ -1,5 +1,3 @@ - - def make_selectseries_false(apps): spquery = apps.get_model('specify', 'Spquery') if 'selectseries' in [field.name for field in spquery._meta.get_fields()]: diff --git a/specifyweb/specify/migration_utils/router.py b/specifyweb/specify/migration_utils/router.py new file mode 100644 index 00000000000..ae88c0723b2 --- /dev/null +++ b/specifyweb/specify/migration_utils/router.py @@ -0,0 +1,49 @@ +from contextvars import ContextVar +from contextlib import contextmanager + +_use_migration_connection = ContextVar[bool]("use_migration_connection", default=False) + +@contextmanager +def use_migration_connection(): + """ + This can be used as a decorator or context manager to tell Django to use + the 'migrations' database defined in specifyweb/settings/__init__.py + + Examples: + + ```py + @use_migration_connection() + def my_func(): + ... # For this function block, Django will use the same connection it + # uses for migrations + + with use_migration_connection(): + ... # Within this block, Django will use the same connection it uses + # for migrations + ``` + """ + token = _use_migration_connection.set(True) + try: + yield + finally: + _use_migration_connection.reset(token) + +""" +A simple MigrationRouter that automatically routes reads and writes through the +migration connection when the use_migration_connection decorator/context manager +is used. + +This is referenced by string in the DATABASE_ROUTERS Django setting within +specifyweb/settings/__init__.py + +See the Django docs on Database Routers: +https://docs.djangoproject.com/en/4.2/topics/db/multi-db/#automatic-database-routing +""" +class MigrationRouter: + def db_for_read(self, model, **hints): + if _use_migration_connection.get(): + return 'migrations' + + def db_for_write(self, model, **hints): + if _use_migration_connection.get(): + return 'migrations' diff --git a/specifyweb/specify/migrations/0002_geo.py b/specifyweb/specify/migrations/0002_geo.py index a3c32bc4b2c..ef06d86d051 100644 --- a/specifyweb/specify/migrations/0002_geo.py +++ b/specifyweb/specify/migrations/0002_geo.py @@ -71,7 +71,7 @@ class Migration(migrations.Migration): ] def consolidated_python_django_migration_operations(apps, schema_editor): - db_alias = schema_editor.connection.alias or 'migrator' + db_alias = schema_editor.connection.alias or 'migrations' create_default_collection_types(apps) create_default_discipline_for_tree_defs(apps, using=db_alias) usc.create_geo_table_schema_config_with_defaults(apps) From a95bc71b2dff82ce63fca34f31a24fc0c56e76a4 Mon Sep 17 00:00:00 2001 From: melton-jason Date: Fri, 5 Jun 2026 10:38:27 -0500 Subject: [PATCH 051/113] perf: reduce set_discipline_for_taxon_treedefs to single DB hit --- .../specify/migration_utils/default_cots.py | 15 ++++++++------- specifyweb/specify/migrations/0002_geo.py | 7 +++---- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/specifyweb/specify/migration_utils/default_cots.py b/specifyweb/specify/migration_utils/default_cots.py index a5f64baec65..b46098a5714 100644 --- a/specifyweb/specify/migration_utils/default_cots.py +++ b/specifyweb/specify/migration_utils/default_cots.py @@ -112,15 +112,16 @@ def set_discipline_for_taxon_treedefs(apps): Collectionobjecttype = apps.get_model('specify', 'Collectionobjecttype') Taxontreedef = apps.get_model('specify', 'Taxontreedef') - collection_object_types = Collectionobjecttype.objects.filter( - taxontreedef__discipline__isnull=True - ).annotate( - discipline=F('collection__discipline') + Taxontreedef.objects.filter( + discipline__isnull=True + ).update( + discipline=Subquery( + Collectionobjecttype.objects.filter( + taxontreedef=OuterRef("pk") + ).order_by("pk").values("collection__discipline")[:1] + ) ) - for cot in collection_object_types: - Taxontreedef.objects.filter(id=cot.taxontreedef_id).update(discipline=cot.discipline) - def fix_taxon_treedef_discipline_links(apps): Discipline = apps.get_model('specify', 'Discipline') Taxontreedef = apps.get_model('specify', 'Taxontreedef') diff --git a/specifyweb/specify/migrations/0002_geo.py b/specifyweb/specify/migrations/0002_geo.py index ef06d86d051..e84e59d5c2e 100644 --- a/specifyweb/specify/migrations/0002_geo.py +++ b/specifyweb/specify/migrations/0002_geo.py @@ -71,12 +71,11 @@ class Migration(migrations.Migration): ] def consolidated_python_django_migration_operations(apps, schema_editor): - db_alias = schema_editor.connection.alias or 'migrations' create_default_collection_types(apps) - create_default_discipline_for_tree_defs(apps, using=db_alias) + create_default_discipline_for_tree_defs(apps) usc.create_geo_table_schema_config_with_defaults(apps) - create_cogtype_type_picklist(apps, using=db_alias) - set_discipline_for_taxon_treedefs(apps, using=db_alias) + create_cogtype_type_picklist(apps) + set_discipline_for_taxon_treedefs(apps) def revert_cosolidated_python_django_migration_operations(apps, schema_editor): revert_cogtype_type_picklist(apps) From 1136e52b706f79697e4aa0f40fc1257893287a32 Mon Sep 17 00:00:00 2001 From: melton-jason Date: Fri, 5 Jun 2026 11:58:37 -0500 Subject: [PATCH 052/113] refactor: collapse default tectonicunit ranks to tuple --- .../specify/migration_utils/tectonic_ranks.py | 72 +++++++------------ 1 file changed, 24 insertions(+), 48 deletions(-) diff --git a/specifyweb/specify/migration_utils/tectonic_ranks.py b/specifyweb/specify/migration_utils/tectonic_ranks.py index 462891fe508..ae5deb19bab 100644 --- a/specifyweb/specify/migration_utils/tectonic_ranks.py +++ b/specifyweb/specify/migration_utils/tectonic_ranks.py @@ -4,6 +4,15 @@ logger = logging.getLogger(__name__) +DEFAULT_RANKS = ( + {"rankid": 0, "name": "Root", "attrs": {"isenforced": True}}, + {"rankid": 10, "name": "Superstructure"}, + {"rankid": 20, "name": "Tectonic Domain"}, + {"rankid": 30, "name": "Tectonic Subdomain"}, + {"rankid": 40, "name": "Tectonic Unit"}, + {"rankid": 50, "name": "Tectonic Subunit"} +) + def create_default_tectonic_ranks(apps): TectonicUnitTreeDefItem = apps.get_model('specify', 'TectonicUnitTreeDefItem') TectonicTreeDef = apps.get_model('specify', 'TectonicUnitTreeDef') @@ -18,55 +27,22 @@ def create_default_tectonic_ranks(apps): trees_missing_ranks = TectonicTreeDef.objects.filter(treedefitems__isnull=True) for tectonic_tree_def in trees_missing_ranks: - # At this point, these get_or_create calls should always be the - # equivalent of create (as we know these nodes didn't exist). - # But keeping the get_or_create here just because - root, _ = TectonicUnitTreeDefItem.objects.get_or_create( - rankid=0, - parent=None, - treedef=tectonic_tree_def, - defaults={ - "name": "Root", - "title": "Root", - "isenforced": True - } - ) - superstructure, _ = TectonicUnitTreeDefItem.objects.get_or_create( - name="Superstructure", - title="Superstructure", - rankid=10, - parent=root, - treedef=tectonic_tree_def, - ) - tectonic_domain, _ = TectonicUnitTreeDefItem.objects.get_or_create( - name="Tectonic Domain", - title="Tectonic Domain", - rankid=20, - parent=superstructure, - treedef=tectonic_tree_def, - ) - tectonic_subdomain, _ = TectonicUnitTreeDefItem.objects.get_or_create( - name="Tectonic Subdomain", - title="Tectonic Subdomain", - rankid=30, - parent=tectonic_domain, - treedef=tectonic_tree_def, - ) - tectonic_unit, _ = TectonicUnitTreeDefItem.objects.get_or_create( - name="Tectonic Unit", - title="Tectonic Unit", - rankid=40, - parent=tectonic_subdomain, - treedef=tectonic_tree_def, - ) - tectonic_subunit, _ = TectonicUnitTreeDefItem.objects.get_or_create( - name="Tectonic Subunit", - title="Tectonic Subunit", - rankid=50, - parent=tectonic_unit, - treedef=tectonic_tree_def, - ) + current_parent = None + for default_rank in DEFAULT_RANKS: + # At this point, these get_or_create calls should always be the + # equivalent of create (as we know these nodes didn't exist). + # But keeping the get_or_create here just because + current_parent, _ = TectonicUnitTreeDefItem.objects.get_or_create( + rankid=default_rank["rankid"], + parent=current_parent, + treedef=tectonic_tree_def, + defaults={ + "name": default_rank["name"], + "title": default_rank["name"], + **default_rank.get('attrs', {}) + } + ) def revert_default_tectonic_ranks(apps, schema_editor=None): TectonicUnit = apps.get_model('specify', 'TectonicUnit') From 5418c648a87a5eee4e9e8b6be423ab51333d1b57 Mon Sep 17 00:00:00 2001 From: melton-jason Date: Fri, 5 Jun 2026 12:42:21 -0500 Subject: [PATCH 053/113] fix: simplify and move reverse tectonic root node migration --- .../specify/migration_utils/tectonic_ranks.py | 17 -------- .../specify/migrations/0009_tectonic_ranks.py | 40 ++++++++++++++++++- 2 files changed, 39 insertions(+), 18 deletions(-) diff --git a/specifyweb/specify/migration_utils/tectonic_ranks.py b/specifyweb/specify/migration_utils/tectonic_ranks.py index ae5deb19bab..835312b988d 100644 --- a/specifyweb/specify/migration_utils/tectonic_ranks.py +++ b/specifyweb/specify/migration_utils/tectonic_ranks.py @@ -106,23 +106,6 @@ def create_root_tectonic_node(apps): TectonicUnitTreeDefItem.objects.filter(parent=None,rankid=0, isenforced__isnull=True).update(isenforced=True) -def revert_create_root_tectonic_node(apps, schema_editor=None): - TectonicUnit = apps.get_model('specify', 'TectonicUnit') - TectonicUnitTreeDefItem = apps.get_model('specify', 'TectonicUnitTreeDefItem') - TectonicTreeDef = apps.get_model('specify', 'TectonicUnitTreeDef') - Discipline = apps.get_model('specify', 'Discipline') - - for discipline in Discipline.objects.all(): - tectonic_tree_def = TectonicTreeDef.objects.filter(name="Tectonic Unit", discipline=discipline).first() - - if tectonic_tree_def: - TectonicUnit.objects.filter( - name="Root", - definition=tectonic_tree_def, - parent__isnull=True, - ).delete() - TectonicUnitTreeDefItem.objects.filter(treedef=tectonic_tree_def).delete() - def _create_tectonic_unit_for_discipline(Discipline_Model, Tectonicunittreedef_Model): # Fetches Discipline objects with an empty TectonicUnitTreeDef relationship # and no TectonicUnitTreeDef objects with a set discipline diff --git a/specifyweb/specify/migrations/0009_tectonic_ranks.py b/specifyweb/specify/migrations/0009_tectonic_ranks.py index f97c7560a19..0cd93b1cb5e 100644 --- a/specifyweb/specify/migrations/0009_tectonic_ranks.py +++ b/specifyweb/specify/migrations/0009_tectonic_ranks.py @@ -1,12 +1,50 @@ from django.db import migrations +from django.db.models import Exists, OuterRef from specifyweb.specify.migration_utils.tectonic_ranks import ( create_default_tectonic_ranks, create_root_tectonic_node, - revert_create_root_tectonic_node, revert_default_tectonic_ranks, ) +def revert_create_root_tectonic_node(apps, schema_editor=None): + TectonicUnit = apps.get_model('specify', 'TectonicUnit') + TectonicUnitTreeDefItem = apps.get_model('specify', 'TectonicUnitTreeDefItem') + + # Technically at this point a user could have more than just the root node + # in the tree, so only delete the TectonicUnit nodes which were created + # from create_root_tectonic_node and are alone in the tree + TectonicUnit.objects.annotate( + has_children_nodes=Exists( + TectonicUnit.objects.filter( + parent=OuterRef("pk") + ) + ) + ).filter( + parent__isnull=True, + has_children_nodes=False, + name="Root" + ).delete() + + # Delete the Root TectonicUnit rank if there are no nodes in the tree and + # no children rank reference the Root rank + TectonicUnitTreeDefItem.objects.annotate( + has_nodes=Exists( + TectonicUnit.objects.filter( + definitionitem=OuterRef("pk") + ) + ), + has_child_rank=Exists( + TectonicUnitTreeDefItem.objects.filter( + parent=OuterRef("pk") + ) + ) + ).filter( + has_nodes=False, + has_child_rank=False, + name="Root" + ).delete() + class Migration(migrations.Migration): dependencies = [ From 419d69b7d2360f2c2e412b9f957075e660281153 Mon Sep 17 00:00:00 2001 From: melton-jason Date: Fri, 5 Jun 2026 13:59:52 -0500 Subject: [PATCH 054/113] fix: handle case when businessrule app is not ready but migrations are applied --- .../backend/businessrules/uniqueness_rules.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/specifyweb/backend/businessrules/uniqueness_rules.py b/specifyweb/backend/businessrules/uniqueness_rules.py index 24b3cc39bc6..d85b1c38e46 100644 --- a/specifyweb/backend/businessrules/uniqueness_rules.py +++ b/specifyweb/backend/businessrules/uniqueness_rules.py @@ -99,7 +99,11 @@ def _initial_businessrules_migration_applied(): ).applied_migrations() ) +def businessrule_app_is_ready(registry): + return any(app.label == 'businessrules' for app in registry.get_app_configs()) +# BUG: If we reverse past the initial businessrule migration, Specify can still +# consider the migration applied within those earlier migrations def _cached_businessrules_migration_applied() -> bool: cache_key = "default" cache_is_active, is_set = _uniqueness_migration_cache.get(cache_key, default=False) @@ -188,12 +192,19 @@ def validate_unique(model, instance): f"Skipping uniqueness rule check on non-Specify model: '{model_name}'") return - if not _cached_businessrules_migration_applied(): - return - # We can't directly use the main app registry in the context of migrations, which uses fake models registry = model._meta.apps + # If we're in a migration where businessrules have not been loaded and/or + # the initial businessrule migration has not been applied, then skip + # checking the rule for now. + # Note that the former can exist where the latter does: if we're reversing + # a migration which does not have a dependency on businessrules (so the + # businessrules app does not need to be loaded) but the businessrule + # migration is still applied + if not businessrule_app_is_ready(registry) or not _cached_businessrules_migration_applied(): + return + # REFACTOR(perf): We should look into batching UniquenessRule queries. # That is, instead of making a query to the DB for each rule, aggregate # the rules and make a "single" query. From 19f5c1a7a59af1dc5e0d8105f128eec37427a4be Mon Sep 17 00:00:00 2001 From: melton-jason Date: Fri, 5 Jun 2026 14:23:58 -0500 Subject: [PATCH 055/113] refactor: move reverse migration to migration file --- .../specify/migration_utils/tectonic_ranks.py | 21 ---------------- .../specify/migrations/0009_tectonic_ranks.py | 24 +++++++++++++++++-- 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/specifyweb/specify/migration_utils/tectonic_ranks.py b/specifyweb/specify/migration_utils/tectonic_ranks.py index 835312b988d..4f23ded3ad5 100644 --- a/specifyweb/specify/migration_utils/tectonic_ranks.py +++ b/specifyweb/specify/migration_utils/tectonic_ranks.py @@ -44,27 +44,6 @@ def create_default_tectonic_ranks(apps): } ) -def revert_default_tectonic_ranks(apps, schema_editor=None): - TectonicUnit = apps.get_model('specify', 'TectonicUnit') - TectonicUnitTreeDefItem = apps.get_model('specify', 'TectonicUnitTreeDefItem') - TectonicTreeDef = apps.get_model('specify', 'TectonicUnitTreeDef') - Discipline = apps.get_model('specify', 'Discipline') - - for discipline in Discipline.objects.all(): - tectonic_tree_defs = TectonicTreeDef.objects.filter(name="Tectonic Unit", discipline=discipline) - - for tectonic_tree_def in tectonic_tree_defs: - tectonic_unit_tree_def_items = TectonicUnitTreeDefItem.objects.filter(treedef=tectonic_tree_def).order_by('-id') - - for item in tectonic_unit_tree_def_items: - TectonicUnit.objects.filter(definitionitem=item).delete() - - item.delete() - - discipline.tectonicunittreedef = None - discipline.save() - tectonic_tree_def.delete() - def create_root_tectonic_node(apps): TectonicUnit = apps.get_model('specify', 'TectonicUnit') TectonicUnitTreeDefItem = apps.get_model('specify', 'TectonicUnitTreeDefItem') diff --git a/specifyweb/specify/migrations/0009_tectonic_ranks.py b/specifyweb/specify/migrations/0009_tectonic_ranks.py index 0cd93b1cb5e..62db4d4a38b 100644 --- a/specifyweb/specify/migrations/0009_tectonic_ranks.py +++ b/specifyweb/specify/migrations/0009_tectonic_ranks.py @@ -3,8 +3,7 @@ from specifyweb.specify.migration_utils.tectonic_ranks import ( create_default_tectonic_ranks, - create_root_tectonic_node, - revert_default_tectonic_ranks, + create_root_tectonic_node ) def revert_create_root_tectonic_node(apps, schema_editor=None): @@ -45,6 +44,27 @@ def revert_create_root_tectonic_node(apps, schema_editor=None): name="Root" ).delete() +def revert_default_tectonic_ranks(apps, schema_editor=None): + TectonicUnit = apps.get_model('specify', 'TectonicUnit') + TectonicUnitTreeDefItem = apps.get_model('specify', 'TectonicUnitTreeDefItem') + TectonicTreeDef = apps.get_model('specify', 'TectonicUnitTreeDef') + Discipline = apps.get_model('specify', 'Discipline') + + for discipline in Discipline.objects.all(): + tectonic_tree_defs = TectonicTreeDef.objects.filter(name="Tectonic Unit", discipline=discipline) + + for tectonic_tree_def in tectonic_tree_defs: + tectonic_unit_tree_def_items = TectonicUnitTreeDefItem.objects.filter(treedef=tectonic_tree_def).order_by('-id') + + for item in tectonic_unit_tree_def_items: + TectonicUnit.objects.filter(definitionitem=item).delete() + + item.delete() + + discipline.tectonicunittreedef = None + discipline.save() + tectonic_tree_def.delete() + class Migration(migrations.Migration): dependencies = [ From 9ddf13e8fcdd8864099eaa5b645a8cf4f69ef64e Mon Sep 17 00:00:00 2001 From: melton-jason Date: Fri, 5 Jun 2026 16:02:39 -0500 Subject: [PATCH 056/113] fix: account for custom Tectonic Trees when reverting migration --- .../specify/migrations/0009_tectonic_ranks.py | 61 +++++++++++++++---- 1 file changed, 49 insertions(+), 12 deletions(-) diff --git a/specifyweb/specify/migrations/0009_tectonic_ranks.py b/specifyweb/specify/migrations/0009_tectonic_ranks.py index 62db4d4a38b..be0ebff9482 100644 --- a/specifyweb/specify/migrations/0009_tectonic_ranks.py +++ b/specifyweb/specify/migrations/0009_tectonic_ranks.py @@ -1,9 +1,10 @@ from django.db import migrations -from django.db.models import Exists, OuterRef +from django.db.models import Exists, OuterRef, Subquery from specifyweb.specify.migration_utils.tectonic_ranks import ( create_default_tectonic_ranks, - create_root_tectonic_node + create_root_tectonic_node, + DEFAULT_RANKS ) def revert_create_root_tectonic_node(apps, schema_editor=None): @@ -44,26 +45,62 @@ def revert_create_root_tectonic_node(apps, schema_editor=None): name="Root" ).delete() +# REFACTOR: Optimize this def revert_default_tectonic_ranks(apps, schema_editor=None): TectonicUnit = apps.get_model('specify', 'TectonicUnit') TectonicUnitTreeDefItem = apps.get_model('specify', 'TectonicUnitTreeDefItem') TectonicTreeDef = apps.get_model('specify', 'TectonicUnitTreeDef') Discipline = apps.get_model('specify', 'Discipline') - for discipline in Discipline.objects.all(): - tectonic_tree_defs = TectonicTreeDef.objects.filter(name="Tectonic Unit", discipline=discipline) + for default_rank in reversed(DEFAULT_RANKS): + tree_def_items = TectonicUnitTreeDefItem.objects.annotate( + has_child_rank=Exists( + TectonicUnitTreeDefItem.objects.filter( + parent=OuterRef("pk") + ) + ) + ).filter( + has_child_rank=False, + name=default_rank["name"], + # rankid=default_rank["rankid"] + ) - for tectonic_tree_def in tectonic_tree_defs: - tectonic_unit_tree_def_items = TectonicUnitTreeDefItem.objects.filter(treedef=tectonic_tree_def).order_by('-id') + units_to_delete = TectonicUnit.objects.annotate( + has_children_nodes=Exists( + TectonicUnit.objects.filter( + parent=OuterRef("pk") + ) + ) + ).filter( + has_children_nodes=False, + definitionitem__in=tree_def_items + ) + TectonicUnit.objects.filter( + acceptedtectonicunit_id__in=units_to_delete.values_list('pk', flat=True) + ).update( + acceptedtectonicunit=None, + isaccepted=True + ) - for item in tectonic_unit_tree_def_items: - TectonicUnit.objects.filter(definitionitem=item).delete() + units_to_delete.delete() + tree_def_items.delete() - item.delete() + empty_tree_defs = TectonicTreeDef.objects.annotate( + has_ranks=Exists( + TectonicUnitTreeDefItem.objects.filter( + treedef=OuterRef("pk") + ) + ) + ).filter( + has_ranks=False + ) - discipline.tectonicunittreedef = None - discipline.save() - tectonic_tree_def.delete() + Discipline.objects.filter( + tectonicunittreedef_id__in=empty_tree_defs.values_list('pk', flat=True) + ).update( + tectonicunittreedef=None + ) + empty_tree_defs.delete() class Migration(migrations.Migration): From 3396fe405945464cabd774d5d46ae2003b4e38a7 Mon Sep 17 00:00:00 2001 From: melton-jason Date: Mon, 8 Jun 2026 08:40:14 -0500 Subject: [PATCH 057/113] fix: handle case when root node is synonymized in reverse migration --- specifyweb/specify/migrations/0009_tectonic_ranks.py | 1 + 1 file changed, 1 insertion(+) diff --git a/specifyweb/specify/migrations/0009_tectonic_ranks.py b/specifyweb/specify/migrations/0009_tectonic_ranks.py index be0ebff9482..975fb3570b1 100644 --- a/specifyweb/specify/migrations/0009_tectonic_ranks.py +++ b/specifyweb/specify/migrations/0009_tectonic_ranks.py @@ -23,6 +23,7 @@ def revert_create_root_tectonic_node(apps, schema_editor=None): ).filter( parent__isnull=True, has_children_nodes=False, + acceptedtectonicunit__isnull=True, name="Root" ).delete() From c037340e32edf9f4a6584bbb53025b13147e4267 Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Mon, 15 Jun 2026 10:28:51 +0200 Subject: [PATCH 058/113] Refactor: Create SchemaReader for schema migration related functions --- .../specify/migration_utils/SchemaReader.py | 305 ++++++++++++++++++ .../migration_utils/update_schema_config.py | 279 +--------------- 2 files changed, 322 insertions(+), 262 deletions(-) create mode 100644 specifyweb/specify/migration_utils/SchemaReader.py diff --git a/specifyweb/specify/migration_utils/SchemaReader.py b/specifyweb/specify/migration_utils/SchemaReader.py new file mode 100644 index 00000000000..4426a5757d6 --- /dev/null +++ b/specifyweb/specify/migration_utils/SchemaReader.py @@ -0,0 +1,305 @@ +import re +import json + +from typing import NamedTuple, Tuple, TypedDict, NotRequired +import logging +from collections import defaultdict +from functools import lru_cache +from pathlib import Path + + +from django.db.models import Q, Count, Window, F, Exists, OuterRef +from django.conf import settings +from django.apps import apps as global_apps +from django.core.exceptions import MultipleObjectsReturned +from django.db import connection, transaction +from django.db.models.functions import RowNumber + +from specifyweb.specify.models_utils.load_datamodel import FieldDoesNotExistError, TableDoesNotExistError + +from specifyweb.specify.models_utils.load_datamodel import Table, FieldDoesNotExistError, TableDoesNotExistError +from specifyweb.specify.models_utils.model_extras import GEOLOGY_DISCIPLINES, PALEO_DISCIPLINES +from specifyweb.specify.models import ( + Discipline, + datamodel, +) +from specifyweb.specify.migration_utils.sp7_schemaconfig import ( + MIGRATION_0002_TABLES, + MIGRATION_0004_FIELDS, + MIGRATION_0004_TABLES, + MIGRATION_0007_FIELDS, + MIGRATION_0008_FIELDS, + MIGRATION_0012_FIELDS, + MIGRATION_0013_FIELDS, + MIGRATION_0020_FIELDS, + MIGRATION_0021_FIELDS, + MIGRATION_0023_FIELDS, + MIGRATION_0023_FIELDS_BIS, + MIGRATION_0024_FIELDS, + MIGRATION_0027_FIELDS, + MIGRATION_0027_UPDATE_FIELDS, + MIGRATION_0029_FIELDS, + MIGRATION_0029_UPDATE_FIELDS, + MIGRATION_0032_FIELDS, + MIGRATION_0032_UPDATE_FIELDS, + MIGRATION_0033_TABLES, + MIGRATION_0034_FIELDS, + MIGRATION_0034_UPDATE_FIELDS, + MIGRATION_0035_FIELDS, + MIGRATION_0038_FIELDS, + MIGRATION_0040_TABLES, + MIGRATION_0040_FIELDS, + MIGRATION_0040_UPDATE_FIELDS, + MIGRATION_0040_HIDDEN_FIELDS, +) + +logger = logging.getLogger(__name__) + +HIDDEN_FIELDS = [ + "timestampcreated", "timestampmodified", "version", "createdbyagent", "modifiedbyagent" +] + +def _has_explicit_hidden_override(field_config: dict) -> bool: + return any(key.lower() == "ishidden" for key in field_config.keys()) + +@lru_cache(maxsize=None) +def _schema_override_hidden_values_for_discipline( + discipline_type: str, +) -> dict[str, dict[str, bool]]: + """ + Return a mapping of {table_name -> {field_name -> ishidden_value}} for fields + that have an + explicit `ishidden` override in config//schema_overrides.json. + """ + normalized_discipline = (discipline_type or "").lower() + if not normalized_discipline: + return {} + + schema_overrides_path = ( + Path(settings.SPECIFY_CONFIG_DIR) / normalized_discipline / "schema_overrides.json" + ) + if not schema_overrides_path.exists(): + return {} + + try: + with schema_overrides_path.open("r", encoding="utf-8") as schema_overrides_file: + overrides = json.load(schema_overrides_file) + except (OSError, json.JSONDecodeError) as exc: + logger.warning( + "Unable to read schema overrides for discipline '%s' at %s: %s", + normalized_discipline, + schema_overrides_path, + exc, + ) + return {} + + if not isinstance(overrides, dict): + return {} + + hidden_override_values_by_table: dict[str, dict[str, bool]] = {} + for table_name, table_config in overrides.items(): + if not isinstance(table_config, dict): + continue + + explicit_hidden_override_values: dict[str, bool] = {} + items = table_config.get("items", []) + if not isinstance(items, list): + continue + + for item in items: + if not isinstance(item, dict): + continue + + for field_name, field_config in item.items(): + if not isinstance(field_config, dict): + continue + if not _has_explicit_hidden_override(field_config): + continue + for key, value in field_config.items(): + if key.lower() == "ishidden": + explicit_hidden_override_values[field_name.lower()] = bool(value) + break + + if explicit_hidden_override_values: + hidden_override_values_by_table[table_name.lower()] = explicit_hidden_override_values + + return hidden_override_values_by_table + +@lru_cache(maxsize=None) +def _schema_override_hidden_fields_for_discipline(discipline_type: str) -> dict[str, set[str]]: + hidden_override_values = _schema_override_hidden_values_for_discipline(discipline_type) + return { + table_name: set(table_values.keys()) + for table_name, table_values in hidden_override_values.items() + } + +def _fields_without_explicit_hidden_override( + table_name: str, + field_names: list[str], + discipline_type: str, +) -> list[str]: + table_hidden_overrides = _schema_override_hidden_fields_for_discipline( + discipline_type + ).get(table_name.lower(), set()) + return [ + field_name + for field_name in field_names + if field_name.lower() not in table_hidden_overrides + ] + +def datamodel_type_to_schematype(datamodel_type: str) -> str: + """ + Converts a string like `many-to-one` to `ManyToOne` by: + - Splitting on hyphens + - e.g., ['many', 'to', 'one'] + - Lowering then capitilizing each string in the split + - e.g., ['Many', 'To', 'One'] + - Joining the split strings back together + - e.g., 'ManyToOne' + """ + return "".join(map(lambda type_part: type_part.lower().capitalize(), datamodel_type.split('-'))) + +def camel_to_spaced_title_case(camel_case: str) -> str: + """ + Given a camel case string, convert it to title case and add spaces + + - `catalogNumber` -> `Catalog Number` + - `modifiedByAgent` -> `Modified By Agent` + - `yesNo6` -> `Yes No6` + - `cojo` -> `Cojo` + """ + return re.sub(r"(? str: + return string.lower() if len(string) <= 1 else string[0].lower() + string[1:] + +def bulk_create_splocaleitemstr_idempotent(Splocaleitemstr, rows: list[dict]) -> int: + if not rows: + return 0 + + fk_fields = ("itemname", "itemdesc", "containername", "containerdesc") + groups: dict[str, list[dict]] = defaultdict(list) + for r in rows: + present = [f for f in fk_fields if r.get(f) is not None] + if len(present) != 1: + raise ValueError(f"Each row must set exactly one FK among {fk_fields}. Got: {present}") + groups[present[0]].append(r) + + total_created = 0 + + for fk_field, group_rows in groups.items(): + fk_ids: set[int] = set() + languages: set[str] = set() + + for r in group_rows: + fk_ids.add(r[fk_field].pk) + languages.add(r["language"]) + + existing_rows = list( + Splocaleitemstr.objects.filter( + **{ + f"{fk_field}_id__in": fk_ids, + "language__in": languages, + } + ) + .filter( + Q(country__isnull=True) | Q(country=""), + Q(variant__isnull=True) | Q(variant=""), + ) + .order_by("id") + ) + + existing_by_key: dict[Tuple[str, int], list] = defaultdict(list) + fk_field_id = f"{fk_field}_id" + for existing_row in existing_rows: + key = (existing_row.language, getattr(existing_row, fk_field_id)) + existing_by_key[key].append(existing_row) + + desired_by_key: dict[Tuple[str, int], dict] = {} + for r in group_rows: + key = (r["language"], r[fk_field].pk) + desired_by_key[key] = r + + ids_to_delete: set[int] = set() + to_create = [] + for key, desired_row in desired_by_key.items(): + existing_for_key = existing_by_key.get(key, []) + + if not existing_for_key: + to_create.append(Splocaleitemstr(**desired_row)) + continue + + for duplicate in existing_for_key[1:]: + ids_to_delete.add(duplicate.id) + + if ids_to_delete: + Splocaleitemstr.objects.filter(id__in=ids_to_delete).delete() + + if to_create: + Splocaleitemstr.objects.bulk_create(to_create) + total_created += len(to_create) + + return total_created + +class TableDefaults(TypedDict): + name: NotRequired[str] + desc: NotRequired[str] + items: "NotRequired[dict[str, FieldDefaults]]" + +def find_missing_schema_config_fields(discipline_id: int, apps=global_apps): + Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') + Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') + + missing_tables: list[str] = [] + missing_fields: dict[str, list[str]] = {} + + containers = Splocalecontainer.objects.filter( + discipline_id=discipline_id, + schematype=0, + ) + container_names = set( + containers.values_list('name', flat=True) + ) + + existing_fields_by_table: dict[str, set[str]] = defaultdict(set) + for table_name, field_name in Splocalecontaineritem.objects.filter( + container__in=containers + ).values_list('container__name', 'name'): + if table_name and field_name: + existing_fields_by_table[table_name].add(field_name.lower()) + + for table in datamodel.tables: + table_name = table.name + table_name_lower = table_name.lower() + 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(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(exclude_id_field=True) + if field.name and field.name.lower() not in existing_fields + ) + + if missing_in_table: + missing_fields[table_name] = missing_in_table + + return missing_tables, missing_fields \ No newline at end of file diff --git a/specifyweb/specify/migration_utils/update_schema_config.py b/specifyweb/specify/migration_utils/update_schema_config.py index 75591205613..d125439dc1c 100644 --- a/specifyweb/specify/migration_utils/update_schema_config.py +++ b/specifyweb/specify/migration_utils/update_schema_config.py @@ -1,28 +1,28 @@ -import re -import json +from specifyweb.specify.migration_utils.SchemaReader import ( + TableSchemaConfig, + FieldSchemaConfig, + TableDefaults, + bulk_create_splocaleitemstr_idempotent, + camel_to_spaced_title_case, + datamodel_type_to_schematype, + find_missing_schema_config_fields, + uncapitilize +) -from typing import NamedTuple, Tuple, TypedDict, NotRequired import logging -from collections import defaultdict -from functools import lru_cache -from pathlib import Path - -from django.db.models import Q, Count, Window, F, Exists, OuterRef -from django.conf import settings from django.apps import apps as global_apps -from django.core.exceptions import MultipleObjectsReturned + from django.db import connection, transaction + +from django.db.models import Q, Window, F, Exists, OuterRef +from django.db import transaction from django.db.models.functions import RowNumber -from specifyweb.specify.models_utils.load_datamodel import FieldDoesNotExistError, TableDoesNotExistError +from typing import NamedTuple, Tuple, TypedDict, NotRequired -from specifyweb.specify.models_utils.load_datamodel import Table, FieldDoesNotExistError, TableDoesNotExistError -from specifyweb.specify.models_utils.model_extras import GEOLOGY_DISCIPLINES, PALEO_DISCIPLINES -from specifyweb.specify.models import ( - Discipline, - datamodel, -) +from specifyweb.specify.models_utils.load_datamodel import FieldDoesNotExistError, TableDoesNotExistError +from specifyweb.specify.models import datamodel from specifyweb.specify.migration_utils.sp7_schemaconfig import ( MIGRATION_0002_TABLES, MIGRATION_0004_FIELDS, @@ -59,206 +59,6 @@ "timestampcreated", "timestampmodified", "version", "createdbyagent", "modifiedbyagent" ] -def _has_explicit_hidden_override(field_config: dict) -> bool: - return any(key.lower() == "ishidden" for key in field_config.keys()) - -@lru_cache(maxsize=None) -def _schema_override_hidden_values_for_discipline( - discipline_type: str, -) -> dict[str, dict[str, bool]]: - """ - Return a mapping of {table_name -> {field_name -> ishidden_value}} for fields - that have an - explicit `ishidden` override in config//schema_overrides.json. - """ - normalized_discipline = (discipline_type or "").lower() - if not normalized_discipline: - return {} - - schema_overrides_path = ( - Path(settings.SPECIFY_CONFIG_DIR) / normalized_discipline / "schema_overrides.json" - ) - if not schema_overrides_path.exists(): - return {} - - try: - with schema_overrides_path.open("r", encoding="utf-8") as schema_overrides_file: - overrides = json.load(schema_overrides_file) - except (OSError, json.JSONDecodeError) as exc: - logger.warning( - "Unable to read schema overrides for discipline '%s' at %s: %s", - normalized_discipline, - schema_overrides_path, - exc, - ) - return {} - - if not isinstance(overrides, dict): - return {} - - hidden_override_values_by_table: dict[str, dict[str, bool]] = {} - for table_name, table_config in overrides.items(): - if not isinstance(table_config, dict): - continue - - explicit_hidden_override_values: dict[str, bool] = {} - items = table_config.get("items", []) - if not isinstance(items, list): - continue - - for item in items: - if not isinstance(item, dict): - continue - - for field_name, field_config in item.items(): - if not isinstance(field_config, dict): - continue - if not _has_explicit_hidden_override(field_config): - continue - for key, value in field_config.items(): - if key.lower() == "ishidden": - explicit_hidden_override_values[field_name.lower()] = bool(value) - break - - if explicit_hidden_override_values: - hidden_override_values_by_table[table_name.lower()] = explicit_hidden_override_values - - return hidden_override_values_by_table - -@lru_cache(maxsize=None) -def _schema_override_hidden_fields_for_discipline(discipline_type: str) -> dict[str, set[str]]: - hidden_override_values = _schema_override_hidden_values_for_discipline(discipline_type) - return { - table_name: set(table_values.keys()) - for table_name, table_values in hidden_override_values.items() - } - -def _fields_without_explicit_hidden_override( - table_name: str, - field_names: list[str], - discipline_type: str, -) -> list[str]: - table_hidden_overrides = _schema_override_hidden_fields_for_discipline( - discipline_type - ).get(table_name.lower(), set()) - return [ - field_name - for field_name in field_names - if field_name.lower() not in table_hidden_overrides - ] - -def datamodel_type_to_schematype(datamodel_type: str) -> str: - """ - Converts a string like `many-to-one` to `ManyToOne` by: - - Splitting on hyphens - - e.g., ['many', 'to', 'one'] - - Lowering then capitilizing each string in the split - - e.g., ['Many', 'To', 'One'] - - Joining the split strings back together - - e.g., 'ManyToOne' - """ - return "".join(map(lambda type_part: type_part.lower().capitalize(), datamodel_type.split('-'))) - -def camel_to_spaced_title_case(camel_case: str) -> str: - """ - Given a camel case string, convert it to title case and add spaces - - - `catalogNumber` -> `Catalog Number` - - `modifiedByAgent` -> `Modified By Agent` - - `yesNo6` -> `Yes No6` - - `cojo` -> `Cojo` - """ - return re.sub(r"(? str: - return string.lower() if len(string) <= 1 else string[0].lower() + string[1:] - -def bulk_create_splocaleitemstr_idempotent(Splocaleitemstr, rows: list[dict]) -> int: - if not rows: - return 0 - - fk_fields = ("itemname", "itemdesc", "containername", "containerdesc") - groups: dict[str, list[dict]] = defaultdict(list) - for r in rows: - present = [f for f in fk_fields if r.get(f) is not None] - if len(present) != 1: - raise ValueError(f"Each row must set exactly one FK among {fk_fields}. Got: {present}") - groups[present[0]].append(r) - - total_created = 0 - - for fk_field, group_rows in groups.items(): - fk_ids: set[int] = set() - languages: set[str] = set() - - for r in group_rows: - fk_ids.add(r[fk_field].pk) - languages.add(r["language"]) - - existing_rows = list( - Splocaleitemstr.objects.filter( - **{ - f"{fk_field}_id__in": fk_ids, - "language__in": languages, - } - ) - .filter( - Q(country__isnull=True) | Q(country=""), - Q(variant__isnull=True) | Q(variant=""), - ) - .order_by("id") - ) - - existing_by_key: dict[Tuple[str, int], list] = defaultdict(list) - fk_field_id = f"{fk_field}_id" - for existing_row in existing_rows: - key = (existing_row.language, getattr(existing_row, fk_field_id)) - existing_by_key[key].append(existing_row) - - desired_by_key: dict[Tuple[str, int], dict] = {} - for r in group_rows: - key = (r["language"], r[fk_field].pk) - desired_by_key[key] = r - - ids_to_delete: set[int] = set() - to_create = [] - for key, desired_row in desired_by_key.items(): - existing_for_key = existing_by_key.get(key, []) - - if not existing_for_key: - to_create.append(Splocaleitemstr(**desired_row)) - continue - - for duplicate in existing_for_key[1:]: - ids_to_delete.add(duplicate.id) - - if ids_to_delete: - Splocaleitemstr.objects.filter(id__in=ids_to_delete).delete() - - if to_create: - Splocaleitemstr.objects.bulk_create(to_create) - total_created += len(to_create) - - return total_created - -class TableDefaults(TypedDict): - name: NotRequired[str] - desc: NotRequired[str] - items: "NotRequired[dict[str, FieldDefaults]]" def update_table_schema_config_with_defaults( table_name, @@ -604,51 +404,6 @@ def update_table_field_schema_config_params( setattr(sp_local_container_item, k, v) sp_local_container_item.save(update_fields=list(update_params.keys())) -def find_missing_schema_config_fields(discipline_id: int, apps=global_apps): - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - - missing_tables: list[str] = [] - missing_fields: dict[str, list[str]] = {} - - containers = Splocalecontainer.objects.filter( - discipline_id=discipline_id, - schematype=0, - ) - container_names = set( - containers.values_list('name', flat=True) - ) - - existing_fields_by_table: dict[str, set[str]] = defaultdict(set) - for table_name, field_name in Splocalecontaineritem.objects.filter( - container__in=containers - ).values_list('container__name', 'name'): - if table_name and field_name: - existing_fields_by_table[table_name].add(field_name.lower()) - - for table in datamodel.tables: - table_name = table.name - table_name_lower = table_name.lower() - 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(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(exclude_id_field=True) - if field.name and field.name.lower() not in existing_fields - ) - - if missing_in_table: - missing_fields[table_name] = missing_in_table - - return missing_tables, missing_fields - - def create_missing_schema_config_fields(discipline_id: int, apps=global_apps, stdout=None): missing_tables, missing_fields = find_missing_schema_config_fields(discipline_id, apps=apps) missing_table_set = set(missing_tables) From a641227ad3f2077d48b71b4628392192fc4a9ac7 Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Mon, 15 Jun 2026 11:02:37 +0200 Subject: [PATCH 059/113] Refactor: Create SchemaWriter for schema writing functions --- .../commands/run_key_migration_functions.py | 1 + .../specify/migration_utils/SchemaWriter.py | 544 ++++++++++++++++++ .../migration_utils/update_schema_config.py | 534 +---------------- 3 files changed, 550 insertions(+), 529 deletions(-) create mode 100644 specifyweb/specify/migration_utils/SchemaWriter.py diff --git a/specifyweb/specify/management/commands/run_key_migration_functions.py b/specifyweb/specify/management/commands/run_key_migration_functions.py index 0f61164f704..4113c7231ce 100644 --- a/specifyweb/specify/management/commands/run_key_migration_functions.py +++ b/specifyweb/specify/management/commands/run_key_migration_functions.py @@ -104,6 +104,7 @@ def apply_schema_overrides_for_all_disciplines(_apps): usc.create_discipline_type_picklist, # specify 0042 # usc.update_discipline_type_splocalecontaineritem, # specify 0042 apply_schema_overrides_for_all_disciplines, + #TODO: Update mport for below line usc.deduplicate_schema_config_orm, ] log_and_run(funcs, stdout) diff --git a/specifyweb/specify/migration_utils/SchemaWriter.py b/specifyweb/specify/migration_utils/SchemaWriter.py new file mode 100644 index 00000000000..6359897ea20 --- /dev/null +++ b/specifyweb/specify/migration_utils/SchemaWriter.py @@ -0,0 +1,544 @@ +from typing import TypedDict, NotRequired +import logging +from collections import defaultdict + +from django.db.models import Q, Exists, OuterRef, F, Window +from django.db import transaction, connection +from django.db.models.functions import RowNumber +from django.apps import apps as global_apps + +from specifyweb.specify.models_utils.load_datamodel import FieldDoesNotExistError, TableDoesNotExistError +from specifyweb.specify.models import datamodel +from specifyweb.specify.migration_utils.SchemaReader import ( + TableSchemaConfig, + FieldSchemaConfig, + TableDefaults, + bulk_create_splocaleitemstr_idempotent, + camel_to_spaced_title_case, + find_missing_schema_config_fields, + uncapitilize, + HIDDEN_FIELDS, + datamodel_type_to_schematype +) + +logger = logging.getLogger(__name__) + +class FieldDefaults(TypedDict): + name: NotRequired[str] + desc: NotRequired[str] + ishidden: NotRequired[bool] + isrequired: NotRequired[bool] + picklistname: NotRequired[str] + +def update_table_schema_config_with_defaults( + table_name, + discipline_id: int, + description: str | None = None, + apps = global_apps, + defaults: TableDefaults | None = None, + pending_itemstr_rows: list[dict] | None = None, +): + Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') + Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') + Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') + + table = datamodel.get_table(table_name) + + # BUG: The splocalecontainer related tables can still exist in the database, + # and this will result in skipping any operation if the table/field is + # removed, renamed, etc. + if table is None: + logger.warning( + f"Table does not exist in latest state of the datamodel, skipping Schema Config entry for: {table_name}" + ) + return + + flush_itemstr_at_end = pending_itemstr_rows is None + if flush_itemstr_at_end: + pending_itemstr_rows = [] + + try: + table_defaults = defaults if defaults is not None else TableDefaults() + table_name_str = table_defaults.get('name', camel_to_spaced_title_case(uncapitilize(table.name))) + table_desc_str = table_defaults.get('desc', camel_to_spaced_title_case(uncapitilize(table.name))) + + table_config = TableSchemaConfig( + name=table.name, + discipline_id=discipline_id, + schema_type=0, + description=table_desc_str if description is None else description, + language="en", + ) + + container_attrs = { + "name": table_config.name.lower(), + "discipline_id": discipline_id, + "schematype": table_config.schema_type + } + + fetched_sp_locale_container = Splocalecontainer.objects.filter(**container_attrs).order_by("id").first() + + if fetched_sp_locale_container is None: + sp_local_container = Splocalecontainer.objects.create(**{ + **container_attrs, + "ishidden": False, + "issystem": table.system, + "version": 0, + }) + else: + sp_local_container = fetched_sp_locale_container + + if Splocalecontaineritem.objects.filter( + container=sp_local_container, + name=table_config.name.lower(), + ).exists(): + return + + item_str_rows = [] + for k, text in { + "containername": table_name_str, + "containerdesc": table_desc_str, + }.items(): + item_str_rows.append( + { + "text": text, + "language": "en", + "version": 0, + k: sp_local_container, + } + ) + + pending_itemstr_rows.extend(item_str_rows) + + 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()) + + update_table_field_schema_config_with_defaults( + table_name, + discipline_id, + field.name, + apps, + defaults=field_defaults, + pending_itemstr_rows=pending_itemstr_rows, + ) + + finally: + if flush_itemstr_at_end and pending_itemstr_rows: + bulk_create_splocaleitemstr_idempotent(Splocaleitemstr, pending_itemstr_rows) + +def revert_table_schema_config(table_name, apps=global_apps): + Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') + Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') + Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') + + containers = Splocalecontainer.objects.filter(name=table_name) + items = Splocalecontaineritem.objects.filter(container__in=containers) + Splocaleitemstr.objects.filter( + Q(itemname__in=items) | + Q(itemdesc__in=items) | + Q(containername__in=containers) | + Q(containerdesc__in=containers) + ).delete() + items.delete() + containers.delete() + +class FieldDefaults(TypedDict): + name: NotRequired[str] + desc: NotRequired[str] + ishidden: NotRequired[bool] + isrequired: NotRequired[bool] + picklistname: NotRequired[str] + +def update_table_field_schema_config_with_defaults( + table_name, + discipline_id: int, + field_name: str, + apps = global_apps, + defaults: FieldDefaults | None = None, + pending_itemstr_rows: list[dict] | None = None, +): + table = datamodel.get_table(table_name) + + # BUG: The splocalecontainer related tables can still exist in the database, + # and this will result in skipping any operation if the table/field is + # removed, renamed, etc. + if table is None: + logger.warning(f"Table does not exist in latest state of the datamodel, skipping Schema Config entry for: {table_name}") + return + + table_name = table.name + table_config = TableSchemaConfig( + name=table_name.lower(), + discipline_id=discipline_id, + schema_type=0, + language="en" + ) + + Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') + Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') + Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') + + sp_local_container = ( + Splocalecontainer.objects.filter( + name=table.name.lower(), + discipline_id=discipline_id, + schematype=table_config.schema_type, + ) + .order_by('id') + .first() + ) + + if sp_local_container is None: + sp_local_container = Splocalecontainer.objects.create( + name=table.name.lower(), + discipline_id=discipline_id, + schematype=table_config.schema_type, + ishidden=False, + issystem=table.system, + version=0, + ) + + try: + field = table.get_field_strict(field_name) + except FieldDoesNotExistError: + if field_name in {'parentCog', 'parentCO', 'children', 'componentParent', 'components'}: + return + logger.warning( + f"Field does not exist in latest state of the datamodel, skipping Schema Config entry for: {table_name} -> {field_name}" + ) + return + except AttributeError: + logger.warning( + f"Field does not exist in latest state of the datamodel, skipping Schema Config entry for: {table_name} -> {field_name}" + ) + return + + # Apply defaults if provided + field_name_str = camel_to_spaced_title_case(field.name) + field_desc_str = camel_to_spaced_title_case(field.name) + field_hidden = field_name.lower() in HIDDEN_FIELDS + field_required = field.required + picklist_name = None + if defaults is not None: + field_name_str = defaults.get('name', field_name_str) + field_desc_str = defaults.get('desc', field_desc_str) + field_hidden = defaults.get('ishidden', field_hidden) + field_required = defaults.get('isrequired', field_required) + picklist_name = defaults.get('picklistname', picklist_name) + + field_config = FieldSchemaConfig( + name=field_name, + column=field.column, + java_type=datamodel_type_to_schematype(field.type) if field.is_relationship else field.type, + description=field_desc_str, + language="en" + ) + + container_item_attrs = { + "name": field_config.name, + "container": sp_local_container + } + + fetched_sp_locale_container_item = Splocalecontaineritem.objects.filter(**container_item_attrs).order_by("id").first() + + if fetched_sp_locale_container_item is None: + sp_locale_container_item = Splocalecontaineritem.objects.create(**{ + **container_item_attrs, + "type": field_config.java_type, + "ishidden": field_hidden, + "isrequired": field_required, + "issystem": table.system, + "version": 0, + "picklistname": picklist_name + } + ) + else: + sp_locale_container_item = fetched_sp_locale_container_item + + itm_str_rows = [] + for k, text in { + "itemname": field_name_str, + "itemdesc": field_desc_str, + }.items(): + row = { + "text": text, + "language": "en", + "version": 0, + k: sp_locale_container_item, + } + itm_str_rows.append(row) + + if pending_itemstr_rows is None: + bulk_create_splocaleitemstr_idempotent(Splocaleitemstr, itm_str_rows) + else: + pending_itemstr_rows.extend(itm_str_rows) + +def revert_table_field_schema_config(table_name, field_name, apps=global_apps): + Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') + Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') + Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') + + containers = Splocalecontainer.objects.filter(name=table_name) + items = Splocalecontaineritem.objects.filter(container__in=containers, name=field_name) + Splocaleitemstr.objects.filter( + Q(itemname__in=items) | + Q(itemdesc__in=items) + ).delete() + items.delete() + +def update_table_field_schema_config_params( + table_name, + discipline_id: int, + field_name: str, + update_params: dict, + apps = global_apps +): + table = datamodel.get_table(table_name) + + if table is None: + logger.warning(f"Table does not exist in latest state of the datamodel, skipping Schema Config entry for: {table_name}") + return + + table_name = table.name + table_config = TableSchemaConfig( + name=table_name.lower(), + discipline_id=discipline_id, + schema_type=0, + language="en" + ) + + Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') + Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') + + sp_local_container = ( + Splocalecontainer.objects.filter( + name=table.name.lower(), + discipline_id=discipline_id, + schematype=table_config.schema_type, + ) + .order_by('id') + .first() + ) + + if sp_local_container is None: + sp_local_container = Splocalecontainer.objects.create( + name=table.name.lower(), + discipline_id=discipline_id, + schematype=table_config.schema_type, + ishidden=False, + issystem=table.system, + version=0, + ) + + try: + field = table.get_field_strict(field_name) + except FieldDoesNotExistError: + logger.warning( + f"Field does not exist in latest state of the datamodel, skipping Schema Config entry for: {table_name} -> {field_name}" + ) + return + except AttributeError: + logger.warning( + f"Field does not exist in latest state of the datamodel, skipping Schema Config entry for: {table_name} -> {field_name}" + ) + return + + field_config = FieldSchemaConfig( + name=field_name, + column=field.column, + java_type=datamodel_type_to_schematype(field.type) if field.is_relationship else field.type, + description=camel_to_spaced_title_case(field.name), + language="en" + ) + + qs = Splocalecontaineritem.objects.filter( + name=field_config.name, + container=sp_local_container, + type=field_config.java_type, + ) + count = qs.count() + + if count == 0: + # logger.warning(f"Splocalecontaineritem does not exist for: {table_name} -> {field_name}, skipping update") + return + + if count > 1: + updated = qs.update(**update_params) + logger.info(f"Updated {updated} duplicate Splocalecontaineritem rows for {table_name}.{field_name}") + return + + sp_local_container_item = qs.first() + for k, v in update_params.items(): + setattr(sp_local_container_item, k, v) + sp_local_container_item.save(update_fields=list(update_params.keys())) + +def create_missing_schema_config_fields(discipline_id: int, apps=global_apps, stdout=None): + missing_tables, missing_fields = find_missing_schema_config_fields(discipline_id, apps=apps) + missing_table_set = set(missing_tables) + + for table_name in missing_tables: + if stdout is not None: + stdout(f"Creating schema config table container for {table_name}...") + update_table_schema_config_with_defaults(table_name, discipline_id, apps=apps) + + for table_name, fields in missing_fields.items(): + if table_name in missing_table_set: + continue + for field_name in fields: + if stdout is not None: + stdout(f"Creating schema config field {table_name}.{field_name}...") + update_table_field_schema_config_with_defaults(table_name, discipline_id, field_name, apps=apps) + + return missing_tables, missing_fields + +def deduplicate_schema_config_sql(apps=None): + dedupe_sql = ''' + /* + + This script removes duplicate entries in the `splocalecontaineritem` table. + + The safe dedupe key is the concrete container row plus the item name: + `SpLocaleContainerID` + `Name`. + + Why this matters: + - Schema config containers can share the same logical table name inside a + discipline while still being distinct rows. + - Grouping by discipline + table name + field name can collapse valid rows + from different containers that merely happen to share the same name. + - Keeping the first row for a specific container/name pair preserves real + schema config entries and only removes true duplicates. + + Any duplicate rows are deleted together with their dependent string rows. + + */ + + + -- 1. Identify all duplicate Container Item IDs + -- We group by the concrete container row and the field name. + -- Only schema-type 0 containers are eligible for this cleanup. + -- We keep the record with the lowest ID (rn = 1) and mark the rest (rn > 1) + CREATE TEMPORARY TABLE container_items_to_delete AS + SELECT + sub.SpLocaleContainerItemID + FROM ( + SELECT + slci.SpLocaleContainerItemID, + ROW_NUMBER() OVER ( + PARTITION BY slci.SpLocaleContainerID, slci.Name + ORDER BY slci.SpLocaleContainerItemID ASC + ) as rn + FROM splocalecontaineritem slci + JOIN splocalecontainer slc ON slci.SpLocaleContainerID = slc.SpLocaleContainerID + WHERE slc.SchemaType = 0 + ) sub + WHERE sub.rn > 1; + + -- 2. Delete the dependent strings first to satisfy Foreign Key constraints + -- This handles strings linked as either 'Name' or 'Description' + DELETE FROM splocaleitemstr + WHERE SpLocaleContainerItemNameID IN (SELECT SpLocaleContainerItemID FROM container_items_to_delete) + OR SpLocaleContainerItemDescID IN (SELECT SpLocaleContainerItemID FROM container_items_to_delete); + + -- 3. Delete the duplicate Container Items + DELETE FROM splocalecontaineritem + WHERE SpLocaleContainerItemID IN (SELECT SpLocaleContainerItemID FROM container_items_to_delete); + + -- 4. Clean up the temporary table + DROP TEMPORARY TABLE container_items_to_delete; + ''' + cursor = connection.cursor() + cursor.execute(dedupe_sql) + cursor.close() + +def deduplicate_splocalecontainers(apps): + Container = apps.get_model('specify', 'SpLocaleContainer') + ContainerItem = apps.get_model('specify', 'SpLocaleContainerItem') + ItemStr = apps.get_model('specify', 'SpLocaleItemStr') + + with transaction.atomic(): + # Find duplicate SpLocaleContainers + # A duplicate should be in the same discipline and have the same name + # and schematype + # For this query we consider the oldest SpLocaleContainer as the + # "cannonical" record, and all later records as the duplicates + # We could be a little smarter about this and also check the associated + # container items and strings, but this should be minimally sufficient + # without sacrificing complexity and speed + # See #7988 + duplicate_containers = Container.objects.filter(schematype=0).annotate( + earlier_exists=Exists( + Container.objects.filter( + discipline_id=OuterRef('discipline_id'), + schematype=0, + name=OuterRef('name'), + timestampcreated__lt=OuterRef('timestampcreated') + ) + ) + ).filter(earlier_exists=True) + + # Remove the items and strings shouldn't be strictly neccesary as they + # should both cascade if we call duplicate_containers.delete() + # But this is the safer option for any edge cases with historical + # models in migrations and if we ever decide to change the delete + # behavior later down the line + # Plus, I don't think the performance impact should be **that** + # significantly different... + duplicate_items = ContainerItem.objects.filter(container__in=duplicate_containers) + ItemStr.objects.filter(itemname__in=duplicate_items).delete() + ItemStr.objects.filter(itemdesc__in=duplicate_items).delete() + duplicate_items.delete() + + ItemStr.objects.filter(containername__in=duplicate_containers).delete() + ItemStr.objects.filter(containerdesc__in=duplicate_containers).delete() + duplicate_containers.delete() + +def deduplicate_containeritems_and_strings(apps): + ContainerItem = apps.get_model('specify', 'SpLocaleContainerItem') + ItemStr = apps.get_model('specify', 'SpLocaleItemStr') + with transaction.atomic(): + # Identify duplicate container items using a Window function. + # Partition by container_id + item name only. + # Only schema type 0 containers (standard schema) are eligible for this cleanup. + # The schema type 1 refers to the WorkBench Schema from Specify 6, which has + # a different structure and should not be modified by this cleanup. + # + # Why this key: + # - Rows are only true duplicates when they refer to the same concrete + # container row and the same field name. + # - Earlier broad grouping by discipline/container-name/field-name could + # collapse valid rows from different containers that happened to share + # names, causing missing Schema Config fields after dedupe. + # - This narrower key preserves legitimate rows and only removes + # duplicates that are semantically equivalent. + qs = ContainerItem.objects.filter( + container__schematype=0, + ).annotate( + rn=Window( + expression=RowNumber(), + partition_by=[ + F('container_id'), + F('name') + ], + order_by=F('id').asc() + ) + ) + + # Extract the IDs of the duplicates, keep the first and delete the rest + ids_to_delete = [item.id for item in qs if item.rn > 1] + + if ids_to_delete: + # Delete dependent strings using corrected field names + ItemStr.objects.filter(itemname_id__in=ids_to_delete).delete() + ItemStr.objects.filter(itemdesc_id__in=ids_to_delete).delete() + # Delete the duplicate Container Items + ContainerItem.objects.filter(id__in=ids_to_delete).delete() + print(f"Successfully deleted {len(ids_to_delete)} duplicate schema items.") + else: + print("No duplicates found.") + +def deduplicate_schema_config_orm(apps, schema_editor=None): + with transaction.atomic(): + deduplicate_splocalecontainers(apps) + deduplicate_containeritems_and_strings(apps) \ No newline at end of file diff --git a/specifyweb/specify/migration_utils/update_schema_config.py b/specifyweb/specify/migration_utils/update_schema_config.py index d125439dc1c..a234e49c7d8 100644 --- a/specifyweb/specify/migration_utils/update_schema_config.py +++ b/specifyweb/specify/migration_utils/update_schema_config.py @@ -1,27 +1,19 @@ from specifyweb.specify.migration_utils.SchemaReader import ( - TableSchemaConfig, - FieldSchemaConfig, - TableDefaults, - bulk_create_splocaleitemstr_idempotent, + _fields_without_explicit_hidden_override, + _schema_override_hidden_values_for_discipline, camel_to_spaced_title_case, datamodel_type_to_schematype, - find_missing_schema_config_fields, uncapitilize ) import logging -from django.apps import apps as global_apps -from django.db import connection, transaction - -from django.db.models import Q, Window, F, Exists, OuterRef -from django.db import transaction -from django.db.models.functions import RowNumber +from django.db.models import Q, Count from typing import NamedTuple, Tuple, TypedDict, NotRequired -from specifyweb.specify.models_utils.load_datamodel import FieldDoesNotExistError, TableDoesNotExistError +from specifyweb.specify.migration_utils.SchemaWriter import revert_table_field_schema_config, revert_table_schema_config, update_table_field_schema_config_params, update_table_field_schema_config_with_defaults, update_table_schema_config_with_defaults from specifyweb.specify.models import datamodel from specifyweb.specify.migration_utils.sp7_schemaconfig import ( MIGRATION_0002_TABLES, @@ -52,6 +44,7 @@ MIGRATION_0040_UPDATE_FIELDS, MIGRATION_0040_HIDDEN_FIELDS, ) +from specifyweb.specify.models_utils.model_extras import GEOLOGY_DISCIPLINES, PALEO_DISCIPLINES logger = logging.getLogger(__name__) @@ -59,523 +52,6 @@ "timestampcreated", "timestampmodified", "version", "createdbyagent", "modifiedbyagent" ] - -def update_table_schema_config_with_defaults( - table_name, - discipline_id: int, - description: str | None = None, - apps = global_apps, - defaults: TableDefaults | None = None, - pending_itemstr_rows: list[dict] | None = None, -): - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') - - table = datamodel.get_table(table_name) - - # BUG: The splocalecontainer related tables can still exist in the database, - # and this will result in skipping any operation if the table/field is - # removed, renamed, etc. - if table is None: - logger.warning( - f"Table does not exist in latest state of the datamodel, skipping Schema Config entry for: {table_name}" - ) - return - - flush_itemstr_at_end = pending_itemstr_rows is None - if flush_itemstr_at_end: - pending_itemstr_rows = [] - - try: - table_defaults = defaults if defaults is not None else TableDefaults() - table_name_str = table_defaults.get('name', camel_to_spaced_title_case(uncapitilize(table.name))) - table_desc_str = table_defaults.get('desc', camel_to_spaced_title_case(uncapitilize(table.name))) - - table_config = TableSchemaConfig( - name=table.name, - discipline_id=discipline_id, - schema_type=0, - description=table_desc_str if description is None else description, - language="en", - ) - - container_attrs = { - "name": table_config.name.lower(), - "discipline_id": discipline_id, - "schematype": table_config.schema_type - } - - fetched_sp_locale_container = Splocalecontainer.objects.filter(**container_attrs).order_by("id").first() - - if fetched_sp_locale_container is None: - sp_local_container = Splocalecontainer.objects.create(**{ - **container_attrs, - "ishidden": False, - "issystem": table.system, - "version": 0, - }) - else: - sp_local_container = fetched_sp_locale_container - - if Splocalecontaineritem.objects.filter( - container=sp_local_container, - name=table_config.name.lower(), - ).exists(): - return - - item_str_rows = [] - for k, text in { - "containername": table_name_str, - "containerdesc": table_desc_str, - }.items(): - item_str_rows.append( - { - "text": text, - "language": "en", - "version": 0, - k: sp_local_container, - } - ) - - pending_itemstr_rows.extend(item_str_rows) - - 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()) - - update_table_field_schema_config_with_defaults( - table_name, - discipline_id, - field.name, - apps, - defaults=field_defaults, - pending_itemstr_rows=pending_itemstr_rows, - ) - - finally: - if flush_itemstr_at_end and pending_itemstr_rows: - bulk_create_splocaleitemstr_idempotent(Splocaleitemstr, pending_itemstr_rows) - -def revert_table_schema_config(table_name, apps=global_apps): - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - - containers = Splocalecontainer.objects.filter(name=table_name) - items = Splocalecontaineritem.objects.filter(container__in=containers) - Splocaleitemstr.objects.filter( - Q(itemname__in=items) | - Q(itemdesc__in=items) | - Q(containername__in=containers) | - Q(containerdesc__in=containers) - ).delete() - items.delete() - containers.delete() - -class FieldDefaults(TypedDict): - name: NotRequired[str] - desc: NotRequired[str] - ishidden: NotRequired[bool] - isrequired: NotRequired[bool] - picklistname: NotRequired[str] - -def update_table_field_schema_config_with_defaults( - table_name, - discipline_id: int, - field_name: str, - apps = global_apps, - defaults: FieldDefaults | None = None, - pending_itemstr_rows: list[dict] | None = None, -): - table = datamodel.get_table(table_name) - - # BUG: The splocalecontainer related tables can still exist in the database, - # and this will result in skipping any operation if the table/field is - # removed, renamed, etc. - if table is None: - logger.warning(f"Table does not exist in latest state of the datamodel, skipping Schema Config entry for: {table_name}") - return - - table_name = table.name - table_config = TableSchemaConfig( - name=table_name.lower(), - discipline_id=discipline_id, - schema_type=0, - language="en" - ) - - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - - sp_local_container = ( - Splocalecontainer.objects.filter( - name=table.name.lower(), - discipline_id=discipline_id, - schematype=table_config.schema_type, - ) - .order_by('id') - .first() - ) - - if sp_local_container is None: - sp_local_container = Splocalecontainer.objects.create( - name=table.name.lower(), - discipline_id=discipline_id, - schematype=table_config.schema_type, - ishidden=False, - issystem=table.system, - version=0, - ) - - try: - field = table.get_field_strict(field_name) - except FieldDoesNotExistError: - if field_name in {'parentCog', 'parentCO', 'children', 'componentParent', 'components'}: - return - logger.warning( - f"Field does not exist in latest state of the datamodel, skipping Schema Config entry for: {table_name} -> {field_name}" - ) - return - except AttributeError: - logger.warning( - f"Field does not exist in latest state of the datamodel, skipping Schema Config entry for: {table_name} -> {field_name}" - ) - return - - # Apply defaults if provided - field_name_str = camel_to_spaced_title_case(field.name) - field_desc_str = camel_to_spaced_title_case(field.name) - field_hidden = field_name.lower() in HIDDEN_FIELDS - field_required = field.required - picklist_name = None - if defaults is not None: - field_name_str = defaults.get('name', field_name_str) - field_desc_str = defaults.get('desc', field_desc_str) - field_hidden = defaults.get('ishidden', field_hidden) - field_required = defaults.get('isrequired', field_required) - picklist_name = defaults.get('picklistname', picklist_name) - - field_config = FieldSchemaConfig( - name=field_name, - column=field.column, - java_type=datamodel_type_to_schematype(field.type) if field.is_relationship else field.type, - description=field_desc_str, - language="en" - ) - - container_item_attrs = { - "name": field_config.name, - "container": sp_local_container - } - - fetched_sp_locale_container_item = Splocalecontaineritem.objects.filter(**container_item_attrs).order_by("id").first() - - if fetched_sp_locale_container_item is None: - sp_locale_container_item = Splocalecontaineritem.objects.create(**{ - **container_item_attrs, - "type": field_config.java_type, - "ishidden": field_hidden, - "isrequired": field_required, - "issystem": table.system, - "version": 0, - "picklistname": picklist_name - } - ) - else: - sp_locale_container_item = fetched_sp_locale_container_item - - itm_str_rows = [] - for k, text in { - "itemname": field_name_str, - "itemdesc": field_desc_str, - }.items(): - row = { - "text": text, - "language": "en", - "version": 0, - k: sp_locale_container_item, - } - itm_str_rows.append(row) - - if pending_itemstr_rows is None: - bulk_create_splocaleitemstr_idempotent(Splocaleitemstr, itm_str_rows) - else: - pending_itemstr_rows.extend(itm_str_rows) - -def revert_table_field_schema_config(table_name, field_name, apps=global_apps): - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - - containers = Splocalecontainer.objects.filter(name=table_name) - items = Splocalecontaineritem.objects.filter(container__in=containers, name=field_name) - Splocaleitemstr.objects.filter( - Q(itemname__in=items) | - Q(itemdesc__in=items) - ).delete() - items.delete() - -def update_table_field_schema_config_params( - table_name, - discipline_id: int, - field_name: str, - update_params: dict, - apps = global_apps -): - table = datamodel.get_table(table_name) - - if table is None: - logger.warning(f"Table does not exist in latest state of the datamodel, skipping Schema Config entry for: {table_name}") - return - - table_name = table.name - table_config = TableSchemaConfig( - name=table_name.lower(), - discipline_id=discipline_id, - schema_type=0, - language="en" - ) - - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - - sp_local_container = ( - Splocalecontainer.objects.filter( - name=table.name.lower(), - discipline_id=discipline_id, - schematype=table_config.schema_type, - ) - .order_by('id') - .first() - ) - - if sp_local_container is None: - sp_local_container = Splocalecontainer.objects.create( - name=table.name.lower(), - discipline_id=discipline_id, - schematype=table_config.schema_type, - ishidden=False, - issystem=table.system, - version=0, - ) - - try: - field = table.get_field_strict(field_name) - except FieldDoesNotExistError: - logger.warning( - f"Field does not exist in latest state of the datamodel, skipping Schema Config entry for: {table_name} -> {field_name}" - ) - return - except AttributeError: - logger.warning( - f"Field does not exist in latest state of the datamodel, skipping Schema Config entry for: {table_name} -> {field_name}" - ) - return - - field_config = FieldSchemaConfig( - name=field_name, - column=field.column, - java_type=datamodel_type_to_schematype(field.type) if field.is_relationship else field.type, - description=camel_to_spaced_title_case(field.name), - language="en" - ) - - qs = Splocalecontaineritem.objects.filter( - name=field_config.name, - container=sp_local_container, - type=field_config.java_type, # maybe remove from filter - ) - count = qs.count() - - if count == 0: - # logger.warning(f"Splocalecontaineritem does not exist for: {table_name} -> {field_name}, skipping update") - return - - if count > 1: - updated = qs.update(**update_params) - logger.info(f"Updated {updated} duplicate Splocalecontaineritem rows for {table_name}.{field_name}") - return - - sp_local_container_item = qs.first() - for k, v in update_params.items(): - setattr(sp_local_container_item, k, v) - sp_local_container_item.save(update_fields=list(update_params.keys())) - -def create_missing_schema_config_fields(discipline_id: int, apps=global_apps, stdout=None): - missing_tables, missing_fields = find_missing_schema_config_fields(discipline_id, apps=apps) - missing_table_set = set(missing_tables) - - for table_name in missing_tables: - if stdout is not None: - stdout(f"Creating schema config table container for {table_name}...") - update_table_schema_config_with_defaults(table_name, discipline_id, apps=apps) - - for table_name, fields in missing_fields.items(): - if table_name in missing_table_set: - continue - for field_name in fields: - if stdout is not None: - stdout(f"Creating schema config field {table_name}.{field_name}...") - update_table_field_schema_config_with_defaults(table_name, discipline_id, field_name, apps=apps) - - return missing_tables, missing_fields - -def deduplicate_schema_config_sql(apps=None): - dedupe_sql = ''' - /* - - This script removes duplicate entries in the `splocalecontaineritem` table. - - The safe dedupe key is the concrete container row plus the item name: - `SpLocaleContainerID` + `Name`. - - Why this matters: - - Schema config containers can share the same logical table name inside a - discipline while still being distinct rows. - - Grouping by discipline + table name + field name can collapse valid rows - from different containers that merely happen to share the same name. - - Keeping the first row for a specific container/name pair preserves real - schema config entries and only removes true duplicates. - - Any duplicate rows are deleted together with their dependent string rows. - - */ - - - -- 1. Identify all duplicate Container Item IDs - -- We group by the concrete container row and the field name. - -- Only schema-type 0 containers are eligible for this cleanup. - -- We keep the record with the lowest ID (rn = 1) and mark the rest (rn > 1) - CREATE TEMPORARY TABLE container_items_to_delete AS - SELECT - sub.SpLocaleContainerItemID - FROM ( - SELECT - slci.SpLocaleContainerItemID, - ROW_NUMBER() OVER ( - PARTITION BY slci.SpLocaleContainerID, slci.Name - ORDER BY slci.SpLocaleContainerItemID ASC - ) as rn - FROM splocalecontaineritem slci - JOIN splocalecontainer slc ON slci.SpLocaleContainerID = slc.SpLocaleContainerID - WHERE slc.SchemaType = 0 - ) sub - WHERE sub.rn > 1; - - -- 2. Delete the dependent strings first to satisfy Foreign Key constraints - -- This handles strings linked as either 'Name' or 'Description' - DELETE FROM splocaleitemstr - WHERE SpLocaleContainerItemNameID IN (SELECT SpLocaleContainerItemID FROM container_items_to_delete) - OR SpLocaleContainerItemDescID IN (SELECT SpLocaleContainerItemID FROM container_items_to_delete); - - -- 3. Delete the duplicate Container Items - DELETE FROM splocalecontaineritem - WHERE SpLocaleContainerItemID IN (SELECT SpLocaleContainerItemID FROM container_items_to_delete); - - -- 4. Clean up the temporary table - DROP TEMPORARY TABLE container_items_to_delete; - ''' - cursor = connection.cursor() - cursor.execute(dedupe_sql) - cursor.close() - -def deduplicate_splocalecontainers(apps): - Container = apps.get_model('specify', 'SpLocaleContainer') - ContainerItem = apps.get_model('specify', 'SpLocaleContainerItem') - ItemStr = apps.get_model('specify', 'SpLocaleItemStr') - - with transaction.atomic(): - # Find duplicate SpLocaleContainers - # A duplicate should be in the same discipline and have the same name - # and schematype - # For this query we consider the oldest SpLocaleContainer as the - # "cannonical" record, and all later records as the duplicates - # We could be a little smarter about this and also check the associated - # container items and strings, but this should be minimally sufficient - # without sacrificing complexity and speed - # See #7988 - duplicate_containers = Container.objects.filter(schematype=0).annotate( - earlier_exists=Exists( - Container.objects.filter( - discipline_id=OuterRef('discipline_id'), - schematype=0, - name=OuterRef('name'), - timestampcreated__lt=OuterRef('timestampcreated') - ) - ) - ).filter(earlier_exists=True) - - # Remove the items and strings shouldn't be strictly neccesary as they - # should both cascade if we call duplicate_containers.delete() - # But this is the safer option for any edge cases with historical - # models in migrations and if we ever decide to change the delete - # behavior later down the line - # Plus, I don't think the performance impact should be **that** - # significantly different... - duplicate_items = ContainerItem.objects.filter(container__in=duplicate_containers) - ItemStr.objects.filter(itemname__in=duplicate_items).delete() - ItemStr.objects.filter(itemdesc__in=duplicate_items).delete() - duplicate_items.delete() - - ItemStr.objects.filter(containername__in=duplicate_containers).delete() - ItemStr.objects.filter(containerdesc__in=duplicate_containers).delete() - duplicate_containers.delete() - - -def deduplicate_containeritems_and_strings(apps): - ContainerItem = apps.get_model('specify', 'SpLocaleContainerItem') - ItemStr = apps.get_model('specify', 'SpLocaleItemStr') - with transaction.atomic(): - # Identify duplicate container items using a Window function. - # Partition by container_id + item name only. - # Only schema type 0 containers (standard schema) are eligible for this cleanup. - # The schema type 1 refers to the WorkBench Schema from Specify 6, which has - # a different structure and should not be modified by this cleanup. - # - # Why this key: - # - Rows are only true duplicates when they refer to the same concrete - # container row and the same field name. - # - Earlier broad grouping by discipline/container-name/field-name could - # collapse valid rows from different containers that happened to share - # names, causing missing Schema Config fields after dedupe. - # - This narrower key preserves legitimate rows and only removes - # duplicates that are semantically equivalent. - qs = ContainerItem.objects.filter( - container__schematype=0, - ).annotate( - rn=Window( - expression=RowNumber(), - partition_by=[ - F('container_id'), - F('name') - ], - order_by=F('id').asc() - ) - ) - - # Extract the IDs of the duplicates, keep the first and delete the rest - ids_to_delete = [item.id for item in qs if item.rn > 1] - - if ids_to_delete: - # Delete dependent strings using corrected field names - ItemStr.objects.filter(itemname_id__in=ids_to_delete).delete() - ItemStr.objects.filter(itemdesc_id__in=ids_to_delete).delete() - - # Delete the duplicate Container Items - ContainerItem.objects.filter(id__in=ids_to_delete).delete() - - print(f"Successfully deleted {len(ids_to_delete)} duplicate schema items.") - else: - print("No duplicates found.") - -def deduplicate_schema_config_orm(apps, schema_editor=None): - with transaction.atomic(): - deduplicate_splocalecontainers(apps) - deduplicate_containeritems_and_strings(apps) - # ############################################################################## # Migration schema config helper functions # ############################################################################## From 93002be882cefe072b5c197e6a682fcc38266b2b Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Mon, 15 Jun 2026 11:09:41 +0200 Subject: [PATCH 060/113] Refactor: Rename update_Schema_config to migrationHelper --- .../{update_schema_config.py => MigrationHelpers.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename specifyweb/specify/migration_utils/{update_schema_config.py => MigrationHelpers.py} (100%) diff --git a/specifyweb/specify/migration_utils/update_schema_config.py b/specifyweb/specify/migration_utils/MigrationHelpers.py similarity index 100% rename from specifyweb/specify/migration_utils/update_schema_config.py rename to specifyweb/specify/migration_utils/MigrationHelpers.py From b6964a7b0d5154afd0dc013f8af71430dfbe7aaf Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Mon, 15 Jun 2026 11:11:52 +0200 Subject: [PATCH 061/113] Refactor: Fix Import --- specifyweb/backend/setup_tool/schema_defaults.py | 2 +- .../backend/workbench/migrations/0007_spdatasetattachment.py | 2 +- .../specify/management/commands/run_key_migration_functions.py | 2 +- .../specify/management/commands/sync_schema_config_fields.py | 2 +- specifyweb/specify/migrations/0002_geo.py | 2 +- specifyweb/specify/migrations/0003_cotype_picklist.py | 2 +- specifyweb/specify/migrations/0004_stratigraphy_age.py | 2 +- specifyweb/specify/migrations/0007_schema_config_update.py | 2 +- specifyweb/specify/migrations/0008_ageCitations_fix.py | 2 +- specifyweb/specify/migrations/0012_add_cojo_to_schema_config.py | 2 +- .../specify/migrations/0013_collectionobjectgroup_parentcog.py | 2 +- specifyweb/specify/migrations/0015_add_version_to_ages.py | 2 +- specifyweb/specify/migrations/0017_schemaconfig_fixes.py | 2 +- specifyweb/specify/migrations/0018_cot_catnum_schema.py | 2 +- .../migrations/0020_add_tectonicunit_to_pc_in_schema_config.py | 2 +- specifyweb/specify/migrations/0021_update_hidden_geo_tables.py | 2 +- specifyweb/specify/migrations/0023_update_schema_config_text.py | 2 +- .../specify/migrations/0024_add_uniqueIdentifier_storage.py | 2 +- specifyweb/specify/migrations/0027_CO_children.py | 2 +- .../specify/migrations/0029_remove_collectionobject_parentco.py | 2 +- specifyweb/specify/migrations/0032_add_quantities_gift.py | 2 +- specifyweb/specify/migrations/0033_update_paleo_desc.py | 2 +- specifyweb/specify/migrations/0034_accession_date_fields.py | 2 +- specifyweb/specify/migrations/0035_version_required.py | 2 +- .../specify/migrations/0039_agent_fields_for_loan_and_gift.py | 2 +- specifyweb/specify/migrations/0040_components.py | 2 +- specifyweb/specify/migrations/0042_discipline_type_picklist.py | 2 +- 27 files changed, 27 insertions(+), 27 deletions(-) diff --git a/specifyweb/backend/setup_tool/schema_defaults.py b/specifyweb/backend/setup_tool/schema_defaults.py index da580abccfd..e136be1210e 100644 --- a/specifyweb/backend/setup_tool/schema_defaults.py +++ b/specifyweb/backend/setup_tool/schema_defaults.py @@ -1,5 +1,5 @@ from specifyweb.specify.models_utils.models_by_table_id import model_names_by_table_id -from specifyweb.specify.migration_utils.update_schema_config import update_table_schema_config_with_defaults +from specifyweb.specify.migration_utils.MigrationHelpers import update_table_schema_config_with_defaults from specifyweb.celery_tasks import app from .utils import load_json_from_file from .task_tracking import queue_discipline_background_task, finish_discipline_background_task diff --git a/specifyweb/backend/workbench/migrations/0007_spdatasetattachment.py b/specifyweb/backend/workbench/migrations/0007_spdatasetattachment.py index 3e1d8bb47db..c5b178c809e 100644 --- a/specifyweb/backend/workbench/migrations/0007_spdatasetattachment.py +++ b/specifyweb/backend/workbench/migrations/0007_spdatasetattachment.py @@ -7,7 +7,7 @@ import django.db.models.deletion import django.utils.timezone import specifyweb.specify.models -from specifyweb.specify.migration_utils.update_schema_config import update_table_field_schema_config_with_defaults, update_table_schema_config_with_defaults, revert_table_field_schema_config, revert_table_schema_config +from specifyweb.specify.migration_utils.MigrationHelpers import update_table_field_schema_config_with_defaults, update_table_schema_config_with_defaults, revert_table_field_schema_config, revert_table_schema_config MIGRATION_0007_TABLES = [ ('SpDataSetAttachment', 'An attachment temporarily associated with a Specify Data Set for use in a WorkBench upload.') diff --git a/specifyweb/specify/management/commands/run_key_migration_functions.py b/specifyweb/specify/management/commands/run_key_migration_functions.py index 4113c7231ce..be094adf9bc 100644 --- a/specifyweb/specify/management/commands/run_key_migration_functions.py +++ b/specifyweb/specify/management/commands/run_key_migration_functions.py @@ -20,7 +20,7 @@ set_discipline_for_taxon_treedefs ) from specifyweb.backend.permissions.initialize import initialize -from specifyweb.specify.migration_utils import update_schema_config as usc +from specifyweb.specify.migration_utils import MigrationHelpers as usc from specifyweb.specify.migration_utils.router import use_migration_connection from specifyweb.specify.migration_utils.misc_migrations import make_selectseries_false from specifyweb.specify.migration_utils.tectonic_ranks import create_default_tectonic_ranks, create_root_tectonic_node, fix_tectonic_unit_treedef_discipline_links diff --git a/specifyweb/specify/management/commands/sync_schema_config_fields.py b/specifyweb/specify/management/commands/sync_schema_config_fields.py index 17da651fcc2..14277fba3ac 100644 --- a/specifyweb/specify/management/commands/sync_schema_config_fields.py +++ b/specifyweb/specify/management/commands/sync_schema_config_fields.py @@ -1,7 +1,7 @@ from django.core.management.base import BaseCommand, CommandError from django.apps import apps -from specifyweb.specify.migration_utils import update_schema_config as update_schema +from specifyweb.specify.migration_utils import MigrationHelpers as update_schema class Command(BaseCommand): diff --git a/specifyweb/specify/migrations/0002_geo.py b/specifyweb/specify/migrations/0002_geo.py index e84e59d5c2e..290552aec1f 100644 --- a/specifyweb/specify/migrations/0002_geo.py +++ b/specifyweb/specify/migrations/0002_geo.py @@ -9,7 +9,7 @@ protect_with_blockers ) from specifyweb.specify.migration_utils.sp7_schemaconfig import MIGRATION_0002_TABLES as SCHEMA_CONFIG_TABLES -from specifyweb.specify.migration_utils import update_schema_config as usc +from specifyweb.specify.migration_utils import MigrationHelpers as usc from specifyweb.specify.migration_utils.default_cots import ( create_cogtype_type_picklist, create_default_collection_types, diff --git a/specifyweb/specify/migrations/0003_cotype_picklist.py b/specifyweb/specify/migrations/0003_cotype_picklist.py index 9d921b074d0..bfd53c082f0 100644 --- a/specifyweb/specify/migrations/0003_cotype_picklist.py +++ b/specifyweb/specify/migrations/0003_cotype_picklist.py @@ -1,5 +1,5 @@ from django.db import migrations -from specifyweb.specify.migration_utils import update_schema_config as usc +from specifyweb.specify.migration_utils import MigrationHelpers as usc from specifyweb.specify.migration_utils.default_cots import create_cotype_picklist, COTYPE_PICKLIST_NAME def revert_cotype_picklist(apps): diff --git a/specifyweb/specify/migrations/0004_stratigraphy_age.py b/specifyweb/specify/migrations/0004_stratigraphy_age.py index eb6636fff99..8634dee9a6c 100644 --- a/specifyweb/specify/migrations/0004_stratigraphy_age.py +++ b/specifyweb/specify/migrations/0004_stratigraphy_age.py @@ -4,7 +4,7 @@ import django.db.models.deletion import django.utils.timezone from specifyweb.specify.models import protect_with_blockers -from specifyweb.specify.migration_utils import update_schema_config as usc +from specifyweb.specify.migration_utils import MigrationHelpers as usc def revert_agetype_picklist(apps): Collection = apps.get_model('specify', 'Collection') diff --git a/specifyweb/specify/migrations/0007_schema_config_update.py b/specifyweb/specify/migrations/0007_schema_config_update.py index 53b6a01f8ec..8d54133ed7c 100644 --- a/specifyweb/specify/migrations/0007_schema_config_update.py +++ b/specifyweb/specify/migrations/0007_schema_config_update.py @@ -16,7 +16,7 @@ from django.db import migrations, models import django.db.models.deletion -from specifyweb.specify.migration_utils import update_schema_config as usc +from specifyweb.specify.migration_utils import MigrationHelpers as usc class Migration(migrations.Migration): dependencies = [ diff --git a/specifyweb/specify/migrations/0008_ageCitations_fix.py b/specifyweb/specify/migrations/0008_ageCitations_fix.py index 9f058e2dbf3..f2db06eeaec 100644 --- a/specifyweb/specify/migrations/0008_ageCitations_fix.py +++ b/specifyweb/specify/migrations/0008_ageCitations_fix.py @@ -3,7 +3,7 @@ from django.db import migrations, models import specifyweb.specify.models -from specifyweb.specify.migration_utils import update_schema_config as usc +from specifyweb.specify.migration_utils import MigrationHelpers as usc class Migration(migrations.Migration): diff --git a/specifyweb/specify/migrations/0012_add_cojo_to_schema_config.py b/specifyweb/specify/migrations/0012_add_cojo_to_schema_config.py index a289553b43f..1470e88aa0d 100644 --- a/specifyweb/specify/migrations/0012_add_cojo_to_schema_config.py +++ b/specifyweb/specify/migrations/0012_add_cojo_to_schema_config.py @@ -2,7 +2,7 @@ This migration adds COG -> cojo and CO -> cojo to Schema Config. """ from django.db import migrations -from specifyweb.specify.migration_utils import update_schema_config as usc +from specifyweb.specify.migration_utils import MigrationHelpers as usc class Migration(migrations.Migration): diff --git a/specifyweb/specify/migrations/0013_collectionobjectgroup_parentcog.py b/specifyweb/specify/migrations/0013_collectionobjectgroup_parentcog.py index 5c0f5f25d4e..fbd8bc0f3f7 100644 --- a/specifyweb/specify/migrations/0013_collectionobjectgroup_parentcog.py +++ b/specifyweb/specify/migrations/0013_collectionobjectgroup_parentcog.py @@ -2,7 +2,7 @@ from django.db import migrations, models import specifyweb.specify.models -from specifyweb.specify.migration_utils import update_schema_config as usc +from specifyweb.specify.migration_utils import MigrationHelpers as usc class Migration(migrations.Migration): diff --git a/specifyweb/specify/migrations/0015_add_version_to_ages.py b/specifyweb/specify/migrations/0015_add_version_to_ages.py index 2dd5d0651b1..06ac538e2ab 100644 --- a/specifyweb/specify/migrations/0015_add_version_to_ages.py +++ b/specifyweb/specify/migrations/0015_add_version_to_ages.py @@ -1,7 +1,7 @@ # Generated by Django 3.2.15 on 2024-12-03 18:59 from django.db import migrations, models -from specifyweb.specify.migration_utils import update_schema_config as usc +from specifyweb.specify.migration_utils import MigrationHelpers as usc class Migration(migrations.Migration): diff --git a/specifyweb/specify/migrations/0017_schemaconfig_fixes.py b/specifyweb/specify/migrations/0017_schemaconfig_fixes.py index f543efeed97..ae33acb6cfe 100644 --- a/specifyweb/specify/migrations/0017_schemaconfig_fixes.py +++ b/specifyweb/specify/migrations/0017_schemaconfig_fixes.py @@ -1,7 +1,7 @@ # Generated by Django 3.2.15 on 2024-11-21 20:08 from django.db import migrations -from specifyweb.specify.migration_utils import update_schema_config as usc +from specifyweb.specify.migration_utils import MigrationHelpers as usc """ This migration fixes two bugs introduced in other migrations by the functions diff --git a/specifyweb/specify/migrations/0018_cot_catnum_schema.py b/specifyweb/specify/migrations/0018_cot_catnum_schema.py index 7e5c378be6d..43b939ec04e 100644 --- a/specifyweb/specify/migrations/0018_cot_catnum_schema.py +++ b/specifyweb/specify/migrations/0018_cot_catnum_schema.py @@ -1,7 +1,7 @@ # Generated by Django 3.2.15 on 2024-11-21 20:08 from django.db import migrations -from specifyweb.specify.migration_utils import update_schema_config as usc +from specifyweb.specify.migration_utils import MigrationHelpers as usc class Migration(migrations.Migration): diff --git a/specifyweb/specify/migrations/0020_add_tectonicunit_to_pc_in_schema_config.py b/specifyweb/specify/migrations/0020_add_tectonicunit_to_pc_in_schema_config.py index 455dd7ee047..1675ce5efc9 100644 --- a/specifyweb/specify/migrations/0020_add_tectonicunit_to_pc_in_schema_config.py +++ b/specifyweb/specify/migrations/0020_add_tectonicunit_to_pc_in_schema_config.py @@ -2,7 +2,7 @@ This migration adds Tectonic Unit -> Paleo Context in the Schema Config. """ from django.db import migrations -from specifyweb.specify.migration_utils import update_schema_config as usc +from specifyweb.specify.migration_utils import MigrationHelpers as usc class Migration(migrations.Migration): diff --git a/specifyweb/specify/migrations/0021_update_hidden_geo_tables.py b/specifyweb/specify/migrations/0021_update_hidden_geo_tables.py index 26dd616c1de..00d319d304c 100644 --- a/specifyweb/specify/migrations/0021_update_hidden_geo_tables.py +++ b/specifyweb/specify/migrations/0021_update_hidden_geo_tables.py @@ -3,7 +3,7 @@ """ from django.db import migrations -from specifyweb.specify.migration_utils import update_schema_config as usc +from specifyweb.specify.migration_utils import MigrationHelpers as usc from specifyweb.specify.migration_utils.sp7_schemaconfig import MIGRATION_0021_FIELDS as SCHEMA_CONFIG_MOD_TABLE_FIELDS from specifyweb.specify.models_utils.model_extras import GEOLOGY_DISCIPLINES, PALEO_DISCIPLINES diff --git a/specifyweb/specify/migrations/0023_update_schema_config_text.py b/specifyweb/specify/migrations/0023_update_schema_config_text.py index 4ddecb4d688..0fceab64c20 100644 --- a/specifyweb/specify/migrations/0023_update_schema_config_text.py +++ b/specifyweb/specify/migrations/0023_update_schema_config_text.py @@ -3,7 +3,7 @@ """ from django.db import migrations -from specifyweb.specify.migration_utils import update_schema_config as usc +from specifyweb.specify.migration_utils import MigrationHelpers as usc class Migration(migrations.Migration): dependencies = [ diff --git a/specifyweb/specify/migrations/0024_add_uniqueIdentifier_storage.py b/specifyweb/specify/migrations/0024_add_uniqueIdentifier_storage.py index e7b26de5b9e..1798371c8c2 100644 --- a/specifyweb/specify/migrations/0024_add_uniqueIdentifier_storage.py +++ b/specifyweb/specify/migrations/0024_add_uniqueIdentifier_storage.py @@ -1,6 +1,6 @@ from django.db import migrations, models from specifyweb.backend.businessrules.uniqueness_rules import DEFAULT_UNIQUENESS_RULES -from specifyweb.specify.migration_utils import update_schema_config as usc +from specifyweb.specify.migration_utils import MigrationHelpers as usc class Migration(migrations.Migration): diff --git a/specifyweb/specify/migrations/0027_CO_children.py b/specifyweb/specify/migrations/0027_CO_children.py index 0dc7ccadad1..f42fd56e5ed 100644 --- a/specifyweb/specify/migrations/0027_CO_children.py +++ b/specifyweb/specify/migrations/0027_CO_children.py @@ -2,7 +2,7 @@ from django.apps import apps as specify_apps from django.db import migrations, models import django.db.models.deletion -from specifyweb.specify.migration_utils import update_schema_config as usc +from specifyweb.specify.migration_utils import MigrationHelpers as usc class Migration(migrations.Migration): diff --git a/specifyweb/specify/migrations/0029_remove_collectionobject_parentco.py b/specifyweb/specify/migrations/0029_remove_collectionobject_parentco.py index 2eeece84774..a258a71bd81 100644 --- a/specifyweb/specify/migrations/0029_remove_collectionobject_parentco.py +++ b/specifyweb/specify/migrations/0029_remove_collectionobject_parentco.py @@ -3,7 +3,7 @@ from django.db import migrations, models import django.db.models.deletion -from specifyweb.specify.migration_utils import update_schema_config as usc +from specifyweb.specify.migration_utils import MigrationHelpers as usc class Migration(migrations.Migration): dependencies = [ diff --git a/specifyweb/specify/migrations/0032_add_quantities_gift.py b/specifyweb/specify/migrations/0032_add_quantities_gift.py index c3acc18d753..1a20f5a4977 100644 --- a/specifyweb/specify/migrations/0032_add_quantities_gift.py +++ b/specifyweb/specify/migrations/0032_add_quantities_gift.py @@ -3,7 +3,7 @@ from django.db import migrations, models from django.apps import apps as specify_apps -from specifyweb.specify.migration_utils import update_schema_config as usc +from specifyweb.specify.migration_utils import MigrationHelpers as usc class Migration(migrations.Migration): diff --git a/specifyweb/specify/migrations/0033_update_paleo_desc.py b/specifyweb/specify/migrations/0033_update_paleo_desc.py index fc9d403e077..68a891e288c 100644 --- a/specifyweb/specify/migrations/0033_update_paleo_desc.py +++ b/specifyweb/specify/migrations/0033_update_paleo_desc.py @@ -1,5 +1,5 @@ from django.db import migrations -from specifyweb.specify.migration_utils import update_schema_config as usc +from specifyweb.specify.migration_utils import MigrationHelpers as usc def schemaconfig_fixes(apps, schema_editor): usc.update_paleo_desc(apps) diff --git a/specifyweb/specify/migrations/0034_accession_date_fields.py b/specifyweb/specify/migrations/0034_accession_date_fields.py index 376cbb80dc5..0a3941c24db 100644 --- a/specifyweb/specify/migrations/0034_accession_date_fields.py +++ b/specifyweb/specify/migrations/0034_accession_date_fields.py @@ -1,7 +1,7 @@ # Generated by Django 4.2.18 on 2025-06-12 23:10 from django.db import migrations, models -from specifyweb.specify.migration_utils import update_schema_config as usc +from specifyweb.specify.migration_utils import MigrationHelpers as usc def apply_migration(apps, schema_editor): usc.update_accession_date_fields(apps) diff --git a/specifyweb/specify/migrations/0035_version_required.py b/specifyweb/specify/migrations/0035_version_required.py index d02b9b543fc..36f219ca0f3 100644 --- a/specifyweb/specify/migrations/0035_version_required.py +++ b/specifyweb/specify/migrations/0035_version_required.py @@ -1,7 +1,7 @@ # Generated by Django 3.2.15 on 2025-04-02 15:28 from django.db import migrations, models -from specifyweb.specify.migration_utils import update_schema_config as usc +from specifyweb.specify.migration_utils import MigrationHelpers as usc def apply_migration(apps, schema_editor): usc.update_version_required(apps) diff --git a/specifyweb/specify/migrations/0039_agent_fields_for_loan_and_gift.py b/specifyweb/specify/migrations/0039_agent_fields_for_loan_and_gift.py index d5f1e0d9435..9f0b475e7d9 100644 --- a/specifyweb/specify/migrations/0039_agent_fields_for_loan_and_gift.py +++ b/specifyweb/specify/migrations/0039_agent_fields_for_loan_and_gift.py @@ -4,7 +4,7 @@ from django.db import migrations, models from specifyweb.specify.models import protect_with_blockers -from specifyweb.specify.migration_utils import update_schema_config as usc +from specifyweb.specify.migration_utils import MigrationHelpers as usc def consolidated_0038_forward(apps, schema_editor): usc.update_loan_and_gift_agent_fields(apps) diff --git a/specifyweb/specify/migrations/0040_components.py b/specifyweb/specify/migrations/0040_components.py index 7a0591d22bd..c012fb8a00e 100644 --- a/specifyweb/specify/migrations/0040_components.py +++ b/specifyweb/specify/migrations/0040_components.py @@ -4,7 +4,7 @@ import django.db.models.deletion import django.utils.timezone import specifyweb.specify.models -from specifyweb.specify.migration_utils import update_schema_config as usc +from specifyweb.specify.migration_utils import MigrationHelpers as usc from specifyweb.specify.models import protect_with_blockers class Migration(migrations.Migration): diff --git a/specifyweb/specify/migrations/0042_discipline_type_picklist.py b/specifyweb/specify/migrations/0042_discipline_type_picklist.py index f75d72aeb45..f9dfc815cf9 100644 --- a/specifyweb/specify/migrations/0042_discipline_type_picklist.py +++ b/specifyweb/specify/migrations/0042_discipline_type_picklist.py @@ -1,5 +1,5 @@ from django.db import migrations -from specifyweb.specify.migration_utils import update_schema_config as usc +from specifyweb.specify.migration_utils import MigrationHelpers as usc class Migration(migrations.Migration): dependencies = [ From 915f36aee61da6b4a9f5d5d71cc8466d6d277868 Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Mon, 15 Jun 2026 12:12:20 +0200 Subject: [PATCH 062/113] Refactor: Create a deduplication file --- .../specify/migration_utils/Deduplication.py | 157 ++++++++++++++++++ .../specify/migration_utils/SchemaReader.py | 1 + .../specify/migration_utils/SchemaWriter.py | 154 +---------------- 3 files changed, 159 insertions(+), 153 deletions(-) create mode 100644 specifyweb/specify/migration_utils/Deduplication.py diff --git a/specifyweb/specify/migration_utils/Deduplication.py b/specifyweb/specify/migration_utils/Deduplication.py new file mode 100644 index 00000000000..93833a0010d --- /dev/null +++ b/specifyweb/specify/migration_utils/Deduplication.py @@ -0,0 +1,157 @@ +from django.db import connection, transaction +from django.db.models import Count, Q, F, Window, OuterRef, Exists +from django.apps import apps as global_apps +import logging +from django.db.models.functions import RowNumber + +logger = logging.getLogger(__name__) + +def deduplicate_schema_config_sql(apps=None): + dedupe_sql = ''' + /* + + This script removes duplicate entries in the `splocalecontaineritem` table. + + The safe dedupe key is the concrete container row plus the item name: + `SpLocaleContainerID` + `Name`. + + Why this matters: + - Schema config containers can share the same logical table name inside a + discipline while still being distinct rows. + - Grouping by discipline + table name + field name can collapse valid rows + from different containers that merely happen to share the same name. + - Keeping the first row for a specific container/name pair preserves real + schema config entries and only removes true duplicates. + + Any duplicate rows are deleted together with their dependent string rows. + + */ + + + -- 1. Identify all duplicate Container Item IDs + -- We group by the concrete container row and the field name. + -- Only schema-type 0 containers are eligible for this cleanup. + -- We keep the record with the lowest ID (rn = 1) and mark the rest (rn > 1) + CREATE TEMPORARY TABLE container_items_to_delete AS + SELECT + sub.SpLocaleContainerItemID + FROM ( + SELECT + slci.SpLocaleContainerItemID, + ROW_NUMBER() OVER ( + PARTITION BY slci.SpLocaleContainerID, slci.Name + ORDER BY slci.SpLocaleContainerItemID ASC + ) as rn + FROM splocalecontaineritem slci + JOIN splocalecontainer slc ON slci.SpLocaleContainerID = slc.SpLocaleContainerID + WHERE slc.SchemaType = 0 + ) sub + WHERE sub.rn > 1; + + -- 2. Delete the dependent strings first to satisfy Foreign Key constraints + -- This handles strings linked as either 'Name' or 'Description' + DELETE FROM splocaleitemstr + WHERE SpLocaleContainerItemNameID IN (SELECT SpLocaleContainerItemID FROM container_items_to_delete) + OR SpLocaleContainerItemDescID IN (SELECT SpLocaleContainerItemID FROM container_items_to_delete); + + -- 3. Delete the duplicate Container Items + DELETE FROM splocalecontaineritem + WHERE SpLocaleContainerItemID IN (SELECT SpLocaleContainerItemID FROM container_items_to_delete); + + -- 4. Clean up the temporary table + DROP TEMPORARY TABLE container_items_to_delete; + ''' + cursor = connection.cursor() + cursor.execute(dedupe_sql) + cursor.close() + +def deduplicate_splocalecontainers(apps): + Container = apps.get_model('specify', 'SpLocaleContainer') + ContainerItem = apps.get_model('specify', 'SpLocaleContainerItem') + ItemStr = apps.get_model('specify', 'SpLocaleItemStr') + + with transaction.atomic(): + # Find duplicate SpLocaleContainers + # A duplicate should be in the same discipline and have the same name + # and schematype + # For this query we consider the oldest SpLocaleContainer as the + # "cannonical" record, and all later records as the duplicates + # We could be a little smarter about this and also check the associated + # container items and strings, but this should be minimally sufficient + # without sacrificing complexity and speed + # See #7988 + duplicate_containers = Container.objects.filter(schematype=0).annotate( + earlier_exists=Exists( + Container.objects.filter( + discipline_id=OuterRef('discipline_id'), + schematype=0, + name=OuterRef('name'), + timestampcreated__lt=OuterRef('timestampcreated') + ) + ) + ).filter(earlier_exists=True) + + # Remove the items and strings shouldn't be strictly neccesary as they + # should both cascade if we call duplicate_containers.delete() + # But this is the safer option for any edge cases with historical + # models in migrations and if we ever decide to change the delete + # behavior later down the line + # Plus, I don't think the performance impact should be **that** + # significantly different... + duplicate_items = ContainerItem.objects.filter(container__in=duplicate_containers) + ItemStr.objects.filter(itemname__in=duplicate_items).delete() + ItemStr.objects.filter(itemdesc__in=duplicate_items).delete() + duplicate_items.delete() + + ItemStr.objects.filter(containername__in=duplicate_containers).delete() + ItemStr.objects.filter(containerdesc__in=duplicate_containers).delete() + duplicate_containers.delete() + +def deduplicate_containeritems_and_strings(apps): + ContainerItem = apps.get_model('specify', 'SpLocaleContainerItem') + ItemStr = apps.get_model('specify', 'SpLocaleItemStr') + with transaction.atomic(): + # Identify duplicate container items using a Window function. + # Partition by container_id + item name only. + # Only schema type 0 containers (standard schema) are eligible for this cleanup. + # The schema type 1 refers to the WorkBench Schema from Specify 6, which has + # a different structure and should not be modified by this cleanup. + # + # Why this key: + # - Rows are only true duplicates when they refer to the same concrete + # container row and the same field name. + # - Earlier broad grouping by discipline/container-name/field-name could + # collapse valid rows from different containers that happened to share + # names, causing missing Schema Config fields after dedupe. + # - This narrower key preserves legitimate rows and only removes + # duplicates that are semantically equivalent. + qs = ContainerItem.objects.filter( + container__schematype=0, + ).annotate( + rn=Window( + expression=RowNumber(), + partition_by=[ + F('container_id'), + F('name') + ], + order_by=F('id').asc() + ) + ) + + # Extract the IDs of the duplicates, keep the first and delete the rest + ids_to_delete = [item.id for item in qs if item.rn > 1] + + if ids_to_delete: + # Delete dependent strings using corrected field names + ItemStr.objects.filter(itemname_id__in=ids_to_delete).delete() + ItemStr.objects.filter(itemdesc_id__in=ids_to_delete).delete() + # Delete the duplicate Container Items + ContainerItem.objects.filter(id__in=ids_to_delete).delete() + print(f"Successfully deleted {len(ids_to_delete)} duplicate schema items.") + else: + print("No duplicates found.") + +def deduplicate_schema_config_orm(apps, schema_editor=None): + with transaction.atomic(): + deduplicate_splocalecontainers(apps) + deduplicate_containeritems_and_strings(apps) diff --git a/specifyweb/specify/migration_utils/SchemaReader.py b/specifyweb/specify/migration_utils/SchemaReader.py index 4426a5757d6..88f84459bec 100644 --- a/specifyweb/specify/migration_utils/SchemaReader.py +++ b/specifyweb/specify/migration_utils/SchemaReader.py @@ -15,6 +15,7 @@ from django.db import connection, transaction from django.db.models.functions import RowNumber +from specifyweb.specify.migration_utils.SchemaWriter import FieldDefaults from specifyweb.specify.models_utils.load_datamodel import FieldDoesNotExistError, TableDoesNotExistError from specifyweb.specify.models_utils.load_datamodel import Table, FieldDoesNotExistError, TableDoesNotExistError diff --git a/specifyweb/specify/migration_utils/SchemaWriter.py b/specifyweb/specify/migration_utils/SchemaWriter.py index 6359897ea20..e630801b9a5 100644 --- a/specifyweb/specify/migration_utils/SchemaWriter.py +++ b/specifyweb/specify/migration_utils/SchemaWriter.py @@ -2,9 +2,7 @@ import logging from collections import defaultdict -from django.db.models import Q, Exists, OuterRef, F, Window -from django.db import transaction, connection -from django.db.models.functions import RowNumber +from django.db.models import Q from django.apps import apps as global_apps from specifyweb.specify.models_utils.load_datamodel import FieldDoesNotExistError, TableDoesNotExistError @@ -392,153 +390,3 @@ def create_missing_schema_config_fields(discipline_id: int, apps=global_apps, st update_table_field_schema_config_with_defaults(table_name, discipline_id, field_name, apps=apps) return missing_tables, missing_fields - -def deduplicate_schema_config_sql(apps=None): - dedupe_sql = ''' - /* - - This script removes duplicate entries in the `splocalecontaineritem` table. - - The safe dedupe key is the concrete container row plus the item name: - `SpLocaleContainerID` + `Name`. - - Why this matters: - - Schema config containers can share the same logical table name inside a - discipline while still being distinct rows. - - Grouping by discipline + table name + field name can collapse valid rows - from different containers that merely happen to share the same name. - - Keeping the first row for a specific container/name pair preserves real - schema config entries and only removes true duplicates. - - Any duplicate rows are deleted together with their dependent string rows. - - */ - - - -- 1. Identify all duplicate Container Item IDs - -- We group by the concrete container row and the field name. - -- Only schema-type 0 containers are eligible for this cleanup. - -- We keep the record with the lowest ID (rn = 1) and mark the rest (rn > 1) - CREATE TEMPORARY TABLE container_items_to_delete AS - SELECT - sub.SpLocaleContainerItemID - FROM ( - SELECT - slci.SpLocaleContainerItemID, - ROW_NUMBER() OVER ( - PARTITION BY slci.SpLocaleContainerID, slci.Name - ORDER BY slci.SpLocaleContainerItemID ASC - ) as rn - FROM splocalecontaineritem slci - JOIN splocalecontainer slc ON slci.SpLocaleContainerID = slc.SpLocaleContainerID - WHERE slc.SchemaType = 0 - ) sub - WHERE sub.rn > 1; - - -- 2. Delete the dependent strings first to satisfy Foreign Key constraints - -- This handles strings linked as either 'Name' or 'Description' - DELETE FROM splocaleitemstr - WHERE SpLocaleContainerItemNameID IN (SELECT SpLocaleContainerItemID FROM container_items_to_delete) - OR SpLocaleContainerItemDescID IN (SELECT SpLocaleContainerItemID FROM container_items_to_delete); - - -- 3. Delete the duplicate Container Items - DELETE FROM splocalecontaineritem - WHERE SpLocaleContainerItemID IN (SELECT SpLocaleContainerItemID FROM container_items_to_delete); - - -- 4. Clean up the temporary table - DROP TEMPORARY TABLE container_items_to_delete; - ''' - cursor = connection.cursor() - cursor.execute(dedupe_sql) - cursor.close() - -def deduplicate_splocalecontainers(apps): - Container = apps.get_model('specify', 'SpLocaleContainer') - ContainerItem = apps.get_model('specify', 'SpLocaleContainerItem') - ItemStr = apps.get_model('specify', 'SpLocaleItemStr') - - with transaction.atomic(): - # Find duplicate SpLocaleContainers - # A duplicate should be in the same discipline and have the same name - # and schematype - # For this query we consider the oldest SpLocaleContainer as the - # "cannonical" record, and all later records as the duplicates - # We could be a little smarter about this and also check the associated - # container items and strings, but this should be minimally sufficient - # without sacrificing complexity and speed - # See #7988 - duplicate_containers = Container.objects.filter(schematype=0).annotate( - earlier_exists=Exists( - Container.objects.filter( - discipline_id=OuterRef('discipline_id'), - schematype=0, - name=OuterRef('name'), - timestampcreated__lt=OuterRef('timestampcreated') - ) - ) - ).filter(earlier_exists=True) - - # Remove the items and strings shouldn't be strictly neccesary as they - # should both cascade if we call duplicate_containers.delete() - # But this is the safer option for any edge cases with historical - # models in migrations and if we ever decide to change the delete - # behavior later down the line - # Plus, I don't think the performance impact should be **that** - # significantly different... - duplicate_items = ContainerItem.objects.filter(container__in=duplicate_containers) - ItemStr.objects.filter(itemname__in=duplicate_items).delete() - ItemStr.objects.filter(itemdesc__in=duplicate_items).delete() - duplicate_items.delete() - - ItemStr.objects.filter(containername__in=duplicate_containers).delete() - ItemStr.objects.filter(containerdesc__in=duplicate_containers).delete() - duplicate_containers.delete() - -def deduplicate_containeritems_and_strings(apps): - ContainerItem = apps.get_model('specify', 'SpLocaleContainerItem') - ItemStr = apps.get_model('specify', 'SpLocaleItemStr') - with transaction.atomic(): - # Identify duplicate container items using a Window function. - # Partition by container_id + item name only. - # Only schema type 0 containers (standard schema) are eligible for this cleanup. - # The schema type 1 refers to the WorkBench Schema from Specify 6, which has - # a different structure and should not be modified by this cleanup. - # - # Why this key: - # - Rows are only true duplicates when they refer to the same concrete - # container row and the same field name. - # - Earlier broad grouping by discipline/container-name/field-name could - # collapse valid rows from different containers that happened to share - # names, causing missing Schema Config fields after dedupe. - # - This narrower key preserves legitimate rows and only removes - # duplicates that are semantically equivalent. - qs = ContainerItem.objects.filter( - container__schematype=0, - ).annotate( - rn=Window( - expression=RowNumber(), - partition_by=[ - F('container_id'), - F('name') - ], - order_by=F('id').asc() - ) - ) - - # Extract the IDs of the duplicates, keep the first and delete the rest - ids_to_delete = [item.id for item in qs if item.rn > 1] - - if ids_to_delete: - # Delete dependent strings using corrected field names - ItemStr.objects.filter(itemname_id__in=ids_to_delete).delete() - ItemStr.objects.filter(itemdesc_id__in=ids_to_delete).delete() - # Delete the duplicate Container Items - ContainerItem.objects.filter(id__in=ids_to_delete).delete() - print(f"Successfully deleted {len(ids_to_delete)} duplicate schema items.") - else: - print("No duplicates found.") - -def deduplicate_schema_config_orm(apps, schema_editor=None): - with transaction.atomic(): - deduplicate_splocalecontainers(apps) - deduplicate_containeritems_and_strings(apps) \ No newline at end of file From a2c9f1c9f1e6956ee5eb7e0462dda6a565233093 Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Mon, 15 Jun 2026 12:17:58 +0200 Subject: [PATCH 063/113] Refactor: Change import --- .../management/commands/run_key_migration_functions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/specifyweb/specify/management/commands/run_key_migration_functions.py b/specifyweb/specify/management/commands/run_key_migration_functions.py index be094adf9bc..de8b36d2893 100644 --- a/specifyweb/specify/management/commands/run_key_migration_functions.py +++ b/specifyweb/specify/management/commands/run_key_migration_functions.py @@ -21,6 +21,7 @@ ) from specifyweb.backend.permissions.initialize import initialize from specifyweb.specify.migration_utils import MigrationHelpers as usc +from specifyweb.specify.migration_utils.Deduplication import deduplicate_schema_config_orm from specifyweb.specify.migration_utils.router import use_migration_connection from specifyweb.specify.migration_utils.misc_migrations import make_selectseries_false from specifyweb.specify.migration_utils.tectonic_ranks import create_default_tectonic_ranks, create_root_tectonic_node, fix_tectonic_unit_treedef_discipline_links @@ -104,8 +105,7 @@ def apply_schema_overrides_for_all_disciplines(_apps): usc.create_discipline_type_picklist, # specify 0042 # usc.update_discipline_type_splocalecontaineritem, # specify 0042 apply_schema_overrides_for_all_disciplines, - #TODO: Update mport for below line - usc.deduplicate_schema_config_orm, + deduplicate_schema_config_orm, ] log_and_run(funcs, stdout) From 0d4250899e7128f99507e5eda02aa02db0454776 Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Mon, 15 Jun 2026 12:24:21 +0200 Subject: [PATCH 064/113] Fix: Remove imports --- .../specify/migration_utils/SchemaReader.py | 45 +------------------ .../specify/migration_utils/SchemaWriter.py | 12 +++-- 2 files changed, 10 insertions(+), 47 deletions(-) diff --git a/specifyweb/specify/migration_utils/SchemaReader.py b/specifyweb/specify/migration_utils/SchemaReader.py index 88f84459bec..150e4818a4d 100644 --- a/specifyweb/specify/migration_utils/SchemaReader.py +++ b/specifyweb/specify/migration_utils/SchemaReader.py @@ -8,51 +8,15 @@ from pathlib import Path -from django.db.models import Q, Count, Window, F, Exists, OuterRef +from django.db.models import Q from django.conf import settings from django.apps import apps as global_apps -from django.core.exceptions import MultipleObjectsReturned -from django.db import connection, transaction -from django.db.models.functions import RowNumber from specifyweb.specify.migration_utils.SchemaWriter import FieldDefaults -from specifyweb.specify.models_utils.load_datamodel import FieldDoesNotExistError, TableDoesNotExistError -from specifyweb.specify.models_utils.load_datamodel import Table, FieldDoesNotExistError, TableDoesNotExistError -from specifyweb.specify.models_utils.model_extras import GEOLOGY_DISCIPLINES, PALEO_DISCIPLINES from specifyweb.specify.models import ( - Discipline, datamodel, ) -from specifyweb.specify.migration_utils.sp7_schemaconfig import ( - MIGRATION_0002_TABLES, - MIGRATION_0004_FIELDS, - MIGRATION_0004_TABLES, - MIGRATION_0007_FIELDS, - MIGRATION_0008_FIELDS, - MIGRATION_0012_FIELDS, - MIGRATION_0013_FIELDS, - MIGRATION_0020_FIELDS, - MIGRATION_0021_FIELDS, - MIGRATION_0023_FIELDS, - MIGRATION_0023_FIELDS_BIS, - MIGRATION_0024_FIELDS, - MIGRATION_0027_FIELDS, - MIGRATION_0027_UPDATE_FIELDS, - MIGRATION_0029_FIELDS, - MIGRATION_0029_UPDATE_FIELDS, - MIGRATION_0032_FIELDS, - MIGRATION_0032_UPDATE_FIELDS, - MIGRATION_0033_TABLES, - MIGRATION_0034_FIELDS, - MIGRATION_0034_UPDATE_FIELDS, - MIGRATION_0035_FIELDS, - MIGRATION_0038_FIELDS, - MIGRATION_0040_TABLES, - MIGRATION_0040_FIELDS, - MIGRATION_0040_UPDATE_FIELDS, - MIGRATION_0040_HIDDEN_FIELDS, -) logger = logging.getLogger(__name__) @@ -171,13 +135,6 @@ def camel_to_spaced_title_case(camel_case: str) -> str: """ return re.sub(r"(? Date: Mon, 15 Jun 2026 12:25:40 +0200 Subject: [PATCH 065/113] Refactor: Remove imports --- specifyweb/specify/migration_utils/Deduplication.py | 2 +- specifyweb/specify/migration_utils/MigrationHelpers.py | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/specifyweb/specify/migration_utils/Deduplication.py b/specifyweb/specify/migration_utils/Deduplication.py index 93833a0010d..1086f65b167 100644 --- a/specifyweb/specify/migration_utils/Deduplication.py +++ b/specifyweb/specify/migration_utils/Deduplication.py @@ -1,5 +1,5 @@ from django.db import connection, transaction -from django.db.models import Count, Q, F, Window, OuterRef, Exists +from django.db.models import F, Window, OuterRef, Exists from django.apps import apps as global_apps import logging from django.db.models.functions import RowNumber diff --git a/specifyweb/specify/migration_utils/MigrationHelpers.py b/specifyweb/specify/migration_utils/MigrationHelpers.py index a234e49c7d8..e9ca311678c 100644 --- a/specifyweb/specify/migration_utils/MigrationHelpers.py +++ b/specifyweb/specify/migration_utils/MigrationHelpers.py @@ -11,8 +11,6 @@ from django.db.models import Q, Count -from typing import NamedTuple, Tuple, TypedDict, NotRequired - from specifyweb.specify.migration_utils.SchemaWriter import revert_table_field_schema_config, revert_table_schema_config, update_table_field_schema_config_params, update_table_field_schema_config_with_defaults, update_table_schema_config_with_defaults from specifyweb.specify.models import datamodel from specifyweb.specify.migration_utils.sp7_schemaconfig import ( From 6a507dc61afa5a19536519fe810807e824dc816b Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Mon, 15 Jun 2026 14:30:25 +0200 Subject: [PATCH 066/113] Refactor: Renaming --- specifyweb/backend/setup_tool/schema_defaults.py | 2 +- .../backend/workbench/migrations/0007_spdatasetattachment.py | 2 +- .../management/commands/run_key_migration_functions.py | 2 +- .../specify/management/commands/sync_schema_config_fields.py | 2 +- .../{MigrationHelpers.py => migration_helpers.py} | 4 ++-- .../migration_utils/{SchemaReader.py => schema_reader.py} | 2 +- .../migration_utils/{SchemaWriter.py => schema_writer.py} | 2 +- specifyweb/specify/migrations/0002_geo.py | 2 +- specifyweb/specify/migrations/0003_cotype_picklist.py | 2 +- specifyweb/specify/migrations/0004_stratigraphy_age.py | 2 +- specifyweb/specify/migrations/0007_schema_config_update.py | 2 +- specifyweb/specify/migrations/0008_ageCitations_fix.py | 2 +- .../specify/migrations/0012_add_cojo_to_schema_config.py | 2 +- .../migrations/0013_collectionobjectgroup_parentcog.py | 2 +- specifyweb/specify/migrations/0015_add_version_to_ages.py | 2 +- specifyweb/specify/migrations/0017_schemaconfig_fixes.py | 2 +- specifyweb/specify/migrations/0018_cot_catnum_schema.py | 2 +- .../0020_add_tectonicunit_to_pc_in_schema_config.py | 2 +- .../specify/migrations/0021_update_hidden_geo_tables.py | 2 +- .../specify/migrations/0023_update_schema_config_text.py | 2 +- .../specify/migrations/0024_add_uniqueIdentifier_storage.py | 2 +- specifyweb/specify/migrations/0027_CO_children.py | 2 +- .../migrations/0029_remove_collectionobject_parentco.py | 2 +- specifyweb/specify/migrations/0032_add_quantities_gift.py | 2 +- specifyweb/specify/migrations/0033_update_paleo_desc.py | 2 +- specifyweb/specify/migrations/0034_accession_date_fields.py | 2 +- specifyweb/specify/migrations/0035_version_required.py | 2 +- .../specify/migrations/0039_agent_fields_for_loan_and_gift.py | 2 +- specifyweb/specify/migrations/0040_components.py | 2 +- .../specify/migrations/0042_discipline_type_picklist.py | 2 +- 30 files changed, 31 insertions(+), 31 deletions(-) rename specifyweb/specify/migration_utils/{MigrationHelpers.py => migration_helpers.py} (99%) rename specifyweb/specify/migration_utils/{SchemaReader.py => schema_reader.py} (99%) rename specifyweb/specify/migration_utils/{SchemaWriter.py => schema_writer.py} (99%) diff --git a/specifyweb/backend/setup_tool/schema_defaults.py b/specifyweb/backend/setup_tool/schema_defaults.py index e136be1210e..0af1052db51 100644 --- a/specifyweb/backend/setup_tool/schema_defaults.py +++ b/specifyweb/backend/setup_tool/schema_defaults.py @@ -1,5 +1,5 @@ from specifyweb.specify.models_utils.models_by_table_id import model_names_by_table_id -from specifyweb.specify.migration_utils.MigrationHelpers import update_table_schema_config_with_defaults +from specifyweb.specify.migration_utils.migration_helpers import update_table_schema_config_with_defaults from specifyweb.celery_tasks import app from .utils import load_json_from_file from .task_tracking import queue_discipline_background_task, finish_discipline_background_task diff --git a/specifyweb/backend/workbench/migrations/0007_spdatasetattachment.py b/specifyweb/backend/workbench/migrations/0007_spdatasetattachment.py index c5b178c809e..392eb67f7a8 100644 --- a/specifyweb/backend/workbench/migrations/0007_spdatasetattachment.py +++ b/specifyweb/backend/workbench/migrations/0007_spdatasetattachment.py @@ -7,7 +7,7 @@ import django.db.models.deletion import django.utils.timezone import specifyweb.specify.models -from specifyweb.specify.migration_utils.MigrationHelpers import update_table_field_schema_config_with_defaults, update_table_schema_config_with_defaults, revert_table_field_schema_config, revert_table_schema_config +from specifyweb.specify.migration_utils.migration_helpers import update_table_field_schema_config_with_defaults, update_table_schema_config_with_defaults, revert_table_field_schema_config, revert_table_schema_config MIGRATION_0007_TABLES = [ ('SpDataSetAttachment', 'An attachment temporarily associated with a Specify Data Set for use in a WorkBench upload.') diff --git a/specifyweb/specify/management/commands/run_key_migration_functions.py b/specifyweb/specify/management/commands/run_key_migration_functions.py index de8b36d2893..8b82afbea10 100644 --- a/specifyweb/specify/management/commands/run_key_migration_functions.py +++ b/specifyweb/specify/management/commands/run_key_migration_functions.py @@ -20,7 +20,7 @@ set_discipline_for_taxon_treedefs ) from specifyweb.backend.permissions.initialize import initialize -from specifyweb.specify.migration_utils import MigrationHelpers as usc +from specifyweb.specify.migration_utils import migration_helpers as usc from specifyweb.specify.migration_utils.Deduplication import deduplicate_schema_config_orm from specifyweb.specify.migration_utils.router import use_migration_connection from specifyweb.specify.migration_utils.misc_migrations import make_selectseries_false diff --git a/specifyweb/specify/management/commands/sync_schema_config_fields.py b/specifyweb/specify/management/commands/sync_schema_config_fields.py index 14277fba3ac..090bc1d6b5e 100644 --- a/specifyweb/specify/management/commands/sync_schema_config_fields.py +++ b/specifyweb/specify/management/commands/sync_schema_config_fields.py @@ -1,7 +1,7 @@ from django.core.management.base import BaseCommand, CommandError from django.apps import apps -from specifyweb.specify.migration_utils import MigrationHelpers as update_schema +from specifyweb.specify.migration_utils import migration_helpers as update_schema class Command(BaseCommand): diff --git a/specifyweb/specify/migration_utils/MigrationHelpers.py b/specifyweb/specify/migration_utils/migration_helpers.py similarity index 99% rename from specifyweb/specify/migration_utils/MigrationHelpers.py rename to specifyweb/specify/migration_utils/migration_helpers.py index e9ca311678c..9164d1bc31d 100644 --- a/specifyweb/specify/migration_utils/MigrationHelpers.py +++ b/specifyweb/specify/migration_utils/migration_helpers.py @@ -1,4 +1,4 @@ -from specifyweb.specify.migration_utils.SchemaReader import ( +from specifyweb.specify.migration_utils.schema_reader import ( _fields_without_explicit_hidden_override, _schema_override_hidden_values_for_discipline, camel_to_spaced_title_case, @@ -11,7 +11,7 @@ from django.db.models import Q, Count -from specifyweb.specify.migration_utils.SchemaWriter import revert_table_field_schema_config, revert_table_schema_config, update_table_field_schema_config_params, update_table_field_schema_config_with_defaults, update_table_schema_config_with_defaults +from specifyweb.specify.migration_utils.schema_writer import revert_table_field_schema_config, revert_table_schema_config, update_table_field_schema_config_params, update_table_field_schema_config_with_defaults, update_table_schema_config_with_defaults from specifyweb.specify.models import datamodel from specifyweb.specify.migration_utils.sp7_schemaconfig import ( MIGRATION_0002_TABLES, diff --git a/specifyweb/specify/migration_utils/SchemaReader.py b/specifyweb/specify/migration_utils/schema_reader.py similarity index 99% rename from specifyweb/specify/migration_utils/SchemaReader.py rename to specifyweb/specify/migration_utils/schema_reader.py index 150e4818a4d..aaacfe6eaf8 100644 --- a/specifyweb/specify/migration_utils/SchemaReader.py +++ b/specifyweb/specify/migration_utils/schema_reader.py @@ -12,7 +12,7 @@ from django.conf import settings from django.apps import apps as global_apps -from specifyweb.specify.migration_utils.SchemaWriter import FieldDefaults +from specifyweb.specify.migration_utils.schema_writer import FieldDefaults from specifyweb.specify.models import ( datamodel, diff --git a/specifyweb/specify/migration_utils/SchemaWriter.py b/specifyweb/specify/migration_utils/schema_writer.py similarity index 99% rename from specifyweb/specify/migration_utils/SchemaWriter.py rename to specifyweb/specify/migration_utils/schema_writer.py index c738cc956d6..44b4f242b58 100644 --- a/specifyweb/specify/migration_utils/SchemaWriter.py +++ b/specifyweb/specify/migration_utils/schema_writer.py @@ -7,7 +7,7 @@ from specifyweb.specify.models_utils.load_datamodel import FieldDoesNotExistError from specifyweb.specify.models import datamodel -from specifyweb.specify.migration_utils.SchemaReader import ( +from specifyweb.specify.migration_utils.schema_reader import ( FieldSchemaConfig, TableDefaults, bulk_create_splocaleitemstr_idempotent, diff --git a/specifyweb/specify/migrations/0002_geo.py b/specifyweb/specify/migrations/0002_geo.py index 290552aec1f..a23f82be669 100644 --- a/specifyweb/specify/migrations/0002_geo.py +++ b/specifyweb/specify/migrations/0002_geo.py @@ -9,7 +9,7 @@ protect_with_blockers ) from specifyweb.specify.migration_utils.sp7_schemaconfig import MIGRATION_0002_TABLES as SCHEMA_CONFIG_TABLES -from specifyweb.specify.migration_utils import MigrationHelpers as usc +from specifyweb.specify.migration_utils import migration_helpers as usc from specifyweb.specify.migration_utils.default_cots import ( create_cogtype_type_picklist, create_default_collection_types, diff --git a/specifyweb/specify/migrations/0003_cotype_picklist.py b/specifyweb/specify/migrations/0003_cotype_picklist.py index bfd53c082f0..2d915601df7 100644 --- a/specifyweb/specify/migrations/0003_cotype_picklist.py +++ b/specifyweb/specify/migrations/0003_cotype_picklist.py @@ -1,5 +1,5 @@ from django.db import migrations -from specifyweb.specify.migration_utils import MigrationHelpers as usc +from specifyweb.specify.migration_utils import migration_helpers as usc from specifyweb.specify.migration_utils.default_cots import create_cotype_picklist, COTYPE_PICKLIST_NAME def revert_cotype_picklist(apps): diff --git a/specifyweb/specify/migrations/0004_stratigraphy_age.py b/specifyweb/specify/migrations/0004_stratigraphy_age.py index 8634dee9a6c..76ec91ab8b4 100644 --- a/specifyweb/specify/migrations/0004_stratigraphy_age.py +++ b/specifyweb/specify/migrations/0004_stratigraphy_age.py @@ -4,7 +4,7 @@ import django.db.models.deletion import django.utils.timezone from specifyweb.specify.models import protect_with_blockers -from specifyweb.specify.migration_utils import MigrationHelpers as usc +from specifyweb.specify.migration_utils import migration_helpers as usc def revert_agetype_picklist(apps): Collection = apps.get_model('specify', 'Collection') diff --git a/specifyweb/specify/migrations/0007_schema_config_update.py b/specifyweb/specify/migrations/0007_schema_config_update.py index 8d54133ed7c..0dcbd329636 100644 --- a/specifyweb/specify/migrations/0007_schema_config_update.py +++ b/specifyweb/specify/migrations/0007_schema_config_update.py @@ -16,7 +16,7 @@ from django.db import migrations, models import django.db.models.deletion -from specifyweb.specify.migration_utils import MigrationHelpers as usc +from specifyweb.specify.migration_utils import migration_helpers as usc class Migration(migrations.Migration): dependencies = [ diff --git a/specifyweb/specify/migrations/0008_ageCitations_fix.py b/specifyweb/specify/migrations/0008_ageCitations_fix.py index f2db06eeaec..fc1606c1051 100644 --- a/specifyweb/specify/migrations/0008_ageCitations_fix.py +++ b/specifyweb/specify/migrations/0008_ageCitations_fix.py @@ -3,7 +3,7 @@ from django.db import migrations, models import specifyweb.specify.models -from specifyweb.specify.migration_utils import MigrationHelpers as usc +from specifyweb.specify.migration_utils import migration_helpers as usc class Migration(migrations.Migration): diff --git a/specifyweb/specify/migrations/0012_add_cojo_to_schema_config.py b/specifyweb/specify/migrations/0012_add_cojo_to_schema_config.py index 1470e88aa0d..61e5f04af83 100644 --- a/specifyweb/specify/migrations/0012_add_cojo_to_schema_config.py +++ b/specifyweb/specify/migrations/0012_add_cojo_to_schema_config.py @@ -2,7 +2,7 @@ This migration adds COG -> cojo and CO -> cojo to Schema Config. """ from django.db import migrations -from specifyweb.specify.migration_utils import MigrationHelpers as usc +from specifyweb.specify.migration_utils import migration_helpers as usc class Migration(migrations.Migration): diff --git a/specifyweb/specify/migrations/0013_collectionobjectgroup_parentcog.py b/specifyweb/specify/migrations/0013_collectionobjectgroup_parentcog.py index fbd8bc0f3f7..b38aecac955 100644 --- a/specifyweb/specify/migrations/0013_collectionobjectgroup_parentcog.py +++ b/specifyweb/specify/migrations/0013_collectionobjectgroup_parentcog.py @@ -2,7 +2,7 @@ from django.db import migrations, models import specifyweb.specify.models -from specifyweb.specify.migration_utils import MigrationHelpers as usc +from specifyweb.specify.migration_utils import migration_helpers as usc class Migration(migrations.Migration): diff --git a/specifyweb/specify/migrations/0015_add_version_to_ages.py b/specifyweb/specify/migrations/0015_add_version_to_ages.py index 06ac538e2ab..bca41f9c0e6 100644 --- a/specifyweb/specify/migrations/0015_add_version_to_ages.py +++ b/specifyweb/specify/migrations/0015_add_version_to_ages.py @@ -1,7 +1,7 @@ # Generated by Django 3.2.15 on 2024-12-03 18:59 from django.db import migrations, models -from specifyweb.specify.migration_utils import MigrationHelpers as usc +from specifyweb.specify.migration_utils import migration_helpers as usc class Migration(migrations.Migration): diff --git a/specifyweb/specify/migrations/0017_schemaconfig_fixes.py b/specifyweb/specify/migrations/0017_schemaconfig_fixes.py index ae33acb6cfe..764408cf258 100644 --- a/specifyweb/specify/migrations/0017_schemaconfig_fixes.py +++ b/specifyweb/specify/migrations/0017_schemaconfig_fixes.py @@ -1,7 +1,7 @@ # Generated by Django 3.2.15 on 2024-11-21 20:08 from django.db import migrations -from specifyweb.specify.migration_utils import MigrationHelpers as usc +from specifyweb.specify.migration_utils import migration_helpers as usc """ This migration fixes two bugs introduced in other migrations by the functions diff --git a/specifyweb/specify/migrations/0018_cot_catnum_schema.py b/specifyweb/specify/migrations/0018_cot_catnum_schema.py index 43b939ec04e..252b9c916c5 100644 --- a/specifyweb/specify/migrations/0018_cot_catnum_schema.py +++ b/specifyweb/specify/migrations/0018_cot_catnum_schema.py @@ -1,7 +1,7 @@ # Generated by Django 3.2.15 on 2024-11-21 20:08 from django.db import migrations -from specifyweb.specify.migration_utils import MigrationHelpers as usc +from specifyweb.specify.migration_utils import migration_helpers as usc class Migration(migrations.Migration): diff --git a/specifyweb/specify/migrations/0020_add_tectonicunit_to_pc_in_schema_config.py b/specifyweb/specify/migrations/0020_add_tectonicunit_to_pc_in_schema_config.py index 1675ce5efc9..15b97746045 100644 --- a/specifyweb/specify/migrations/0020_add_tectonicunit_to_pc_in_schema_config.py +++ b/specifyweb/specify/migrations/0020_add_tectonicunit_to_pc_in_schema_config.py @@ -2,7 +2,7 @@ This migration adds Tectonic Unit -> Paleo Context in the Schema Config. """ from django.db import migrations -from specifyweb.specify.migration_utils import MigrationHelpers as usc +from specifyweb.specify.migration_utils import migration_helpers as usc class Migration(migrations.Migration): diff --git a/specifyweb/specify/migrations/0021_update_hidden_geo_tables.py b/specifyweb/specify/migrations/0021_update_hidden_geo_tables.py index 00d319d304c..a3d3ec0e0ed 100644 --- a/specifyweb/specify/migrations/0021_update_hidden_geo_tables.py +++ b/specifyweb/specify/migrations/0021_update_hidden_geo_tables.py @@ -3,7 +3,7 @@ """ from django.db import migrations -from specifyweb.specify.migration_utils import MigrationHelpers as usc +from specifyweb.specify.migration_utils import migration_helpers as usc from specifyweb.specify.migration_utils.sp7_schemaconfig import MIGRATION_0021_FIELDS as SCHEMA_CONFIG_MOD_TABLE_FIELDS from specifyweb.specify.models_utils.model_extras import GEOLOGY_DISCIPLINES, PALEO_DISCIPLINES diff --git a/specifyweb/specify/migrations/0023_update_schema_config_text.py b/specifyweb/specify/migrations/0023_update_schema_config_text.py index 0fceab64c20..f39ce2da439 100644 --- a/specifyweb/specify/migrations/0023_update_schema_config_text.py +++ b/specifyweb/specify/migrations/0023_update_schema_config_text.py @@ -3,7 +3,7 @@ """ from django.db import migrations -from specifyweb.specify.migration_utils import MigrationHelpers as usc +from specifyweb.specify.migration_utils import migration_helpers as usc class Migration(migrations.Migration): dependencies = [ diff --git a/specifyweb/specify/migrations/0024_add_uniqueIdentifier_storage.py b/specifyweb/specify/migrations/0024_add_uniqueIdentifier_storage.py index 1798371c8c2..6c13d3756f8 100644 --- a/specifyweb/specify/migrations/0024_add_uniqueIdentifier_storage.py +++ b/specifyweb/specify/migrations/0024_add_uniqueIdentifier_storage.py @@ -1,6 +1,6 @@ from django.db import migrations, models from specifyweb.backend.businessrules.uniqueness_rules import DEFAULT_UNIQUENESS_RULES -from specifyweb.specify.migration_utils import MigrationHelpers as usc +from specifyweb.specify.migration_utils import migration_helpers as usc class Migration(migrations.Migration): diff --git a/specifyweb/specify/migrations/0027_CO_children.py b/specifyweb/specify/migrations/0027_CO_children.py index f42fd56e5ed..fd9ab5eb6cb 100644 --- a/specifyweb/specify/migrations/0027_CO_children.py +++ b/specifyweb/specify/migrations/0027_CO_children.py @@ -2,7 +2,7 @@ from django.apps import apps as specify_apps from django.db import migrations, models import django.db.models.deletion -from specifyweb.specify.migration_utils import MigrationHelpers as usc +from specifyweb.specify.migration_utils import migration_helpers as usc class Migration(migrations.Migration): diff --git a/specifyweb/specify/migrations/0029_remove_collectionobject_parentco.py b/specifyweb/specify/migrations/0029_remove_collectionobject_parentco.py index a258a71bd81..497e40f3e99 100644 --- a/specifyweb/specify/migrations/0029_remove_collectionobject_parentco.py +++ b/specifyweb/specify/migrations/0029_remove_collectionobject_parentco.py @@ -3,7 +3,7 @@ from django.db import migrations, models import django.db.models.deletion -from specifyweb.specify.migration_utils import MigrationHelpers as usc +from specifyweb.specify.migration_utils import migration_helpers as usc class Migration(migrations.Migration): dependencies = [ diff --git a/specifyweb/specify/migrations/0032_add_quantities_gift.py b/specifyweb/specify/migrations/0032_add_quantities_gift.py index 1a20f5a4977..5e779710a1f 100644 --- a/specifyweb/specify/migrations/0032_add_quantities_gift.py +++ b/specifyweb/specify/migrations/0032_add_quantities_gift.py @@ -3,7 +3,7 @@ from django.db import migrations, models from django.apps import apps as specify_apps -from specifyweb.specify.migration_utils import MigrationHelpers as usc +from specifyweb.specify.migration_utils import migration_helpers as usc class Migration(migrations.Migration): diff --git a/specifyweb/specify/migrations/0033_update_paleo_desc.py b/specifyweb/specify/migrations/0033_update_paleo_desc.py index 68a891e288c..240e77e3a9b 100644 --- a/specifyweb/specify/migrations/0033_update_paleo_desc.py +++ b/specifyweb/specify/migrations/0033_update_paleo_desc.py @@ -1,5 +1,5 @@ from django.db import migrations -from specifyweb.specify.migration_utils import MigrationHelpers as usc +from specifyweb.specify.migration_utils import migration_helpers as usc def schemaconfig_fixes(apps, schema_editor): usc.update_paleo_desc(apps) diff --git a/specifyweb/specify/migrations/0034_accession_date_fields.py b/specifyweb/specify/migrations/0034_accession_date_fields.py index 0a3941c24db..5bdf85ef066 100644 --- a/specifyweb/specify/migrations/0034_accession_date_fields.py +++ b/specifyweb/specify/migrations/0034_accession_date_fields.py @@ -1,7 +1,7 @@ # Generated by Django 4.2.18 on 2025-06-12 23:10 from django.db import migrations, models -from specifyweb.specify.migration_utils import MigrationHelpers as usc +from specifyweb.specify.migration_utils import migration_helpers as usc def apply_migration(apps, schema_editor): usc.update_accession_date_fields(apps) diff --git a/specifyweb/specify/migrations/0035_version_required.py b/specifyweb/specify/migrations/0035_version_required.py index 36f219ca0f3..df805f2faa1 100644 --- a/specifyweb/specify/migrations/0035_version_required.py +++ b/specifyweb/specify/migrations/0035_version_required.py @@ -1,7 +1,7 @@ # Generated by Django 3.2.15 on 2025-04-02 15:28 from django.db import migrations, models -from specifyweb.specify.migration_utils import MigrationHelpers as usc +from specifyweb.specify.migration_utils import migration_helpers as usc def apply_migration(apps, schema_editor): usc.update_version_required(apps) diff --git a/specifyweb/specify/migrations/0039_agent_fields_for_loan_and_gift.py b/specifyweb/specify/migrations/0039_agent_fields_for_loan_and_gift.py index 9f0b475e7d9..22825b4361e 100644 --- a/specifyweb/specify/migrations/0039_agent_fields_for_loan_and_gift.py +++ b/specifyweb/specify/migrations/0039_agent_fields_for_loan_and_gift.py @@ -4,7 +4,7 @@ from django.db import migrations, models from specifyweb.specify.models import protect_with_blockers -from specifyweb.specify.migration_utils import MigrationHelpers as usc +from specifyweb.specify.migration_utils import migration_helpers as usc def consolidated_0038_forward(apps, schema_editor): usc.update_loan_and_gift_agent_fields(apps) diff --git a/specifyweb/specify/migrations/0040_components.py b/specifyweb/specify/migrations/0040_components.py index c012fb8a00e..aa693ec3537 100644 --- a/specifyweb/specify/migrations/0040_components.py +++ b/specifyweb/specify/migrations/0040_components.py @@ -4,7 +4,7 @@ import django.db.models.deletion import django.utils.timezone import specifyweb.specify.models -from specifyweb.specify.migration_utils import MigrationHelpers as usc +from specifyweb.specify.migration_utils import migration_helpers as usc from specifyweb.specify.models import protect_with_blockers class Migration(migrations.Migration): diff --git a/specifyweb/specify/migrations/0042_discipline_type_picklist.py b/specifyweb/specify/migrations/0042_discipline_type_picklist.py index f9dfc815cf9..0c18ee81c0a 100644 --- a/specifyweb/specify/migrations/0042_discipline_type_picklist.py +++ b/specifyweb/specify/migrations/0042_discipline_type_picklist.py @@ -1,5 +1,5 @@ from django.db import migrations -from specifyweb.specify.migration_utils import MigrationHelpers as usc +from specifyweb.specify.migration_utils import migration_helpers as usc class Migration(migrations.Migration): dependencies = [ From e9df6683e88f619f3c87eff27685a2be68c974d9 Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Mon, 15 Jun 2026 14:53:25 +0200 Subject: [PATCH 067/113] Refactor: Avoid circular imports --- .../specify/migration_utils/migration_helpers.py | 10 +++++++++- specifyweb/specify/migration_utils/schema_reader.py | 10 +++++++--- specifyweb/specify/migration_utils/schema_writer.py | 7 ------- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/specifyweb/specify/migration_utils/migration_helpers.py b/specifyweb/specify/migration_utils/migration_helpers.py index 9164d1bc31d..a25eef83bc4 100644 --- a/specifyweb/specify/migration_utils/migration_helpers.py +++ b/specifyweb/specify/migration_utils/migration_helpers.py @@ -3,6 +3,7 @@ _schema_override_hidden_values_for_discipline, camel_to_spaced_title_case, datamodel_type_to_schematype, + find_missing_schema_config_fields, uncapitilize ) @@ -11,7 +12,14 @@ from django.db.models import Q, Count -from specifyweb.specify.migration_utils.schema_writer import revert_table_field_schema_config, revert_table_schema_config, update_table_field_schema_config_params, update_table_field_schema_config_with_defaults, update_table_schema_config_with_defaults +from specifyweb.specify.migration_utils.schema_writer import ( + create_missing_schema_config_fields, + revert_table_field_schema_config, + revert_table_schema_config, + update_table_field_schema_config_params, + update_table_field_schema_config_with_defaults, + update_table_schema_config_with_defaults, +) from specifyweb.specify.models import datamodel from specifyweb.specify.migration_utils.sp7_schemaconfig import ( MIGRATION_0002_TABLES, diff --git a/specifyweb/specify/migration_utils/schema_reader.py b/specifyweb/specify/migration_utils/schema_reader.py index aaacfe6eaf8..34992a30c98 100644 --- a/specifyweb/specify/migration_utils/schema_reader.py +++ b/specifyweb/specify/migration_utils/schema_reader.py @@ -12,8 +12,6 @@ from django.conf import settings from django.apps import apps as global_apps -from specifyweb.specify.migration_utils.schema_writer import FieldDefaults - from specifyweb.specify.models import ( datamodel, ) @@ -213,10 +211,16 @@ def bulk_create_splocaleitemstr_idempotent(Splocaleitemstr, rows: list[dict]) -> return total_created +class FieldDefaults(TypedDict): + name: NotRequired[str] + desc: NotRequired[str] + ishidden: NotRequired[bool] + isrequired: NotRequired[bool] + picklistname: NotRequired[str] class TableDefaults(TypedDict): name: NotRequired[str] desc: NotRequired[str] - items: "NotRequired[dict[str, FieldDefaults]]" + items: NotRequired[dict[str, FieldDefaults]] def find_missing_schema_config_fields(discipline_id: int, apps=global_apps): Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') diff --git a/specifyweb/specify/migration_utils/schema_writer.py b/specifyweb/specify/migration_utils/schema_writer.py index 44b4f242b58..600d0228221 100644 --- a/specifyweb/specify/migration_utils/schema_writer.py +++ b/specifyweb/specify/migration_utils/schema_writer.py @@ -27,13 +27,6 @@ class TableSchemaConfig(NamedTuple): description: str = "TBD" language: str = "en" -class FieldDefaults(TypedDict): - name: NotRequired[str] - desc: NotRequired[str] - ishidden: NotRequired[bool] - isrequired: NotRequired[bool] - picklistname: NotRequired[str] - def update_table_schema_config_with_defaults( table_name, discipline_id: int, From 1c65df5d7329a8100617ba25c68b98b0543e2595 Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Mon, 15 Jun 2026 14:56:02 +0200 Subject: [PATCH 068/113] Fix: Normalize revert filters to match the forward writes --- .../specify/migration_utils/schema_writer.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/specifyweb/specify/migration_utils/schema_writer.py b/specifyweb/specify/migration_utils/schema_writer.py index 600d0228221..9c81a92ceeb 100644 --- a/specifyweb/specify/migration_utils/schema_writer.py +++ b/specifyweb/specify/migration_utils/schema_writer.py @@ -130,7 +130,10 @@ def revert_table_schema_config(table_name, apps=global_apps): Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - containers = Splocalecontainer.objects.filter(name=table_name) + containers = Splocalecontainer.objects.filter( + name=table_name.lower(), + schematype=0, + ) items = Splocalecontaineritem.objects.filter(container__in=containers) Splocaleitemstr.objects.filter( Q(itemname__in=items) | @@ -277,8 +280,14 @@ def revert_table_field_schema_config(table_name, field_name, apps=global_apps): Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - containers = Splocalecontainer.objects.filter(name=table_name) - items = Splocalecontaineritem.objects.filter(container__in=containers, name=field_name) + containers = Splocalecontainer.objects.filter( + name=table_name.lower(), + schematype=0, + ) + items = Splocalecontaineritem.objects.filter( + container__in=containers, + name__iexact=field_name, + ) Splocaleitemstr.objects.filter( Q(itemname__in=items) | Q(itemdesc__in=items) From 8e711360bcaa73308acbb7eb2d691f3e9bbda4a1 Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Mon, 15 Jun 2026 16:18:28 +0200 Subject: [PATCH 069/113] Refactor: Compartimentalize migration helpers --- .../migration_utils/migration_helpers.py | 1404 +---------------- .../0002_schema_config_update_helper.py | 22 + .../0003_cotype_picklist_helper.py | 53 + .../0004_stratigraphy_age_helper.py | 62 + .../0007_schema_config_update_helper.py | 134 ++ .../0008_schema_config_update_helper.py | 22 + .../0012_add_cojo_to_schema_config_helper.py | 21 + ..._collectionobjectgroup_parentcog_helper.py | 33 + .../0015_add_version_to_ages_helper.py | 23 + .../0017_schemaconfig_fixes_helper.py | 100 ++ .../0018_cot_catnum_schema_helper.py | 60 + ...tonicunit_to_pc_in_schema_config_helper.py | 20 + .../0021_update_hidden_geo_tables_helper.py | 51 + .../0023_update_schema_config_text_helper.py | 184 +++ ...024_add_uniqueIdentifier_storage_helper.py | 22 + .../0027_CO_children_helper.py | 80 + ...remove_collectionobject_parentco_helper.py | 130 ++ .../0032_add_quantities_gift_helper.py | 80 + .../0033_update_paleo_desc_helper.py | 18 + .../0035_version_required_helper.py | 31 + ...9_agent_fields_for_loan_and_gift_helper.py | 24 + .../0040_components_helper.py | 135 ++ .../0042_discipline_type_picklist_helper.py | 65 + ...helper0034_accession_date_fields_helper.py | 81 + .../specify/migration_utils/schema_writer.py | 5 +- 25 files changed, 1456 insertions(+), 1404 deletions(-) create mode 100644 specifyweb/specify/migration_utils/migration_helpers/0002_schema_config_update_helper.py create mode 100644 specifyweb/specify/migration_utils/migration_helpers/0003_cotype_picklist_helper.py create mode 100644 specifyweb/specify/migration_utils/migration_helpers/0004_stratigraphy_age_helper.py create mode 100644 specifyweb/specify/migration_utils/migration_helpers/0007_schema_config_update_helper.py create mode 100644 specifyweb/specify/migration_utils/migration_helpers/0008_schema_config_update_helper.py create mode 100644 specifyweb/specify/migration_utils/migration_helpers/0012_add_cojo_to_schema_config_helper.py create mode 100644 specifyweb/specify/migration_utils/migration_helpers/0013_collectionobjectgroup_parentcog_helper.py create mode 100644 specifyweb/specify/migration_utils/migration_helpers/0015_add_version_to_ages_helper.py create mode 100644 specifyweb/specify/migration_utils/migration_helpers/0017_schemaconfig_fixes_helper.py create mode 100644 specifyweb/specify/migration_utils/migration_helpers/0018_cot_catnum_schema_helper.py create mode 100644 specifyweb/specify/migration_utils/migration_helpers/0020_add_tectonicunit_to_pc_in_schema_config_helper.py create mode 100644 specifyweb/specify/migration_utils/migration_helpers/0021_update_hidden_geo_tables_helper.py create mode 100644 specifyweb/specify/migration_utils/migration_helpers/0023_update_schema_config_text_helper.py create mode 100644 specifyweb/specify/migration_utils/migration_helpers/0024_add_uniqueIdentifier_storage_helper.py create mode 100644 specifyweb/specify/migration_utils/migration_helpers/0027_CO_children_helper.py create mode 100644 specifyweb/specify/migration_utils/migration_helpers/0029_remove_collectionobject_parentco_helper.py create mode 100644 specifyweb/specify/migration_utils/migration_helpers/0032_add_quantities_gift_helper.py create mode 100644 specifyweb/specify/migration_utils/migration_helpers/0033_update_paleo_desc_helper.py create mode 100644 specifyweb/specify/migration_utils/migration_helpers/0035_version_required_helper.py create mode 100644 specifyweb/specify/migration_utils/migration_helpers/0039_agent_fields_for_loan_and_gift_helper.py create mode 100644 specifyweb/specify/migration_utils/migration_helpers/0040_components_helper.py create mode 100644 specifyweb/specify/migration_utils/migration_helpers/0042_discipline_type_picklist_helper.py create mode 100644 specifyweb/specify/migration_utils/migration_helpers/_helper0034_accession_date_fields_helper.py diff --git a/specifyweb/specify/migration_utils/migration_helpers.py b/specifyweb/specify/migration_utils/migration_helpers.py index a25eef83bc4..1a84f519df6 100644 --- a/specifyweb/specify/migration_utils/migration_helpers.py +++ b/specifyweb/specify/migration_utils/migration_helpers.py @@ -1,63 +1,9 @@ -from specifyweb.specify.migration_utils.schema_reader import ( - _fields_without_explicit_hidden_override, - _schema_override_hidden_values_for_discipline, - camel_to_spaced_title_case, - datamodel_type_to_schematype, - find_missing_schema_config_fields, - uncapitilize -) - -import logging - - -from django.db.models import Q, Count - from specifyweb.specify.migration_utils.schema_writer import ( - create_missing_schema_config_fields, - revert_table_field_schema_config, - revert_table_schema_config, - update_table_field_schema_config_params, - update_table_field_schema_config_with_defaults, update_table_schema_config_with_defaults, ) from specifyweb.specify.models import datamodel -from specifyweb.specify.migration_utils.sp7_schemaconfig import ( - MIGRATION_0002_TABLES, - MIGRATION_0004_FIELDS, - MIGRATION_0004_TABLES, - MIGRATION_0007_FIELDS, - MIGRATION_0008_FIELDS, - MIGRATION_0012_FIELDS, - MIGRATION_0013_FIELDS, - MIGRATION_0020_FIELDS, - MIGRATION_0021_FIELDS, - MIGRATION_0023_FIELDS, - MIGRATION_0023_FIELDS_BIS, - MIGRATION_0024_FIELDS, - MIGRATION_0027_FIELDS, - MIGRATION_0027_UPDATE_FIELDS, - MIGRATION_0029_FIELDS, - MIGRATION_0029_UPDATE_FIELDS, - MIGRATION_0032_FIELDS, - MIGRATION_0032_UPDATE_FIELDS, - MIGRATION_0033_TABLES, - MIGRATION_0034_FIELDS, - MIGRATION_0034_UPDATE_FIELDS, - MIGRATION_0035_FIELDS, - MIGRATION_0038_FIELDS, - MIGRATION_0040_TABLES, - MIGRATION_0040_FIELDS, - MIGRATION_0040_UPDATE_FIELDS, - MIGRATION_0040_HIDDEN_FIELDS, -) -from specifyweb.specify.models_utils.model_extras import GEOLOGY_DISCIPLINES, PALEO_DISCIPLINES - -logger = logging.getLogger(__name__) - -HIDDEN_FIELDS = [ - "timestampcreated", "timestampmodified", "version", "createdbyagent", "modifiedbyagent" -] +#TODO: This is not used, can we remove? # ############################################################################## # Migration schema config helper functions # ############################################################################## @@ -68,1351 +14,3 @@ def update_all_table_schema_config_with_defaults(apps): for table in datamodel.tables: update_table_schema_config_with_defaults(table.name, discipline.id, None, apps) -# ########################################## -# Used in 0002_schema_config_update.py -# ########################################## - -DEFAULT_COG_TYPES = [ - 'Discrete', - 'Consolidated', - 'Drill Core', -] - -def create_geo_table_schema_config_with_defaults(apps): - Discipline = apps.get_model('specify', 'Discipline') - for discipline in Discipline.objects.all(): - for table, desc in MIGRATION_0002_TABLES: - update_table_schema_config_with_defaults(table, discipline.id, desc, apps) - -# ########################################## -# Used in 0003_cotype_picklist.py -# ########################################## - -COT_PICKLIST_NAME = 'CollectionObjectType' -COT_FIELD_NAME = 'collectionObjectType' -COT_TEXT = 'Collection Object Type' - -# FEAT: Replace this implementation with -# update_table_field_schema_config_with_defaults -def create_cotype_splocalecontaineritem(apps): - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') - - # Create a Splocalecontaineritem record for each CollectionObject Splocalecontainer - # NOTE: Each discipline has its own CollectionObject Splocalecontainer - for container in Splocalecontainer.objects.filter(name='collectionobject', schematype=0): - container_item_attrs = { - "name": COT_FIELD_NAME, - "container": container - } - container_item = Splocalecontaineritem.objects.filter(**container_item_attrs).order_by("id").first() - if container_item is None: - resolved_item = Splocalecontaineritem.objects.create( - **container_item_attrs, - picklistname=COT_PICKLIST_NAME, - type="ManyToOne", - isrequired=True - ) - else: - resolved_item = container_item - - field_label_attrs = { - "language": "en", - "itemname":resolved_item - } - - field_label = Splocaleitemstr.objects.filter(**field_label_attrs).order_by("id").first() - - if field_label is None: - Splocaleitemstr.objects.create(**field_label_attrs, text=COT_TEXT) - - field_desc_attrs = { - "language": "en", - "itemdesc":resolved_item - } - - field_desc = Splocaleitemstr.objects.filter(**field_desc_attrs).order_by("id").first() - - if field_desc is None: - Splocaleitemstr.objects.create(**field_desc_attrs, text=COT_TEXT) - -# ########################################## -# Used in 0004_stratigraphy_age.py -# ########################################## - -AGETYPE_PICKLIST_NAME = 'AgeType' -DEFAULT_AGE_TYPES = [ - 'Sedimentation', - 'Metamorphism', - 'Erosion', - 'Diagenetic', -] - -def create_agetype_picklist(apps): - Collection = apps.get_model('specify', 'Collection') - Picklist = apps.get_model('specify', 'Picklist') - PicklistItem = apps.get_model('specify', 'Picklistitem') - - for collection in Collection.objects.all(): - age_type_picklist, created = Picklist.objects.get_or_create( - name=AGETYPE_PICKLIST_NAME, - type=0, - collection_id=collection.id, - defaults={ - "issystem": False, - "readonly": False, - "sizelimit": -1, - "sorttype": 1, - } - ) - if created: - for age_type in DEFAULT_AGE_TYPES: - PicklistItem.objects.get_or_create( - title=age_type, - value=age_type, - picklist=age_type_picklist - ) - -def create_strat_table_schema_config_with_defaults(apps): - Discipline = apps.get_model('specify', 'Discipline') - for discipline in Discipline.objects.all(): - for table, desc in MIGRATION_0004_TABLES: # NOTE: lots of Nones, getting skips - update_table_schema_config_with_defaults(table, discipline.id, desc, apps) - - for table, fields in MIGRATION_0004_FIELDS.items(): - for field in fields: - update_table_field_schema_config_with_defaults(table, discipline.id, field, apps) - -def revert_strat_table_schema_config_with_defaults(apps): - for table, _ in MIGRATION_0004_TABLES: - revert_table_schema_config(table, apps) - for table, fields in MIGRATION_0004_FIELDS.items(): - for field in fields: - revert_table_field_schema_config(table, field, apps) - -# ########################################## -# Used in 0007_schema_config_update.py -# ########################################## - -COG_PICKLIST_NAME = 'COGTypes' -COGTYPE_FIELD_NAME = 'cogType' -SYSTEM_COGTYPE_PICKLIST_NAME = "SystemCOGTypes" - -def update_cog_type_fields(apps): - Discipline = apps.get_model('specify', 'Discipline') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') - - # Revert COG -> children before adding to avoid duplicates - revert_table_field_schema_config('CollectionObjectGroup', 'children', apps) - # Add StorageTreeDef -> institution and COG -> children - for discipline in Discipline.objects.all(): - for table, fields in MIGRATION_0007_FIELDS.items(): - for field in fields: - update_table_field_schema_config_with_defaults(table, discipline.id, field, apps) - - # Remove COG -> cojo - revert_table_field_schema_config('CollectionObjectGroup', 'cojo', apps) - - # Remove duplicate CollectionObject -> collectionObjectType - container_items = Splocalecontaineritem.objects.filter( - name="collectionObjectType", - picklistname=None, - container__name="collectionobject", - ) - for container_item in container_items: - Splocaleitemstr.objects.filter(itemname=container_item).delete() - Splocaleitemstr.objects.filter(itemdesc=container_item).delete() - container_items.delete() - -# NOTE: The reverse function will not re-add the duplicate CO -> coType or COG -> cojo as its unnecessary -def revert_cog_type_fields(apps): - # Remove StorageTreeDef -> institution and COG -> children - for table, fields in MIGRATION_0007_FIELDS.items(): - for field in fields: - revert_table_field_schema_config(table, field, apps) - -def create_cogtype_picklist(apps): - Collection = apps.get_model('specify', 'Collection') - Picklist = apps.get_model('specify', 'Picklist') - - # Create a cogtype picklist for each collection - for collection in Collection.objects.all(): - Picklist.objects.update_or_create( - collection=collection, - name=COG_PICKLIST_NAME, - defaults={ - "type": 1, - "tablename": "collectionobjectgrouptype", - "issystem": True, - "readonly": True, - "sizelimit": -1, - "sorttype": 1, - "formatter": "CollectionObjectGroupType", - }, - ) - -def revert_cogtype_picklist(apps): - Picklist = apps.get_model('specify', 'Picklist') - - Picklist.objects.filter(name=COG_PICKLIST_NAME).delete() - - -# Updates COG -> cogtype to use the type 1 picklist created above -def update_cogtype_splocalecontaineritem(apps): - Splocalecontaineritem = apps.get_model("specify", "Splocalecontaineritem") - - Splocalecontaineritem.objects.filter( - container__name="collectionobjectgroup", - container__schematype=0, - name=COGTYPE_FIELD_NAME, - ).update(picklistname=COG_PICKLIST_NAME, type="ManyToOne", isrequired=True) - - -def revert_cogtype_splocalecontaineritem(apps): - Splocalecontaineritem = apps.get_model("specify", "Splocalecontaineritem") - - Splocalecontaineritem.objects.filter( - container__name="collectionobjectgroup", - container__schematype=0, - name=COGTYPE_FIELD_NAME, - ).update(picklistname=None, type=None, isrequired=None) - - -def update_systemcogtypes_picklist(apps): - Picklist = apps.get_model('specify', 'Picklist') - - Picklist.objects.filter(name='Default Collection Object Group Types').update( - name=SYSTEM_COGTYPE_PICKLIST_NAME, - type=0, - issystem=True, - readonly=True, - sizelimit=3, - tablename=None - ) - -def revert_systemcogtypes_picklist(apps): - Picklist = apps.get_model('specify', 'Picklist') - - # revert only changes the name and not the other attributes as those were incorrect - Picklist.objects.filter(name=SYSTEM_COGTYPE_PICKLIST_NAME).update( - name='Default Collection Object Group Types', - ) - - -# Updates cogtype -> type to use the Default COGType picklist (Drill Core, Discrete, Consolidated) -def update_cogtype_type_splocalecontaineritem(apps): - Splocalecontaineritem = apps.get_model("specify", "Splocalecontaineritem") - - Splocalecontaineritem.objects.filter( - container__name="collectionobjectgrouptype", - container__schematype=0, - name="type", - ).update(picklistname=SYSTEM_COGTYPE_PICKLIST_NAME, isrequired=True) - - -def revert_cogtype_type_splocalecontaineritem(apps): - Splocalecontaineritem = apps.get_model("specify", "Splocalecontaineritem") - - Splocalecontaineritem.objects.filter( - container__name="collectionobjectgrouptype", - container__schematype=0, - name="type", - ).update(picklistname=None, isrequired=None) - -# ########################################## -# Used in 0008_schema_config_update.py -# ########################################## - -def update_relative_age_fields(apps): - Discipline = apps.get_model('specify', 'Discipline') - - # Add absoluteAgeCitation -> absoluteAge & Add relativeAgeCitation -> relativeAge - for discipline in Discipline.objects.all(): - for table, fields in MIGRATION_0008_FIELDS.items(): - for field in fields: - update_table_field_schema_config_with_defaults(table, discipline.id, field, apps) - -def revert_relative_age_fields(apps): - # Remove absoluteAgeCitation -> absoluteAge and relativeAgeCitation -> relativeAge - for table, fields in MIGRATION_0008_FIELDS.items(): - for field in fields: - revert_table_field_schema_config(table, field, apps) - -# ########################################## -# Used in 0012_add_cojo_to_schema_config.py -# ########################################## - -def add_cojo_to_schema_config(apps): - Discipline = apps.get_model('specify', 'Discipline') - for discipline in Discipline.objects.all(): - for table, fields in MIGRATION_0012_FIELDS.items(): - for field in fields: - update_table_field_schema_config_with_defaults( - table, discipline.id, field, apps) - - -def remove_cojo_from_schema_config(apps): - for table, fields in MIGRATION_0012_FIELDS.items(): - for field in fields: - revert_table_field_schema_config(table, field, apps) - - -# ########################################## -# Used in 0013_collectionobjectgroup_parentcog.py -# ########################################## - -def update_cog_schema_config(apps): - revert_table_field_schema_config( - 'CollectionObjectGroup', 'parentCojo', apps) - revert_table_field_schema_config( - 'CollectionObjectGroup', 'parentCog', apps) - - Discipline = apps.get_model('specify', 'Discipline') - for discipline in Discipline.objects.all(): - for table, fields in MIGRATION_0013_FIELDS.items(): - for field in fields: - update_table_field_schema_config_with_defaults( - table, discipline.id, field, apps) - - -def revert_update_cog_schema_config(apps): - for table, fields in MIGRATION_0013_FIELDS.items(): - for field in fields: - revert_table_field_schema_config(table, field, apps) - - Discipline = apps.get_model('specify', 'Discipline') - for discipline in Discipline.objects.all(): - update_table_field_schema_config_with_defaults( - 'CollectionObjectGroup', discipline.id, 'parentCojo', apps) - -# ########################################## -# Used in 0015_add_version_to_ages.py -# ########################################## - -def update_age_schema_config(apps): - # Revert before adding to avoid duplicates - # BUG: This will delete people's potentially modified Schema Config items - # If we want to avoid duplicates, we should check the creation code and - # prevent duplicates being created there - # revert_update_age_schema_config(apps) - - Discipline = apps.get_model('specify', 'Discipline') - for discipline in Discipline.objects.all(): - update_table_field_schema_config_with_defaults('AbsoluteAge', discipline.id, 'version', apps) - update_table_field_schema_config_with_defaults('RelativeAge', discipline.id, 'version', apps) - -def revert_update_age_schema_config(apps): - revert_table_field_schema_config('AbsoluteAge', 'version', apps) - revert_table_field_schema_config('RelativeAge', 'version', apps) - -# ########################################## -# Used in 0017_schemaconfig_fixes.py -# ########################################## - -CONTAINER_MIGRATIONS = [MIGRATION_0002_TABLES, MIGRATION_0004_TABLES] - -CONTAINER_ITEM_MIGRATIONS = [ - MIGRATION_0004_FIELDS, - MIGRATION_0007_FIELDS, - MIGRATION_0008_FIELDS, - MIGRATION_0012_FIELDS, - MIGRATION_0013_FIELDS, -] - -def fix_table_captions(apps): - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') - - for migration in CONTAINER_MIGRATIONS: - for table_name, table_desc in migration: - table = datamodel.get_table(table_name) - - # BUG: The splocalecontainer related tables can still exist in the - # database, and this will result in skipping any operation if the - # table/field is removed, renamed, etc. - if table is None: - logger.warning(f"Table does not exist in latest state of the datamodel, skipping Schema Config update for: {table_name}") - continue - containers = Splocalecontainer.objects.filter( - name=table_name.lower(), schematype=0) - - # If needed, correct the label of the table in the schema config - if table_desc is not None: - Splocaleitemstr.objects.filter( - containername__in=containers, text=table_desc - ).update(text=camel_to_spaced_title_case(uncapitilize(table.name))) - - # Update the types for the fields in the table - items = Splocalecontaineritem.objects.filter( - container__in=containers) - for item in items: - datamodel_field = table.get_field(item.name) - if not datamodel_field: - continue - - item.type = datamodel_type_to_schematype( - datamodel_field.type) if datamodel_field.is_relationship else datamodel_field.type - item.isrequired = datamodel_field.required if item.isrequired is None else item.isrequired - - item.save() - - -def fix_item_types(apps): - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - - for migration in CONTAINER_ITEM_MIGRATIONS: - for table_name, fields in migration.items(): - table = datamodel.get_table(table_name) - # BUG: The splocalecontainer related tables can still exist in the - # database, and this will result in skipping any operation if the - # table/field is removed, renamed, etc. - if table is None: - logger.warning(f"Table does not exist in latest state of the datamodel, skipping Schema Config entry for: {table_name}") - continue - items = Splocalecontaineritem.objects.filter( - container__name=table_name.lower(), container__schematype=0, name__in=fields) - - for item in items: - datamodel_field = table.get_field(item.name) - if not datamodel_field: - continue - - item.type = datamodel_type_to_schematype( - datamodel_field.type) if datamodel_field.is_relationship else datamodel_field.type - item.isrequired = datamodel_field.required if item.isrequired is None else item.isrequired - - item.save() - - -def schemaconfig_fixes(apps, schema_editor=None): - fix_table_captions(apps) - fix_item_types(apps) - -# ########################################## -# Used in 0018_cot_catnum_schema.py -# ########################################## - -def add_cot_catnum_to_schema(apps, schema_editor=None): - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') - - CollectionObjectType_Table = datamodel.get_table_strict( - 'collectionobjecttype') - catalognumber_format_field = CollectionObjectType_Table.get_field_strict( - 'catalogNumberFormatName') - - for container in Splocalecontainer.objects.filter(name='collectionobjecttype', schematype=0): - schema_item, created = Splocalecontaineritem.objects.get_or_create( - name=catalognumber_format_field.name, type=catalognumber_format_field.type, container=container) - if created: - schema_item.version = 0 - - schema_item.isrequired = ( - catalognumber_format_field.required - if schema_item.isrequired is None - else schema_item.isrequired - ) - - schema_item.save() - - schema_name = camel_to_spaced_title_case( - catalognumber_format_field.name) - Splocaleitemstr.objects.get_or_create( - language='en', text=schema_name, itemname=schema_item) - Splocaleitemstr.objects.get_or_create( - language='en', text=schema_name, itemdesc=schema_item) - -def remove_cot_catnum_from_schema(apps, schema_editor=None): - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') - - CollectionObjectType_Table = datamodel.get_table_strict( - 'collectionobjecttype') - catalognumber_format_field = CollectionObjectType_Table.get_field_strict( - 'catalogNumberFormatName') - - containers = Splocalecontainer.objects.filter( - name='collectionobjecttype', schematype=0) - items = Splocalecontaineritem.objects.filter( - name='catalogNumberFormatName', container__in=containers) - - schema_name = camel_to_spaced_title_case(catalognumber_format_field.name) - filters = Q(language='en', text=schema_name) & ( - Q(itemname__in=items) | Q(itemdesc__in=items)) - locale_strings = Splocaleitemstr.objects.filter(filters) - - locale_strings.delete() - items.delete() - -# ########################################## -# Used in 0020_add_tectonicunit_to_pc_in_schema_config.py -# ########################################## - -def add_tectonicunit_to_pc_in_schema_config(apps): - Discipline = apps.get_model('specify', 'Discipline') - for discipline in Discipline.objects.all(): - for table, fields in MIGRATION_0020_FIELDS.items(): - for field in fields: - update_table_field_schema_config_with_defaults( - table, discipline.id, field, apps) - -def remove_tectonicunit_from_pc_schema_config(apps): - for table, fields in MIGRATION_0020_FIELDS.items(): - for field in fields: - revert_table_field_schema_config(table, field, apps) - -# ########################################## -# Used in 0021_update_hidden_geo_tables.py -# ########################################## - -def fix_hidden_geo_prop(apps, schema_editor=None): - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - Discipline = apps.get_model('specify', 'Discipline') - - excluded_disciplines = PALEO_DISCIPLINES | GEOLOGY_DISCIPLINES - - filtered_disciplines = Discipline.objects.exclude(type__in=excluded_disciplines) - - for discipline in filtered_disciplines: - for table, fields in MIGRATION_0021_FIELDS.items(): - containers = Splocalecontainer.objects.filter( - name=table.lower(), - discipline_id=discipline.id, - ) - for container in containers: - # BUG: What if the user wants the field unhidden? - Splocalecontaineritem.objects.filter( - container=container, - name__in=tuple(map(lambda field_name: field_name.lower(), fields)) - ).update(ishidden=True) - -def reverse_fix_hidden_geo_prop(apps, schema_editor=None): - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - Discipline = apps.get_model('specify', 'Discipline') - - excluded_disciplines = PALEO_DISCIPLINES | GEOLOGY_DISCIPLINES - - filtered_disciplines = Discipline.objects.exclude(type__in=excluded_disciplines) - - for discipline in filtered_disciplines: - for table, fields in MIGRATION_0021_FIELDS.items(): - containers = Splocalecontainer.objects.filter( - name=table.lower(), - discipline_id=discipline.id, - ) - for container in containers: - # BUG: What if the user wants the field hidden? - Splocalecontaineritem.objects.filter( - container=container, - name__in=tuple(map(lambda field_name: field_name.lower(), fields)) - ).update(ishidden=False) - -# ########################################## -# Used in 0023_update_schema_config_text.py -# ########################################## - -def update_schema_config_field_desc(apps, schema_editor=None): - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') - - for table, fields in MIGRATION_0023_FIELDS.items(): - #i.e: Collection Object - containers = Splocalecontainer.objects.filter( - name=table.lower(), - ) - - for container in containers: - for field_name, new_name, new_desc in fields: - #i.e: COType - items = Splocalecontaineritem.objects.filter( - container=container, - name__iexact=field_name - ) - - for item in items: - localized_items_desc = Splocaleitemstr.objects.filter(itemdesc_id=item.id).first() - localized_items_name = Splocaleitemstr.objects.filter(itemname_id=item.id).first() - - if localized_items_desc is None or localized_items_name is None: - continue - - localized_items_desc.text = new_desc - localized_items_desc.save() - - localized_items_name.text = new_name - localized_items_name.save() - -def update_hidden_prop(apps, schema_editor=None): - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') - Discipline = apps.get_model('specify', 'Discipline') - discipline_types_by_id = dict(Discipline.objects.values_list("id", "type")) - - for table, fields in MIGRATION_0023_FIELDS_BIS.items(): - field_names = [field_name.lower() for field_name in fields] - field_name_set = set(field_names) - containers = Splocalecontainer.objects.filter( - name=table.lower(), - schematype=0 - ) - for container in containers: - discipline_type = discipline_types_by_id.get(container.discipline_id, "") - explicit_hidden_overrides = { - field_name: ishidden - for field_name, ishidden in _schema_override_hidden_values_for_discipline( - discipline_type - ).get(table.lower(), {}).items() - if field_name in field_name_set - } - explicit_fields_to_hide = [ - field_name - for field_name, ishidden in explicit_hidden_overrides.items() - if ishidden - ] - explicit_fields_to_show = [ - field_name - for field_name, ishidden in explicit_hidden_overrides.items() - if not ishidden - ] - - if explicit_fields_to_hide: - Splocalecontaineritem.objects.filter( - container=container, - ishidden=False, - name__in=explicit_fields_to_hide, - ).update(ishidden=True) - - if explicit_fields_to_show: - Splocalecontaineritem.objects.filter( - container=container, - ishidden=True, - name__in=explicit_fields_to_show, - ).update(ishidden=False) - - fields_to_hide = _fields_without_explicit_hidden_override( - table, - field_names, - discipline_type, - ) - if not fields_to_hide: - continue - - items_updated = Splocalecontaineritem.objects.filter( - container=container, - ishidden=False, - name__in=fields_to_hide - ).update(ishidden=True) - if items_updated > 0: - logger.info(f"Hid {items_updated} items for table {table} and container {container.id}") - - duplicates = ( - Splocalecontaineritem.objects.values("container", "name") - .annotate(count=Count("id")) - .filter(count__gt=1) - ) - for duplicate in duplicates: - container_id = duplicate['container'] - name = duplicate['name'] - duplicate_items = Splocalecontaineritem.objects.filter(container_id=container_id, name=name) - item_to_keep = duplicate_items.first() - items_to_delete = duplicate_items.exclude(id=item_to_keep.id) - - Splocaleitemstr.objects.filter(itemdesc_id__in=items_to_delete).update(itemdesc_id=item_to_keep.id) - Splocaleitemstr.objects.filter(itemname_id__in=items_to_delete).update(itemname_id=item_to_keep.id) - items_to_delete.delete() - -def reverse_update_hidden_prop(apps, schema_editor=None): - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - Discipline = apps.get_model('specify', 'Discipline') - discipline_types_by_id = dict(Discipline.objects.values_list("id", "type")) - - for table, fields in MIGRATION_0023_FIELDS_BIS.items(): - field_names = [field_name.lower() for field_name in fields] - containers = Splocalecontainer.objects.filter( - name=table.lower(), - ) - for container in containers: - discipline_type = discipline_types_by_id.get(container.discipline_id, "") - fields_to_unhide = _fields_without_explicit_hidden_override( - table, - field_names, - discipline_type, - ) - if not fields_to_unhide: - continue - - items = Splocalecontaineritem.objects.filter( - container=container, - name__in=fields_to_unhide - ) - logger.info(f"Reverting {items.count()} items for table {table} and container {container.id}") - items.update(ishidden=False) - -def reverse_update_schema_config_field_desc(apps, schema_editor=None): - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') - - for table, fields in MIGRATION_0023_FIELDS.items(): - containers = Splocalecontainer.objects.filter( - name=table.lower(), - ) - - for container in containers: - for field_name, new_name, new_desc in fields: - items = Splocalecontaineritem.objects.filter( - container=container, - name=field_name.lower() - ) - - for item in items: - localized_items_desc = Splocaleitemstr.objects.filter(itemdesc_id=item.id).first() - localized_items_name = Splocaleitemstr.objects.filter(itemname_id=item.id).first() - - if localized_items_desc is None or localized_items_name is None: - continue - - localized_items_desc.text = item.name - localized_items_desc.save() - - localized_items_name.text = item.name - localized_items_name.save() - -# ########################################## -# Used in 0024_add_uniqueIdentifier_storage.py -# ########################################## - -def update_storage_unique_id_fields(apps): - Discipline = apps.get_model('specify', 'Discipline') - - # Add uniqueIdentifier -> storage - for discipline in Discipline.objects.all(): - for table, fields in MIGRATION_0024_FIELDS.items(): - for field in fields: - update_table_field_schema_config_with_defaults(table, discipline.id, field, apps) - -def revert_storage_unique_id_fields(apps): - # Remove uniqueIdentifier -> storage - for table, fields in MIGRATION_0024_FIELDS.items(): - for field in fields: - revert_table_field_schema_config(table, field, apps) - -# ########################################## -# Used in 0027_CO_children.py -# ########################################## - -def update_co_children_fields(apps): - def update_discipline_fields(apps): - Discipline = apps.get_model('specify', 'Discipline') - - for discipline in Discipline.objects.all(): - for table, fields in MIGRATION_0027_FIELDS.items(): - for field in fields: - update_table_field_schema_config_with_defaults(table, discipline.id, field, apps) - - def update_schema_config_field_desc(apps): - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') - - for table, fields in MIGRATION_0027_UPDATE_FIELDS.items(): - #i.e: Collection Object - containers = Splocalecontainer.objects.filter( - name=table.lower(), - ) - - for container in containers: - for field_name, new_name, new_desc in fields: - #i.e: COType - items = Splocalecontaineritem.objects.filter( - container=container, - name__iexact=field_name - ) - - for item in items: - localized_items_desc = Splocaleitemstr.objects.filter(itemdesc_id=item.id).first() - localized_items_name = Splocaleitemstr.objects.filter(itemname_id=item.id).first() - - if localized_items_desc is None or localized_items_name is None: - continue - - localized_items_desc.text = new_desc - localized_items_desc.save() - - localized_items_name.text = new_name - localized_items_name.save() - - update_discipline_fields(apps) - update_schema_config_field_desc(apps) - -def revert_co_children_fields(apps): - def revert_update_fields(apps): - for table, fields in MIGRATION_0027_FIELDS.items(): - for field in fields: - revert_table_field_schema_config(table, field, apps) - - def revert_update_schema_field(apps): - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - - for table, fields in MIGRATION_0027_UPDATE_FIELDS.items(): - containers = Splocalecontainer.objects.filter( - name=table.lower(), - ) - for container in containers: - for field_name in fields: - items = Splocalecontaineritem.objects.filter( - container=container, - name=field_name - ) - - for item in items: - item.ishidden = False - item.save() - - revert_update_fields(apps) - revert_update_schema_field(apps) - -# ########################################## -# Used in 0029_remove_collectionobject_parentco.py -# ########################################## - -def remove_collectionobject_parentco(apps): - def update_fields(apps): - Discipline = apps.get_model('specify', 'Discipline') - - for discipline in Discipline.objects.all(): - for table, fields in MIGRATION_0029_FIELDS.items(): - for field in fields: - update_table_field_schema_config_with_defaults(table, discipline.id, field, apps) - - def update_schema_config_field_desc(apps): - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') - - for table, fields in MIGRATION_0029_UPDATE_FIELDS.items(): - #i.e: Collection Object - containers = Splocalecontainer.objects.filter( - name=table.lower(), - ) - - for container in containers: - for field_name, new_name, new_desc in fields: - #i.e: COType - items = Splocalecontaineritem.objects.filter( - container=container, - name__iexact=field_name - ) - - for item in items: - localized_items_desc = Splocaleitemstr.objects.filter(itemdesc_id=item.id).first() - localized_items_name = Splocaleitemstr.objects.filter(itemname_id=item.id).first() - - if localized_items_desc is None or localized_items_name is None: - continue - - localized_items_desc.text = new_desc - localized_items_desc.save() - - localized_items_name.text = new_name - localized_items_name.save() - - def hide_co_component(apps): - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - Discipline = apps.get_model('specify', 'Discipline') - - disciplines = Discipline.objects.all() - - for discipline in disciplines: - for table, fields in MIGRATION_0029_UPDATE_FIELDS.items(): - containers = Splocalecontainer.objects.filter( - name=table.lower(), - discipline_id=discipline.id, - ) - for container in containers: - for field_name, _, _ in fields: - items = Splocalecontaineritem.objects.filter( - container=container, - name=field_name.lower() - ) - - for item in items: - item.ishidden = True - item.save() - - update_fields(apps) - update_schema_config_field_desc(apps) - hide_co_component(apps) - -def revert_remove_collectionobject_parentco(apps): - def revert_update_fields(apps): - for table, fields in MIGRATION_0029_FIELDS.items(): - for field in fields: - revert_table_field_schema_config(table, field, apps) - - def revert_update_schema_field(apps): - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - - for table, fields in MIGRATION_0029_UPDATE_FIELDS.items(): - containers = Splocalecontainer.objects.filter( - name=table.lower(), - ) - for container in containers: - for field_name in fields: - items = Splocalecontaineritem.objects.filter( - container=container, - name=field_name - ) - - for item in items: - item.ishidden = False - item.save() - - def reverse_hide_co_component(apps): - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - Discipline = apps.get_model('specify', 'Discipline') - - disciplines = Discipline.objects.all() - - for discipline in disciplines: - for table, fields in MIGRATION_0029_UPDATE_FIELDS.items(): - containers = Splocalecontainer.objects.filter( - name=table.lower(), - discipline_id=discipline.id, - ) - for container in containers: - for field_name, _, _ in fields: - items = Splocalecontaineritem.objects.filter( - container=container, - name=field_name.lower() - ) - - for item in items: - item.ishidden = False - item.save() - - revert_update_fields(apps) - revert_update_schema_field(apps) - reverse_hide_co_component(apps) - -# ########################################## -# Used in 0032_add_quantities_gift.py -# ########################################## - -def add_quantities_gift(apps): - def update_fields(apps): - Discipline = apps.get_model('specify', 'Discipline') - - for discipline in Discipline.objects.all(): - for table, fields in MIGRATION_0032_FIELDS.items(): - for field in fields: - update_table_field_schema_config_with_defaults(table, discipline.id, field, apps) - - def update_schema_config_field_desc(apps): - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') - - for table, fields in MIGRATION_0032_UPDATE_FIELDS.items(): - #i.e: Collection Object - containers = Splocalecontainer.objects.filter( - name=table.lower(), - ) - - for container in containers: - for field_name, new_name, new_desc in fields: - #i.e: COType - items = Splocalecontaineritem.objects.filter( - container=container, - name__iexact=field_name - ) - - for item in items: - localized_items_desc = Splocaleitemstr.objects.filter(itemdesc_id=item.id).first() - localized_items_name = Splocaleitemstr.objects.filter(itemname_id=item.id).first() - - if localized_items_desc is None or localized_items_name is None: - continue - - localized_items_desc.text = new_desc - localized_items_desc.save() - - localized_items_name.text = new_name - localized_items_name.save() - - update_fields(apps) - update_schema_config_field_desc(apps) - -def revert_add_quantities_gift(apps): - def revert_update_fields(apps): - for table, fields in MIGRATION_0032_FIELDS.items(): - for field in fields: - revert_table_field_schema_config(table, field, apps) - - def revert_update_schema_field(apps): - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - - for table, fields in MIGRATION_0032_UPDATE_FIELDS.items(): - containers = Splocalecontainer.objects.filter( - name=table.lower(), - ) - for container in containers: - for field_name in fields: - items = Splocalecontaineritem.objects.filter( - container=container, - name=field_name - ) - - for item in items: - item.ishidden = False - item.save() - - revert_update_fields(apps) - revert_update_schema_field(apps) - -# ########################################## -# Used in 0033_update_paleo_desc.py -# ########################################## - -def update_paleo_desc(apps): - def fix_table_description(apps): - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') - - for table_name, table_desc in MIGRATION_0033_TABLES: - containers = Splocalecontainer.objects.filter(name=table_name.lower(), schematype=0) - Splocaleitemstr.objects.filter(containerdesc__in=containers).update(text=table_desc) - - fix_table_description(apps) - -# ########################################## -# Used in 0034_accession_date_fields.py -# ########################################## - -def update_accession_date_fields(apps): - def update_0034_fields(apps): - """ - Update table-field schema entries for plain field names - (e.g., MIGRATION_0034_FIELDS). - """ - Discipline = apps.get_model('specify', 'Discipline') - for discipline in Discipline.objects.all(): - for table, fields in MIGRATION_0034_FIELDS.items(): - for field_name in fields: - update_table_field_schema_config_with_defaults(table, discipline.id, field_name, apps) - - def update_0034_schema_config_field_desc(apps): - """ - Update field descriptions and display names using MIGRATION_0034_UPDATE_FIELDS - (tuple: (fieldName, newLabel, newDesc)). - """ - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') - - for table, fields in MIGRATION_0034_UPDATE_FIELDS.items(): - containers = Splocalecontainer.objects.filter(name=table.lower()) - for container in containers: - for (field_name, new_name, new_desc) in fields: - items = Splocalecontaineritem.objects.filter( - container=container, - name__iexact=field_name - ) - for item in items: - item.ishidden = True - item.save() - desc_str = Splocaleitemstr.objects.filter(itemdesc_id=item.id).first() - name_str = Splocaleitemstr.objects.filter(itemname_id=item.id).first() - if desc_str is not None: - desc_str.text = new_desc - desc_str.save() - if name_str is not None: - name_str.text = new_name - name_str.save() - - update_0034_fields(apps) - update_0034_schema_config_field_desc(apps) - -def revert_update_accession_date_fields(apps): - def revert_0034_fields(apps): - """ - Revert table-field entries for plain field names. - """ - for table, fields in MIGRATION_0034_FIELDS.items(): - for field_name in fields: - revert_table_field_schema_config(table, field_name, apps) - - def revert_0034_schema_config_field_desc(apps): - """ - Revert the field name/description updates. - """ - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - - for table, fields in MIGRATION_0034_UPDATE_FIELDS.items(): - containers = Splocalecontainer.objects.filter(name=table.lower()) - for container in containers: - for (field_name, _, _) in fields: - items = Splocalecontaineritem.objects.filter( - container=container, - name__iexact=field_name - ) - # If needed, reset ishidden or revert text - - revert_0034_fields(apps) - revert_0034_schema_config_field_desc(apps) - -# ########################################## -# Used in 0035_version_required.py -# ########################################## - -def update_version_required(apps): - Discipline = apps.get_model('specify', 'Discipline') - updated_config_params = { - 'isrequired': False, - } - - # Update the schema config for each discipline with the version isHidden change - for discipline in Discipline.objects.all(): - for table, fields in MIGRATION_0035_FIELDS.items(): - for field in fields: - update_table_field_schema_config_params(table, discipline.id, field, updated_config_params, apps) - -def revert_version_required(apps): - Discipline = apps.get_model('specify', 'Discipline') - updated_config_params = { - 'isrequired': True, - } - - # Revert the schema config for each discipline with the version isHidden change - for discipline in Discipline.objects.all(): - for table, fields in MIGRATION_0035_FIELDS.items(): - for field in fields: - update_table_field_schema_config_params(table, discipline.id, field, updated_config_params, apps) - -# ########################################## -# Used in 0039_agent_fields_for_loan_and_gift.py -# ########################################## - -def update_loan_and_gift_agent_fields(apps): - Discipline = apps.get_model('specify', 'Discipline') - field_defaults = { - "ishidden": True - } - for discipline in Discipline.objects.all(): - for table, fields in MIGRATION_0038_FIELDS.items(): - for field_name in fields: - update_table_field_schema_config_with_defaults(table, discipline.id, field_name, apps, defaults=field_defaults) - -def revert_loan_and_gift_agent_fields(apps): - for table, fields in MIGRATION_0038_FIELDS.items(): - for field_name in fields: - revert_table_field_schema_config(table, field_name, apps) - -# ########################################## -# Used in 0040_components.py -# ########################################## - -def remove_componentparent_item(apps): - revert_table_field_schema_config("CollectionObject", "componentParent", apps) - -def remove_0029_schema_config_fields(apps, schema_editor=None): - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') - - FIELDS_TO_REMOVE = MIGRATION_0029_UPDATE_FIELDS - for table, fields in FIELDS_TO_REMOVE.items(): - items = Splocalecontaineritem.objects.filter( - container__name=table.lower(), - container__schematype=0, - # we only need the field name from the tuple of Schema Config information - name__in=list(map(lambda f: f[0].lower(), fields)) - ) - - # Delete field labels (captions) and descriptions (Splocaleitemstr) associated with the fields - Splocaleitemstr.objects.filter( - Q(itemdesc__in=items) | Q(itemname__in=items) - ).delete() - - items.delete() - -def create_table_schema_config_with_defaults(apps, schema_editor=None): - Discipline = apps.get_model('specify', 'Discipline') - for discipline in Discipline.objects.all(): - for table, desc in MIGRATION_0040_TABLES: - update_table_schema_config_with_defaults(table, discipline.id, desc, apps) - - for table, fields in MIGRATION_0040_FIELDS.items(): - for field in fields: - update_table_field_schema_config_with_defaults(table, discipline.id, field, apps) - -def update_schema_config_field_desc_for_components(apps, schema_editor=None): - Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') - - for table, fields in MIGRATION_0040_UPDATE_FIELDS.items(): - for field_name, new_name, new_desc in fields: - - Splocaleitemstr.objects.filter( - itemdesc__container__name=table.lower(), - itemdesc__container__schematype=0, - itemdesc__name=field_name.lower(), - language="en", - ).update(text=new_desc) - - Splocaleitemstr.objects.filter( - itemname__container__name=table.lower(), - itemname__container__schematype=0, - itemname__name=field_name.lower(), - language="en", - ).update(text=new_name) - -def update_hidden_prop_for_compoenents(apps, schema_editor=None): - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - - for table, fields in MIGRATION_0040_FIELDS.items(): - Splocalecontaineritem.objects.filter( - container__name=table.lower(), - container__schematype=0, - name__in=list(map(lambda f: f.lower(), fields)) - ).update(ishidden=True) - -def create_cotype_splocalecontaineritem_for_components(apps): - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - PICKLIST_NAME = 'CollectionObjectType' - FIELD_NAME = 'type' - - # Create a Splocalecontaineritem record for each Component Splocalecontainer - # NOTE: Each discipline has its own Component Splocalecontainer - Splocalecontaineritem.objects.filter( - container__name='component', - container__schematype=0, - name=FIELD_NAME - ).update( - picklistname=PICKLIST_NAME, - isrequired=True, - type='ManyToOne', - ) - -def hide_component_fields(apps, schema_editor=None): - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - - for table, fields in MIGRATION_0040_HIDDEN_FIELDS.items(): - Splocalecontaineritem.objects.filter( - container__name=table.lower(), - container__schematype=0, - name__in=list(map(lambda f: f.lower(), fields)) - ).update(ishidden=True) - -def restore_0029_schema_config_fields(apps, schema_editor=None): - Discipline = apps.get_model('specify', 'Discipline') - FIELDS_TO_REMOVE = MIGRATION_0029_UPDATE_FIELDS - for discipline in Discipline.objects.all(): - for table, fields in FIELDS_TO_REMOVE.items(): - for field_name, _, _ in fields: - update_table_field_schema_config_with_defaults(table, discipline.id, field_name, apps) - -def revert_table_schema_config_with_defaults(apps, schema_editor=None): - for table, _ in MIGRATION_0040_TABLES: - revert_table_schema_config(table, apps) - for table, fields in MIGRATION_0040_FIELDS.items(): - for field in fields: - revert_table_field_schema_config(table, field, apps) - -def reverse_hide_component_fields(apps, schema_editor=None): - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - Discipline = apps.get_model('specify', 'Discipline') - - for discipline in Discipline.objects.all(): - for table, fields in MIGRATION_0040_HIDDEN_FIELDS.items(): - containers = Splocalecontainer.objects.filter( - name=table.lower(), - discipline_id=discipline.id, - ) - for container in containers: - for field_name in fields: - items = Splocalecontaineritem.objects.filter( - container=container, - name=field_name.lower() - ) - items.update(ishidden=False) - -# ########################################## -# Used in 0042_discipline_type_picklist.py -# ########################################## - -from specifyweb.backend.context.app_resource import DISCIPLINE_NAMES - -DISCIPLINE_TYPE_PICKLIST_NAME = 'DisciplineType' - -def create_discipline_type_picklist(apps): - Collection = apps.get_model('specify', 'Collection') - Picklist = apps.get_model('specify', 'Picklist') - Picklistitem = apps.get_model('specify', 'Picklistitem') - - # Create a discipline type picklist for each collection - for collection in Collection.objects.all(): - picklist, created = Picklist.objects.get_or_create( - name=DISCIPLINE_TYPE_PICKLIST_NAME, - type=0, - collection=collection, - defaults={ - "issystem": True, - "readonly": True, - "sizelimit": -1, - "sorttype": 1, - } - ) - # If the picklist doesn't exist, create a new one - if created: - ordinal = 1 - items = [] - for value, title in DISCIPLINE_NAMES.items(): - items.append( - Picklistitem( - picklist=picklist, - ordinal=ordinal, - value=value, - title=title, - ) - ) - ordinal += 1 - Picklistitem.objects.bulk_create(items) - -def revert_discipline_type_picklist(apps): - Picklist = apps.get_model('specify', 'Picklist') - - Picklist.objects.filter(name=DISCIPLINE_TYPE_PICKLIST_NAME).delete() - -def update_discipline_type_splocalecontaineritem(apps): - Splocalecontaineritem = apps.get_model("specify", "Splocalecontaineritem") - - Splocalecontaineritem.objects.filter( - container__name="discipline", - container__schematype=0, - name="type", - ).update(picklistname=DISCIPLINE_TYPE_PICKLIST_NAME, isrequired=True) - -def revert_discipline_type_splocalecontaineritem(apps): - Splocalecontaineritem = apps.get_model("specify", "Splocalecontaineritem") - - Splocalecontaineritem.objects.filter( - container__name="discipline", - container__schematype=0, - name="type", - ).update(picklistname=None, isrequired=None) diff --git a/specifyweb/specify/migration_utils/migration_helpers/0002_schema_config_update_helper.py b/specifyweb/specify/migration_utils/migration_helpers/0002_schema_config_update_helper.py new file mode 100644 index 00000000000..8fadc98dc2c --- /dev/null +++ b/specifyweb/specify/migration_utils/migration_helpers/0002_schema_config_update_helper.py @@ -0,0 +1,22 @@ +from specifyweb.specify.migration_utils.sp7_schemaconfig import ( + MIGRATION_0002_TABLES, +) + +# ########################################## +# Used in 0002_schema_config_update.py +# ########################################## + +from specifyweb.specify.migration_utils.schema_writer import update_table_schema_config_with_defaults + + +DEFAULT_COG_TYPES = [ + 'Discrete', + 'Consolidated', + 'Drill Core', +] + +def create_geo_table_schema_config_with_defaults(apps): + Discipline = apps.get_model('specify', 'Discipline') + for discipline in Discipline.objects.all(): + for table, desc in MIGRATION_0002_TABLES: + update_table_schema_config_with_defaults(table, discipline.id, desc, apps) diff --git a/specifyweb/specify/migration_utils/migration_helpers/0003_cotype_picklist_helper.py b/specifyweb/specify/migration_utils/migration_helpers/0003_cotype_picklist_helper.py new file mode 100644 index 00000000000..401c4e26eb9 --- /dev/null +++ b/specifyweb/specify/migration_utils/migration_helpers/0003_cotype_picklist_helper.py @@ -0,0 +1,53 @@ + +# ########################################## +# Used in 0003_cotype_picklist.py +# ########################################## + +COT_PICKLIST_NAME = 'CollectionObjectType' +COT_FIELD_NAME = 'collectionObjectType' +COT_TEXT = 'Collection Object Type' + +# FEAT: Replace this implementation with +# update_table_field_schema_config_with_defaults +def create_cotype_splocalecontaineritem(apps): + Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') + Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') + Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') + + # Create a Splocalecontaineritem record for each CollectionObject Splocalecontainer + # NOTE: Each discipline has its own CollectionObject Splocalecontainer + for container in Splocalecontainer.objects.filter(name='collectionobject', schematype=0): + container_item_attrs = { + "name": COT_FIELD_NAME, + "container": container + } + container_item = Splocalecontaineritem.objects.filter(**container_item_attrs).order_by("id").first() + if container_item is None: + resolved_item = Splocalecontaineritem.objects.create( + **container_item_attrs, + picklistname=COT_PICKLIST_NAME, + type="ManyToOne", + isrequired=True + ) + else: + resolved_item = container_item + + field_label_attrs = { + "language": "en", + "itemname":resolved_item + } + + field_label = Splocaleitemstr.objects.filter(**field_label_attrs).order_by("id").first() + + if field_label is None: + Splocaleitemstr.objects.create(**field_label_attrs, text=COT_TEXT) + + field_desc_attrs = { + "language": "en", + "itemdesc":resolved_item + } + + field_desc = Splocaleitemstr.objects.filter(**field_desc_attrs).order_by("id").first() + + if field_desc is None: + Splocaleitemstr.objects.create(**field_desc_attrs, text=COT_TEXT) \ No newline at end of file diff --git a/specifyweb/specify/migration_utils/migration_helpers/0004_stratigraphy_age_helper.py b/specifyweb/specify/migration_utils/migration_helpers/0004_stratigraphy_age_helper.py new file mode 100644 index 00000000000..79f154130c2 --- /dev/null +++ b/specifyweb/specify/migration_utils/migration_helpers/0004_stratigraphy_age_helper.py @@ -0,0 +1,62 @@ + +from specifyweb.specify.migration_utils.sp7_schemaconfig import ( + MIGRATION_0004_FIELDS, + MIGRATION_0004_TABLES, +) + +# ########################################## +# Used in 0004_stratigraphy_age.py +# ########################################## + +from specifyweb.specify.migration_utils.schema_writer import revert_table_field_schema_config, revert_table_schema_config, update_table_field_schema_config_with_defaults, update_table_schema_config_with_defaults + + +AGETYPE_PICKLIST_NAME = 'AgeType' +DEFAULT_AGE_TYPES = [ + 'Sedimentation', + 'Metamorphism', + 'Erosion', + 'Diagenetic', +] + +def create_agetype_picklist(apps): + Collection = apps.get_model('specify', 'Collection') + Picklist = apps.get_model('specify', 'Picklist') + PicklistItem = apps.get_model('specify', 'Picklistitem') + + for collection in Collection.objects.all(): + age_type_picklist, created = Picklist.objects.get_or_create( + name=AGETYPE_PICKLIST_NAME, + type=0, + collection_id=collection.id, + defaults={ + "issystem": False, + "readonly": False, + "sizelimit": -1, + "sorttype": 1, + } + ) + if created: + for age_type in DEFAULT_AGE_TYPES: + PicklistItem.objects.get_or_create( + title=age_type, + value=age_type, + picklist=age_type_picklist + ) + +def create_strat_table_schema_config_with_defaults(apps): + Discipline = apps.get_model('specify', 'Discipline') + for discipline in Discipline.objects.all(): + for table, desc in MIGRATION_0004_TABLES: # NOTE: lots of Nones, getting skips + update_table_schema_config_with_defaults(table, discipline.id, desc, apps) + + for table, fields in MIGRATION_0004_FIELDS.items(): + for field in fields: + update_table_field_schema_config_with_defaults(table, discipline.id, field, apps) + +def revert_strat_table_schema_config_with_defaults(apps): + for table, _ in MIGRATION_0004_TABLES: + revert_table_schema_config(table, apps) + for table, fields in MIGRATION_0004_FIELDS.items(): + for field in fields: + revert_table_field_schema_config(table, field, apps) \ No newline at end of file diff --git a/specifyweb/specify/migration_utils/migration_helpers/0007_schema_config_update_helper.py b/specifyweb/specify/migration_utils/migration_helpers/0007_schema_config_update_helper.py new file mode 100644 index 00000000000..93e2f9d53e4 --- /dev/null +++ b/specifyweb/specify/migration_utils/migration_helpers/0007_schema_config_update_helper.py @@ -0,0 +1,134 @@ +from specifyweb.specify.migration_utils.schema_writer import revert_table_field_schema_config, update_table_field_schema_config_with_defaults +from specifyweb.specify.migration_utils.sp7_schemaconfig import ( + MIGRATION_0007_FIELDS, +) + +# ########################################## +# Used in 0007_schema_config_update.py +# ########################################## + +COG_PICKLIST_NAME = 'COGTypes' +COGTYPE_FIELD_NAME = 'cogType' +SYSTEM_COGTYPE_PICKLIST_NAME = "SystemCOGTypes" + +def update_cog_type_fields(apps): + Discipline = apps.get_model('specify', 'Discipline') + Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') + Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') + + # Revert COG -> children before adding to avoid duplicates + revert_table_field_schema_config('CollectionObjectGroup', 'children', apps) + # Add StorageTreeDef -> institution and COG -> children + for discipline in Discipline.objects.all(): + for table, fields in MIGRATION_0007_FIELDS.items(): + for field in fields: + update_table_field_schema_config_with_defaults(table, discipline.id, field, apps) + + # Remove COG -> cojo + revert_table_field_schema_config('CollectionObjectGroup', 'cojo', apps) + + # Remove duplicate CollectionObject -> collectionObjectType + container_items = Splocalecontaineritem.objects.filter( + name="collectionObjectType", + picklistname=None, + container__name="collectionobject", + ) + for container_item in container_items: + Splocaleitemstr.objects.filter(itemname=container_item).delete() + Splocaleitemstr.objects.filter(itemdesc=container_item).delete() + container_items.delete() + +# NOTE: The reverse function will not re-add the duplicate CO -> coType or COG -> cojo as its unnecessary +def revert_cog_type_fields(apps): + # Remove StorageTreeDef -> institution and COG -> children + for table, fields in MIGRATION_0007_FIELDS.items(): + for field in fields: + revert_table_field_schema_config(table, field, apps) + +def create_cogtype_picklist(apps): + Collection = apps.get_model('specify', 'Collection') + Picklist = apps.get_model('specify', 'Picklist') + + # Create a cogtype picklist for each collection + for collection in Collection.objects.all(): + Picklist.objects.update_or_create( + collection=collection, + name=COG_PICKLIST_NAME, + defaults={ + "type": 1, + "tablename": "collectionobjectgrouptype", + "issystem": True, + "readonly": True, + "sizelimit": -1, + "sorttype": 1, + "formatter": "CollectionObjectGroupType", + }, + ) + +def revert_cogtype_picklist(apps): + Picklist = apps.get_model('specify', 'Picklist') + + Picklist.objects.filter(name=COG_PICKLIST_NAME).delete() + + +# Updates COG -> cogtype to use the type 1 picklist created above +def update_cogtype_splocalecontaineritem(apps): + Splocalecontaineritem = apps.get_model("specify", "Splocalecontaineritem") + + Splocalecontaineritem.objects.filter( + container__name="collectionobjectgroup", + container__schematype=0, + name=COGTYPE_FIELD_NAME, + ).update(picklistname=COG_PICKLIST_NAME, type="ManyToOne", isrequired=True) + + +def revert_cogtype_splocalecontaineritem(apps): + Splocalecontaineritem = apps.get_model("specify", "Splocalecontaineritem") + + Splocalecontaineritem.objects.filter( + container__name="collectionobjectgroup", + container__schematype=0, + name=COGTYPE_FIELD_NAME, + ).update(picklistname=None, type=None, isrequired=None) + + +def update_systemcogtypes_picklist(apps): + Picklist = apps.get_model('specify', 'Picklist') + + Picklist.objects.filter(name='Default Collection Object Group Types').update( + name=SYSTEM_COGTYPE_PICKLIST_NAME, + type=0, + issystem=True, + readonly=True, + sizelimit=3, + tablename=None + ) + +def revert_systemcogtypes_picklist(apps): + Picklist = apps.get_model('specify', 'Picklist') + + # revert only changes the name and not the other attributes as those were incorrect + Picklist.objects.filter(name=SYSTEM_COGTYPE_PICKLIST_NAME).update( + name='Default Collection Object Group Types', + ) + + +# Updates cogtype -> type to use the Default COGType picklist (Drill Core, Discrete, Consolidated) +def update_cogtype_type_splocalecontaineritem(apps): + Splocalecontaineritem = apps.get_model("specify", "Splocalecontaineritem") + + Splocalecontaineritem.objects.filter( + container__name="collectionobjectgrouptype", + container__schematype=0, + name="type", + ).update(picklistname=SYSTEM_COGTYPE_PICKLIST_NAME, isrequired=True) + + +def revert_cogtype_type_splocalecontaineritem(apps): + Splocalecontaineritem = apps.get_model("specify", "Splocalecontaineritem") + + Splocalecontaineritem.objects.filter( + container__name="collectionobjectgrouptype", + container__schematype=0, + name="type", + ).update(picklistname=None, isrequired=None) \ No newline at end of file diff --git a/specifyweb/specify/migration_utils/migration_helpers/0008_schema_config_update_helper.py b/specifyweb/specify/migration_utils/migration_helpers/0008_schema_config_update_helper.py new file mode 100644 index 00000000000..eba74b0873e --- /dev/null +++ b/specifyweb/specify/migration_utils/migration_helpers/0008_schema_config_update_helper.py @@ -0,0 +1,22 @@ +from specifyweb.specify.migration_utils.schema_writer import revert_table_field_schema_config, update_table_field_schema_config_with_defaults +from specifyweb.specify.migration_utils.sp7_schemaconfig import ( + MIGRATION_0008_FIELDS, +) +# ########################################## +# Used in 0008_schema_config_update.py +# ########################################## + +def update_relative_age_fields(apps): + Discipline = apps.get_model('specify', 'Discipline') + + # Add absoluteAgeCitation -> absoluteAge & Add relativeAgeCitation -> relativeAge + for discipline in Discipline.objects.all(): + for table, fields in MIGRATION_0008_FIELDS.items(): + for field in fields: + update_table_field_schema_config_with_defaults(table, discipline.id, field, apps) + +def revert_relative_age_fields(apps): + # Remove absoluteAgeCitation -> absoluteAge and relativeAgeCitation -> relativeAge + for table, fields in MIGRATION_0008_FIELDS.items(): + for field in fields: + revert_table_field_schema_config(table, field, apps) \ No newline at end of file diff --git a/specifyweb/specify/migration_utils/migration_helpers/0012_add_cojo_to_schema_config_helper.py b/specifyweb/specify/migration_utils/migration_helpers/0012_add_cojo_to_schema_config_helper.py new file mode 100644 index 00000000000..3ecf105a7e6 --- /dev/null +++ b/specifyweb/specify/migration_utils/migration_helpers/0012_add_cojo_to_schema_config_helper.py @@ -0,0 +1,21 @@ +from specifyweb.specify.migration_utils.schema_writer import revert_table_field_schema_config, update_table_field_schema_config_with_defaults +from specifyweb.specify.migration_utils.sp7_schemaconfig import ( + MIGRATION_0012_FIELDS, +) +# ########################################## +# Used in 0012_add_cojo_to_schema_config.py +# ########################################## + +def add_cojo_to_schema_config(apps): + Discipline = apps.get_model('specify', 'Discipline') + for discipline in Discipline.objects.all(): + for table, fields in MIGRATION_0012_FIELDS.items(): + for field in fields: + update_table_field_schema_config_with_defaults( + table, discipline.id, field, apps) + + +def remove_cojo_from_schema_config(apps): + for table, fields in MIGRATION_0012_FIELDS.items(): + for field in fields: + revert_table_field_schema_config(table, field, apps) \ No newline at end of file diff --git a/specifyweb/specify/migration_utils/migration_helpers/0013_collectionobjectgroup_parentcog_helper.py b/specifyweb/specify/migration_utils/migration_helpers/0013_collectionobjectgroup_parentcog_helper.py new file mode 100644 index 00000000000..88c02aba98b --- /dev/null +++ b/specifyweb/specify/migration_utils/migration_helpers/0013_collectionobjectgroup_parentcog_helper.py @@ -0,0 +1,33 @@ +from specifyweb.specify.migration_utils.sp7_schemaconfig import ( + MIGRATION_0013_FIELDS, +) +# ########################################## +# Used in 0013_collectionobjectgroup_parentcog.py +# ########################################## + +from specifyweb.specify.migration_utils.schema_writer import revert_table_field_schema_config, update_table_field_schema_config_with_defaults + + +def update_cog_schema_config(apps): + revert_table_field_schema_config( + 'CollectionObjectGroup', 'parentCojo', apps) + revert_table_field_schema_config( + 'CollectionObjectGroup', 'parentCog', apps) + + Discipline = apps.get_model('specify', 'Discipline') + for discipline in Discipline.objects.all(): + for table, fields in MIGRATION_0013_FIELDS.items(): + for field in fields: + update_table_field_schema_config_with_defaults( + table, discipline.id, field, apps) + + +def revert_update_cog_schema_config(apps): + for table, fields in MIGRATION_0013_FIELDS.items(): + for field in fields: + revert_table_field_schema_config(table, field, apps) + + Discipline = apps.get_model('specify', 'Discipline') + for discipline in Discipline.objects.all(): + update_table_field_schema_config_with_defaults( + 'CollectionObjectGroup', discipline.id, 'parentCojo', apps) \ No newline at end of file diff --git a/specifyweb/specify/migration_utils/migration_helpers/0015_add_version_to_ages_helper.py b/specifyweb/specify/migration_utils/migration_helpers/0015_add_version_to_ages_helper.py new file mode 100644 index 00000000000..768512e14f4 --- /dev/null +++ b/specifyweb/specify/migration_utils/migration_helpers/0015_add_version_to_ages_helper.py @@ -0,0 +1,23 @@ + +# ########################################## +# Used in 0015_add_version_to_ages.py +# ########################################## + +from specifyweb.specify.migration_utils.schema_writer import revert_table_field_schema_config, update_table_field_schema_config_with_defaults + + +def update_age_schema_config(apps): + # Revert before adding to avoid duplicates + # BUG: This will delete people's potentially modified Schema Config items + # If we want to avoid duplicates, we should check the creation code and + # prevent duplicates being created there + # revert_update_age_schema_config(apps) + + Discipline = apps.get_model('specify', 'Discipline') + for discipline in Discipline.objects.all(): + update_table_field_schema_config_with_defaults('AbsoluteAge', discipline.id, 'version', apps) + update_table_field_schema_config_with_defaults('RelativeAge', discipline.id, 'version', apps) + +def revert_update_age_schema_config(apps): + revert_table_field_schema_config('AbsoluteAge', 'version', apps) + revert_table_field_schema_config('RelativeAge', 'version', apps) \ No newline at end of file diff --git a/specifyweb/specify/migration_utils/migration_helpers/0017_schemaconfig_fixes_helper.py b/specifyweb/specify/migration_utils/migration_helpers/0017_schemaconfig_fixes_helper.py new file mode 100644 index 00000000000..8b0b55b23d5 --- /dev/null +++ b/specifyweb/specify/migration_utils/migration_helpers/0017_schemaconfig_fixes_helper.py @@ -0,0 +1,100 @@ +from specifyweb.specify.migration_utils.schema_reader import camel_to_spaced_title_case, datamodel_type_to_schematype, uncapitilize +from specifyweb.specify.models import datamodel + +import logging + +from specifyweb.specify.migration_utils.sp7_schemaconfig import ( + MIGRATION_0002_TABLES, + MIGRATION_0004_FIELDS, + MIGRATION_0004_TABLES, + MIGRATION_0007_FIELDS, + MIGRATION_0008_FIELDS, + MIGRATION_0012_FIELDS, + MIGRATION_0013_FIELDS, +) +# ########################################## +# Used in 0017_schemaconfig_fixes.py +# ########################################## + +CONTAINER_MIGRATIONS = [MIGRATION_0002_TABLES, MIGRATION_0004_TABLES] + +CONTAINER_ITEM_MIGRATIONS = [ + MIGRATION_0004_FIELDS, + MIGRATION_0007_FIELDS, + MIGRATION_0008_FIELDS, + MIGRATION_0012_FIELDS, + MIGRATION_0013_FIELDS, +] + +logger = logging.getLogger(__name__) + + +def fix_table_captions(apps): + Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') + Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') + Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') + + for migration in CONTAINER_MIGRATIONS: + for table_name, table_desc in migration: + table = datamodel.get_table(table_name) + + # BUG: The splocalecontainer related tables can still exist in the + # database, and this will result in skipping any operation if the + # table/field is removed, renamed, etc. + if table is None: + logger.warning(f"Table does not exist in latest state of the datamodel, skipping Schema Config update for: {table_name}") + continue + containers = Splocalecontainer.objects.filter( + name=table_name.lower(), schematype=0) + + # If needed, correct the label of the table in the schema config + if table_desc is not None: + Splocaleitemstr.objects.filter( + containername__in=containers, text=table_desc + ).update(text=camel_to_spaced_title_case(uncapitilize(table.name))) + + # Update the types for the fields in the table + items = Splocalecontaineritem.objects.filter( + container__in=containers) + for item in items: + datamodel_field = table.get_field(item.name) + if not datamodel_field: + continue + + item.type = datamodel_type_to_schematype( + datamodel_field.type) if datamodel_field.is_relationship else datamodel_field.type + item.isrequired = datamodel_field.required if item.isrequired is None else item.isrequired + + item.save() + + +def fix_item_types(apps): + Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') + + for migration in CONTAINER_ITEM_MIGRATIONS: + for table_name, fields in migration.items(): + table = datamodel.get_table(table_name) + # BUG: The splocalecontainer related tables can still exist in the + # database, and this will result in skipping any operation if the + # table/field is removed, renamed, etc. + if table is None: + logger.warning(f"Table does not exist in latest state of the datamodel, skipping Schema Config entry for: {table_name}") + continue + items = Splocalecontaineritem.objects.filter( + container__name=table_name.lower(), container__schematype=0, name__in=fields) + + for item in items: + datamodel_field = table.get_field(item.name) + if not datamodel_field: + continue + + item.type = datamodel_type_to_schematype( + datamodel_field.type) if datamodel_field.is_relationship else datamodel_field.type + item.isrequired = datamodel_field.required if item.isrequired is None else item.isrequired + + item.save() + + +def schemaconfig_fixes(apps, schema_editor=None): + fix_table_captions(apps) + fix_item_types(apps) \ No newline at end of file diff --git a/specifyweb/specify/migration_utils/migration_helpers/0018_cot_catnum_schema_helper.py b/specifyweb/specify/migration_utils/migration_helpers/0018_cot_catnum_schema_helper.py new file mode 100644 index 00000000000..6814e610afa --- /dev/null +++ b/specifyweb/specify/migration_utils/migration_helpers/0018_cot_catnum_schema_helper.py @@ -0,0 +1,60 @@ +from specifyweb.specify.migration_utils.schema_reader import camel_to_spaced_title_case +from specifyweb.specify.models import datamodel + +# ########################################## +# Used in 0018_cot_catnum_schema.py +# ########################################## + +def add_cot_catnum_to_schema(apps, schema_editor=None): + Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') + Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') + Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') + + CollectionObjectType_Table = datamodel.get_table_strict( + 'collectionobjecttype') + catalognumber_format_field = CollectionObjectType_Table.get_field_strict( + 'catalogNumberFormatName') + + for container in Splocalecontainer.objects.filter(name='collectionobjecttype', schematype=0): + schema_item, created = Splocalecontaineritem.objects.get_or_create( + name=catalognumber_format_field.name, type=catalognumber_format_field.type, container=container) + if created: + schema_item.version = 0 + + schema_item.isrequired = ( + catalognumber_format_field.required + if schema_item.isrequired is None + else schema_item.isrequired + ) + + schema_item.save() + + schema_name = camel_to_spaced_title_case( + catalognumber_format_field.name) + Splocaleitemstr.objects.get_or_create( + language='en', text=schema_name, itemname=schema_item) + Splocaleitemstr.objects.get_or_create( + language='en', text=schema_name, itemdesc=schema_item) + +def remove_cot_catnum_from_schema(apps, schema_editor=None): + Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') + Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') + Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') + + CollectionObjectType_Table = datamodel.get_table_strict( + 'collectionobjecttype') + catalognumber_format_field = CollectionObjectType_Table.get_field_strict( + 'catalogNumberFormatName') + + containers = Splocalecontainer.objects.filter( + name='collectionobjecttype', schematype=0) + items = Splocalecontaineritem.objects.filter( + name='catalogNumberFormatName', container__in=containers) + + schema_name = camel_to_spaced_title_case(catalognumber_format_field.name) + filters = Q(language='en', text=schema_name) & ( + Q(itemname__in=items) | Q(itemdesc__in=items)) + locale_strings = Splocaleitemstr.objects.filter(filters) + + locale_strings.delete() + items.delete() \ No newline at end of file diff --git a/specifyweb/specify/migration_utils/migration_helpers/0020_add_tectonicunit_to_pc_in_schema_config_helper.py b/specifyweb/specify/migration_utils/migration_helpers/0020_add_tectonicunit_to_pc_in_schema_config_helper.py new file mode 100644 index 00000000000..5d7e3b7df57 --- /dev/null +++ b/specifyweb/specify/migration_utils/migration_helpers/0020_add_tectonicunit_to_pc_in_schema_config_helper.py @@ -0,0 +1,20 @@ +from specifyweb.specify.migration_utils.schema_writer import revert_table_field_schema_config, update_table_field_schema_config_with_defaults +from specifyweb.specify.migration_utils.sp7_schemaconfig import ( + MIGRATION_0020_FIELDS, +) +# ########################################## +# Used in 0020_add_tectonicunit_to_pc_in_schema_config.py +# ########################################## + +def add_tectonicunit_to_pc_in_schema_config(apps): + Discipline = apps.get_model('specify', 'Discipline') + for discipline in Discipline.objects.all(): + for table, fields in MIGRATION_0020_FIELDS.items(): + for field in fields: + update_table_field_schema_config_with_defaults( + table, discipline.id, field, apps) + +def remove_tectonicunit_from_pc_schema_config(apps): + for table, fields in MIGRATION_0020_FIELDS.items(): + for field in fields: + revert_table_field_schema_config(table, field, apps) \ No newline at end of file diff --git a/specifyweb/specify/migration_utils/migration_helpers/0021_update_hidden_geo_tables_helper.py b/specifyweb/specify/migration_utils/migration_helpers/0021_update_hidden_geo_tables_helper.py new file mode 100644 index 00000000000..f91e9735d28 --- /dev/null +++ b/specifyweb/specify/migration_utils/migration_helpers/0021_update_hidden_geo_tables_helper.py @@ -0,0 +1,51 @@ +from specifyweb.specify.models_utils.model_extras import GEOLOGY_DISCIPLINES, PALEO_DISCIPLINES +from specifyweb.specify.migration_utils.sp7_schemaconfig import ( + MIGRATION_0021_FIELDS, +) +# ########################################## +# Used in 0021_update_hidden_geo_tables.py +# ########################################## + +def fix_hidden_geo_prop(apps, schema_editor=None): + Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') + Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') + Discipline = apps.get_model('specify', 'Discipline') + + excluded_disciplines = PALEO_DISCIPLINES | GEOLOGY_DISCIPLINES + + filtered_disciplines = Discipline.objects.exclude(type__in=excluded_disciplines) + + for discipline in filtered_disciplines: + for table, fields in MIGRATION_0021_FIELDS.items(): + containers = Splocalecontainer.objects.filter( + name=table.lower(), + discipline_id=discipline.id, + ) + for container in containers: + # BUG: What if the user wants the field unhidden? + Splocalecontaineritem.objects.filter( + container=container, + name__in=tuple(map(lambda field_name: field_name.lower(), fields)) + ).update(ishidden=True) + +def reverse_fix_hidden_geo_prop(apps, schema_editor=None): + Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') + Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') + Discipline = apps.get_model('specify', 'Discipline') + + excluded_disciplines = PALEO_DISCIPLINES | GEOLOGY_DISCIPLINES + + filtered_disciplines = Discipline.objects.exclude(type__in=excluded_disciplines) + + for discipline in filtered_disciplines: + for table, fields in MIGRATION_0021_FIELDS.items(): + containers = Splocalecontainer.objects.filter( + name=table.lower(), + discipline_id=discipline.id, + ) + for container in containers: + # BUG: What if the user wants the field hidden? + Splocalecontaineritem.objects.filter( + container=container, + name__in=tuple(map(lambda field_name: field_name.lower(), fields)) + ).update(ishidden=False) \ No newline at end of file diff --git a/specifyweb/specify/migration_utils/migration_helpers/0023_update_schema_config_text_helper.py b/specifyweb/specify/migration_utils/migration_helpers/0023_update_schema_config_text_helper.py new file mode 100644 index 00000000000..f4d523a4e7d --- /dev/null +++ b/specifyweb/specify/migration_utils/migration_helpers/0023_update_schema_config_text_helper.py @@ -0,0 +1,184 @@ +import logging +from django.db.models import Count + +from specifyweb.specify.migration_utils.schema_reader import _fields_without_explicit_hidden_override, _schema_override_hidden_values_for_discipline +from specifyweb.specify.migration_utils.sp7_schemaconfig import ( + MIGRATION_0023_FIELDS, + MIGRATION_0023_FIELDS_BIS, +) + +logger = logging.getLogger(__name__) + +# ########################################## +# Used in 0023_update_schema_config_text.py +# ########################################## + +def update_schema_config_field_desc(apps, schema_editor=None): + Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') + Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') + Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') + + for table, fields in MIGRATION_0023_FIELDS.items(): + #i.e: Collection Object + containers = Splocalecontainer.objects.filter( + name=table.lower(), + ) + + for container in containers: + for field_name, new_name, new_desc in fields: + #i.e: COType + items = Splocalecontaineritem.objects.filter( + container=container, + name__iexact=field_name + ) + + for item in items: + localized_items_desc = Splocaleitemstr.objects.filter(itemdesc_id=item.id).first() + localized_items_name = Splocaleitemstr.objects.filter(itemname_id=item.id).first() + + if localized_items_desc is None or localized_items_name is None: + continue + + localized_items_desc.text = new_desc + localized_items_desc.save() + + localized_items_name.text = new_name + localized_items_name.save() + +def update_hidden_prop(apps, schema_editor=None): + Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') + Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') + Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') + Discipline = apps.get_model('specify', 'Discipline') + discipline_types_by_id = dict(Discipline.objects.values_list("id", "type")) + + for table, fields in MIGRATION_0023_FIELDS_BIS.items(): + field_names = [field_name.lower() for field_name in fields] + field_name_set = set(field_names) + containers = Splocalecontainer.objects.filter( + name=table.lower(), + schematype=0 + ) + for container in containers: + discipline_type = discipline_types_by_id.get(container.discipline_id, "") + explicit_hidden_overrides = { + field_name: ishidden + for field_name, ishidden in _schema_override_hidden_values_for_discipline( + discipline_type + ).get(table.lower(), {}).items() + if field_name in field_name_set + } + explicit_fields_to_hide = [ + field_name + for field_name, ishidden in explicit_hidden_overrides.items() + if ishidden + ] + explicit_fields_to_show = [ + field_name + for field_name, ishidden in explicit_hidden_overrides.items() + if not ishidden + ] + + if explicit_fields_to_hide: + Splocalecontaineritem.objects.filter( + container=container, + ishidden=False, + name__in=explicit_fields_to_hide, + ).update(ishidden=True) + + if explicit_fields_to_show: + Splocalecontaineritem.objects.filter( + container=container, + ishidden=True, + name__in=explicit_fields_to_show, + ).update(ishidden=False) + + fields_to_hide = _fields_without_explicit_hidden_override( + table, + field_names, + discipline_type, + ) + if not fields_to_hide: + continue + + items_updated = Splocalecontaineritem.objects.filter( + container=container, + ishidden=False, + name__in=fields_to_hide + ).update(ishidden=True) + if items_updated > 0: + logger.info(f"Hid {items_updated} items for table {table} and container {container.id}") + + duplicates = ( + Splocalecontaineritem.objects.values("container", "name") + .annotate(count=Count("id")) + .filter(count__gt=1) + ) + for duplicate in duplicates: + container_id = duplicate['container'] + name = duplicate['name'] + duplicate_items = Splocalecontaineritem.objects.filter(container_id=container_id, name=name) + item_to_keep = duplicate_items.first() + items_to_delete = duplicate_items.exclude(id=item_to_keep.id) + + Splocaleitemstr.objects.filter(itemdesc_id__in=items_to_delete).update(itemdesc_id=item_to_keep.id) + Splocaleitemstr.objects.filter(itemname_id__in=items_to_delete).update(itemname_id=item_to_keep.id) + items_to_delete.delete() + +def reverse_update_hidden_prop(apps, schema_editor=None): + Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') + Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') + Discipline = apps.get_model('specify', 'Discipline') + discipline_types_by_id = dict(Discipline.objects.values_list("id", "type")) + + for table, fields in MIGRATION_0023_FIELDS_BIS.items(): + field_names = [field_name.lower() for field_name in fields] + containers = Splocalecontainer.objects.filter( + name=table.lower(), + ) + for container in containers: + discipline_type = discipline_types_by_id.get(container.discipline_id, "") + fields_to_unhide = _fields_without_explicit_hidden_override( + table, + field_names, + discipline_type, + ) + if not fields_to_unhide: + continue + + items = Splocalecontaineritem.objects.filter( + container=container, + name__in=fields_to_unhide + ) + logger.info(f"Reverting {items.count()} items for table {table} and container {container.id}") + items.update(ishidden=False) + +def reverse_update_schema_config_field_desc(apps, schema_editor=None): + Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') + Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') + Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') + + for table, fields in MIGRATION_0023_FIELDS.items(): + containers = Splocalecontainer.objects.filter( + name=table.lower(), + ) + + for container in containers: + for field_name, new_name, new_desc in fields: + items = Splocalecontaineritem.objects.filter( + container=container, + name=field_name.lower() + ) + + for item in items: + localized_items_desc = Splocaleitemstr.objects.filter(itemdesc_id=item.id).first() + localized_items_name = Splocaleitemstr.objects.filter(itemname_id=item.id).first() + + if localized_items_desc is None or localized_items_name is None: + continue + + localized_items_desc.text = item.name + localized_items_desc.save() + + localized_items_name.text = item.name + localized_items_name.save() \ No newline at end of file diff --git a/specifyweb/specify/migration_utils/migration_helpers/0024_add_uniqueIdentifier_storage_helper.py b/specifyweb/specify/migration_utils/migration_helpers/0024_add_uniqueIdentifier_storage_helper.py new file mode 100644 index 00000000000..37d98dff604 --- /dev/null +++ b/specifyweb/specify/migration_utils/migration_helpers/0024_add_uniqueIdentifier_storage_helper.py @@ -0,0 +1,22 @@ +from specifyweb.specify.migration_utils.schema_writer import revert_table_field_schema_config, update_table_field_schema_config_with_defaults +from specifyweb.specify.migration_utils.sp7_schemaconfig import ( + MIGRATION_0024_FIELDS, +) +# ########################################## +# Used in 0024_add_uniqueIdentifier_storage.py +# ########################################## + +def update_storage_unique_id_fields(apps): + Discipline = apps.get_model('specify', 'Discipline') + + # Add uniqueIdentifier -> storage + for discipline in Discipline.objects.all(): + for table, fields in MIGRATION_0024_FIELDS.items(): + for field in fields: + update_table_field_schema_config_with_defaults(table, discipline.id, field, apps) + +def revert_storage_unique_id_fields(apps): + # Remove uniqueIdentifier -> storage + for table, fields in MIGRATION_0024_FIELDS.items(): + for field in fields: + revert_table_field_schema_config(table, field, apps) \ No newline at end of file diff --git a/specifyweb/specify/migration_utils/migration_helpers/0027_CO_children_helper.py b/specifyweb/specify/migration_utils/migration_helpers/0027_CO_children_helper.py new file mode 100644 index 00000000000..fa7e90e001f --- /dev/null +++ b/specifyweb/specify/migration_utils/migration_helpers/0027_CO_children_helper.py @@ -0,0 +1,80 @@ +from specifyweb.specify.migration_utils.schema_writer import revert_table_field_schema_config, update_table_field_schema_config_with_defaults +from specifyweb.specify.migration_utils.sp7_schemaconfig import ( + MIGRATION_0027_FIELDS, + MIGRATION_0027_UPDATE_FIELDS, + ) +# ########################################## +# Used in 0027_CO_children.py +# ########################################## + +def update_co_children_fields(apps): + def update_discipline_fields(apps): + Discipline = apps.get_model('specify', 'Discipline') + + for discipline in Discipline.objects.all(): + for table, fields in MIGRATION_0027_FIELDS.items(): + for field in fields: + update_table_field_schema_config_with_defaults(table, discipline.id, field, apps) + + def update_schema_config_field_desc(apps): + Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') + Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') + Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') + + for table, fields in MIGRATION_0027_UPDATE_FIELDS.items(): + #i.e: Collection Object + containers = Splocalecontainer.objects.filter( + name=table.lower(), + ) + + for container in containers: + for field_name, new_name, new_desc in fields: + #i.e: COType + items = Splocalecontaineritem.objects.filter( + container=container, + name__iexact=field_name + ) + + for item in items: + localized_items_desc = Splocaleitemstr.objects.filter(itemdesc_id=item.id).first() + localized_items_name = Splocaleitemstr.objects.filter(itemname_id=item.id).first() + + if localized_items_desc is None or localized_items_name is None: + continue + + localized_items_desc.text = new_desc + localized_items_desc.save() + + localized_items_name.text = new_name + localized_items_name.save() + + update_discipline_fields(apps) + update_schema_config_field_desc(apps) + +def revert_co_children_fields(apps): + def revert_update_fields(apps): + for table, fields in MIGRATION_0027_FIELDS.items(): + for field in fields: + revert_table_field_schema_config(table, field, apps) + + def revert_update_schema_field(apps): + Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') + Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') + + for table, fields in MIGRATION_0027_UPDATE_FIELDS.items(): + containers = Splocalecontainer.objects.filter( + name=table.lower(), + ) + for container in containers: + for field_name in fields: + items = Splocalecontaineritem.objects.filter( + container=container, + name=field_name + ) + + for item in items: + item.ishidden = False + item.save() + + revert_update_fields(apps) + revert_update_schema_field(apps) \ No newline at end of file diff --git a/specifyweb/specify/migration_utils/migration_helpers/0029_remove_collectionobject_parentco_helper.py b/specifyweb/specify/migration_utils/migration_helpers/0029_remove_collectionobject_parentco_helper.py new file mode 100644 index 00000000000..612443d7d22 --- /dev/null +++ b/specifyweb/specify/migration_utils/migration_helpers/0029_remove_collectionobject_parentco_helper.py @@ -0,0 +1,130 @@ +from specifyweb.specify.migration_utils.schema_writer import revert_table_field_schema_config, update_table_field_schema_config_with_defaults +from specifyweb.specify.migration_utils.sp7_schemaconfig import ( + MIGRATION_0029_UPDATE_FIELDS, + MIGRATION_0029_FIELDS, +) +# ########################################## +# Used in 0029_remove_collectionobject_parentco.py +# ########################################## + +def remove_collectionobject_parentco(apps): + def update_fields(apps): + Discipline = apps.get_model('specify', 'Discipline') + + for discipline in Discipline.objects.all(): + for table, fields in MIGRATION_0029_FIELDS.items(): + for field in fields: + update_table_field_schema_config_with_defaults(table, discipline.id, field, apps) + + def update_schema_config_field_desc(apps): + Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') + Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') + Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') + + for table, fields in MIGRATION_0029_UPDATE_FIELDS.items(): + #i.e: Collection Object + containers = Splocalecontainer.objects.filter( + name=table.lower(), + ) + + for container in containers: + for field_name, new_name, new_desc in fields: + #i.e: COType + items = Splocalecontaineritem.objects.filter( + container=container, + name__iexact=field_name + ) + + for item in items: + localized_items_desc = Splocaleitemstr.objects.filter(itemdesc_id=item.id).first() + localized_items_name = Splocaleitemstr.objects.filter(itemname_id=item.id).first() + + if localized_items_desc is None or localized_items_name is None: + continue + + localized_items_desc.text = new_desc + localized_items_desc.save() + + localized_items_name.text = new_name + localized_items_name.save() + + def hide_co_component(apps): + Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') + Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') + Discipline = apps.get_model('specify', 'Discipline') + + disciplines = Discipline.objects.all() + + for discipline in disciplines: + for table, fields in MIGRATION_0029_UPDATE_FIELDS.items(): + containers = Splocalecontainer.objects.filter( + name=table.lower(), + discipline_id=discipline.id, + ) + for container in containers: + for field_name, _, _ in fields: + items = Splocalecontaineritem.objects.filter( + container=container, + name=field_name.lower() + ) + + for item in items: + item.ishidden = True + item.save() + + update_fields(apps) + update_schema_config_field_desc(apps) + hide_co_component(apps) + +def revert_remove_collectionobject_parentco(apps): + def revert_update_fields(apps): + for table, fields in MIGRATION_0029_FIELDS.items(): + for field in fields: + revert_table_field_schema_config(table, field, apps) + + def revert_update_schema_field(apps): + Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') + Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') + + for table, fields in MIGRATION_0029_UPDATE_FIELDS.items(): + containers = Splocalecontainer.objects.filter( + name=table.lower(), + ) + for container in containers: + for field_name in fields: + items = Splocalecontaineritem.objects.filter( + container=container, + name=field_name + ) + + for item in items: + item.ishidden = False + item.save() + + def reverse_hide_co_component(apps): + Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') + Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') + Discipline = apps.get_model('specify', 'Discipline') + + disciplines = Discipline.objects.all() + + for discipline in disciplines: + for table, fields in MIGRATION_0029_UPDATE_FIELDS.items(): + containers = Splocalecontainer.objects.filter( + name=table.lower(), + discipline_id=discipline.id, + ) + for container in containers: + for field_name, _, _ in fields: + items = Splocalecontaineritem.objects.filter( + container=container, + name=field_name.lower() + ) + + for item in items: + item.ishidden = False + item.save() + + revert_update_fields(apps) + revert_update_schema_field(apps) + reverse_hide_co_component(apps) \ No newline at end of file diff --git a/specifyweb/specify/migration_utils/migration_helpers/0032_add_quantities_gift_helper.py b/specifyweb/specify/migration_utils/migration_helpers/0032_add_quantities_gift_helper.py new file mode 100644 index 00000000000..dcadd862bb7 --- /dev/null +++ b/specifyweb/specify/migration_utils/migration_helpers/0032_add_quantities_gift_helper.py @@ -0,0 +1,80 @@ +from specifyweb.specify.migration_utils.schema_writer import revert_table_field_schema_config, update_table_field_schema_config_with_defaults +from specifyweb.specify.migration_utils.sp7_schemaconfig import ( + MIGRATION_0032_FIELDS, + MIGRATION_0032_UPDATE_FIELDS, +) +# ########################################## +# Used in 0032_add_quantities_gift.py +# ########################################## + +def add_quantities_gift(apps): + def update_fields(apps): + Discipline = apps.get_model('specify', 'Discipline') + + for discipline in Discipline.objects.all(): + for table, fields in MIGRATION_0032_FIELDS.items(): + for field in fields: + update_table_field_schema_config_with_defaults(table, discipline.id, field, apps) + + def update_schema_config_field_desc(apps): + Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') + Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') + Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') + + for table, fields in MIGRATION_0032_UPDATE_FIELDS.items(): + #i.e: Collection Object + containers = Splocalecontainer.objects.filter( + name=table.lower(), + ) + + for container in containers: + for field_name, new_name, new_desc in fields: + #i.e: COType + items = Splocalecontaineritem.objects.filter( + container=container, + name__iexact=field_name + ) + + for item in items: + localized_items_desc = Splocaleitemstr.objects.filter(itemdesc_id=item.id).first() + localized_items_name = Splocaleitemstr.objects.filter(itemname_id=item.id).first() + + if localized_items_desc is None or localized_items_name is None: + continue + + localized_items_desc.text = new_desc + localized_items_desc.save() + + localized_items_name.text = new_name + localized_items_name.save() + + update_fields(apps) + update_schema_config_field_desc(apps) + +def revert_add_quantities_gift(apps): + def revert_update_fields(apps): + for table, fields in MIGRATION_0032_FIELDS.items(): + for field in fields: + revert_table_field_schema_config(table, field, apps) + + def revert_update_schema_field(apps): + Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') + Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') + + for table, fields in MIGRATION_0032_UPDATE_FIELDS.items(): + containers = Splocalecontainer.objects.filter( + name=table.lower(), + ) + for container in containers: + for field_name in fields: + items = Splocalecontaineritem.objects.filter( + container=container, + name=field_name + ) + + for item in items: + item.ishidden = False + item.save() + + revert_update_fields(apps) + revert_update_schema_field(apps) diff --git a/specifyweb/specify/migration_utils/migration_helpers/0033_update_paleo_desc_helper.py b/specifyweb/specify/migration_utils/migration_helpers/0033_update_paleo_desc_helper.py new file mode 100644 index 00000000000..5bd058b58e4 --- /dev/null +++ b/specifyweb/specify/migration_utils/migration_helpers/0033_update_paleo_desc_helper.py @@ -0,0 +1,18 @@ +from specifyweb.specify.migration_utils.sp7_schemaconfig import ( + MIGRATION_0033_TABLES, +) + +# ########################################## +# Used in 0033_update_paleo_desc.py +# ########################################## + +def update_paleo_desc(apps): + def fix_table_description(apps): + Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') + Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') + + for table_name, table_desc in MIGRATION_0033_TABLES: + containers = Splocalecontainer.objects.filter(name=table_name.lower(), schematype=0) + Splocaleitemstr.objects.filter(containerdesc__in=containers).update(text=table_desc) + + fix_table_description(apps) \ No newline at end of file diff --git a/specifyweb/specify/migration_utils/migration_helpers/0035_version_required_helper.py b/specifyweb/specify/migration_utils/migration_helpers/0035_version_required_helper.py new file mode 100644 index 00000000000..0d09141f906 --- /dev/null +++ b/specifyweb/specify/migration_utils/migration_helpers/0035_version_required_helper.py @@ -0,0 +1,31 @@ +from specifyweb.specify.migration_utils.schema_writer import update_table_field_schema_config_params +from specifyweb.specify.migration_utils.sp7_schemaconfig import ( + MIGRATION_0035_FIELDS, +) +# ########################################## +# Used in 0035_version_required.py +# ########################################## + +def update_version_required(apps): + Discipline = apps.get_model('specify', 'Discipline') + updated_config_params = { + 'isrequired': False, + } + + # Update the schema config for each discipline with the version isHidden change + for discipline in Discipline.objects.all(): + for table, fields in MIGRATION_0035_FIELDS.items(): + for field in fields: + update_table_field_schema_config_params(table, discipline.id, field, updated_config_params, apps) + +def revert_version_required(apps): + Discipline = apps.get_model('specify', 'Discipline') + updated_config_params = { + 'isrequired': True, + } + + # Revert the schema config for each discipline with the version isHidden change + for discipline in Discipline.objects.all(): + for table, fields in MIGRATION_0035_FIELDS.items(): + for field in fields: + update_table_field_schema_config_params(table, discipline.id, field, updated_config_params, apps) diff --git a/specifyweb/specify/migration_utils/migration_helpers/0039_agent_fields_for_loan_and_gift_helper.py b/specifyweb/specify/migration_utils/migration_helpers/0039_agent_fields_for_loan_and_gift_helper.py new file mode 100644 index 00000000000..5d2fcb2c929 --- /dev/null +++ b/specifyweb/specify/migration_utils/migration_helpers/0039_agent_fields_for_loan_and_gift_helper.py @@ -0,0 +1,24 @@ +from specifyweb.specify.migration_utils.sp7_schemaconfig import ( + MIGRATION_0038_FIELDS, +) +# ########################################## +# Used in 0039_agent_fields_for_loan_and_gift.py +# ########################################## + +from specifyweb.specify.migration_utils.schema_writer import revert_table_field_schema_config, update_table_field_schema_config_with_defaults + + +def update_loan_and_gift_agent_fields(apps): + Discipline = apps.get_model('specify', 'Discipline') + field_defaults = { + "ishidden": True + } + for discipline in Discipline.objects.all(): + for table, fields in MIGRATION_0038_FIELDS.items(): + for field_name in fields: + update_table_field_schema_config_with_defaults(table, discipline.id, field_name, apps, defaults=field_defaults) + +def revert_loan_and_gift_agent_fields(apps): + for table, fields in MIGRATION_0038_FIELDS.items(): + for field_name in fields: + revert_table_field_schema_config(table, field_name, apps) \ No newline at end of file diff --git a/specifyweb/specify/migration_utils/migration_helpers/0040_components_helper.py b/specifyweb/specify/migration_utils/migration_helpers/0040_components_helper.py new file mode 100644 index 00000000000..daba2bab0b1 --- /dev/null +++ b/specifyweb/specify/migration_utils/migration_helpers/0040_components_helper.py @@ -0,0 +1,135 @@ +from specifyweb.specify.migration_utils.schema_writer import revert_table_field_schema_config, revert_table_schema_config, update_table_field_schema_config_with_defaults, update_table_schema_config_with_defaults +from specifyweb.specify.migration_utils.sp7_schemaconfig import ( + MIGRATION_0029_UPDATE_FIELDS, + MIGRATION_0040_TABLES, + MIGRATION_0040_FIELDS, + MIGRATION_0040_UPDATE_FIELDS, + MIGRATION_0040_HIDDEN_FIELDS, +) +# ########################################## +# Used in 0040_components.py +# ########################################## + +def remove_componentparent_item(apps): + revert_table_field_schema_config("CollectionObject", "componentParent", apps) + +def remove_0029_schema_config_fields(apps, schema_editor=None): + Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') + Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') + + FIELDS_TO_REMOVE = MIGRATION_0029_UPDATE_FIELDS + for table, fields in FIELDS_TO_REMOVE.items(): + items = Splocalecontaineritem.objects.filter( + container__name=table.lower(), + container__schematype=0, + # we only need the field name from the tuple of Schema Config information + name__in=list(map(lambda f: f[0].lower(), fields)) + ) + + # Delete field labels (captions) and descriptions (Splocaleitemstr) associated with the fields + Splocaleitemstr.objects.filter( + Q(itemdesc__in=items) | Q(itemname__in=items) + ).delete() + + items.delete() + +def create_table_schema_config_with_defaults(apps, schema_editor=None): + Discipline = apps.get_model('specify', 'Discipline') + for discipline in Discipline.objects.all(): + for table, desc in MIGRATION_0040_TABLES: + update_table_schema_config_with_defaults(table, discipline.id, desc, apps) + + for table, fields in MIGRATION_0040_FIELDS.items(): + for field in fields: + update_table_field_schema_config_with_defaults(table, discipline.id, field, apps) + +def update_schema_config_field_desc_for_components(apps, schema_editor=None): + Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') + + for table, fields in MIGRATION_0040_UPDATE_FIELDS.items(): + for field_name, new_name, new_desc in fields: + + Splocaleitemstr.objects.filter( + itemdesc__container__name=table.lower(), + itemdesc__container__schematype=0, + itemdesc__name=field_name.lower(), + language="en", + ).update(text=new_desc) + + Splocaleitemstr.objects.filter( + itemname__container__name=table.lower(), + itemname__container__schematype=0, + itemname__name=field_name.lower(), + language="en", + ).update(text=new_name) + +def update_hidden_prop_for_compoenents(apps, schema_editor=None): + Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') + + for table, fields in MIGRATION_0040_FIELDS.items(): + Splocalecontaineritem.objects.filter( + container__name=table.lower(), + container__schematype=0, + name__in=list(map(lambda f: f.lower(), fields)) + ).update(ishidden=True) + +def create_cotype_splocalecontaineritem_for_components(apps): + Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') + PICKLIST_NAME = 'CollectionObjectType' + FIELD_NAME = 'type' + + # Create a Splocalecontaineritem record for each Component Splocalecontainer + # NOTE: Each discipline has its own Component Splocalecontainer + Splocalecontaineritem.objects.filter( + container__name='component', + container__schematype=0, + name=FIELD_NAME + ).update( + picklistname=PICKLIST_NAME, + isrequired=True, + type='ManyToOne', + ) + +def hide_component_fields(apps, schema_editor=None): + Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') + + for table, fields in MIGRATION_0040_HIDDEN_FIELDS.items(): + Splocalecontaineritem.objects.filter( + container__name=table.lower(), + container__schematype=0, + name__in=list(map(lambda f: f.lower(), fields)) + ).update(ishidden=True) + +def restore_0029_schema_config_fields(apps, schema_editor=None): + Discipline = apps.get_model('specify', 'Discipline') + FIELDS_TO_REMOVE = MIGRATION_0029_UPDATE_FIELDS + for discipline in Discipline.objects.all(): + for table, fields in FIELDS_TO_REMOVE.items(): + for field_name, _, _ in fields: + update_table_field_schema_config_with_defaults(table, discipline.id, field_name, apps) + +def revert_table_schema_config_with_defaults(apps, schema_editor=None): + for table, _ in MIGRATION_0040_TABLES: + revert_table_schema_config(table, apps) + for table, fields in MIGRATION_0040_FIELDS.items(): + for field in fields: + revert_table_field_schema_config(table, field, apps) + +def reverse_hide_component_fields(apps, schema_editor=None): + Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') + Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') + Discipline = apps.get_model('specify', 'Discipline') + + for discipline in Discipline.objects.all(): + for table, fields in MIGRATION_0040_HIDDEN_FIELDS.items(): + containers = Splocalecontainer.objects.filter( + name=table.lower(), + discipline_id=discipline.id, + ) + for container in containers: + for field_name in fields: + items = Splocalecontaineritem.objects.filter( + container=container, + name=field_name.lower() + ) + items.update(ishidden=False) \ No newline at end of file diff --git a/specifyweb/specify/migration_utils/migration_helpers/0042_discipline_type_picklist_helper.py b/specifyweb/specify/migration_utils/migration_helpers/0042_discipline_type_picklist_helper.py new file mode 100644 index 00000000000..c24f53b7657 --- /dev/null +++ b/specifyweb/specify/migration_utils/migration_helpers/0042_discipline_type_picklist_helper.py @@ -0,0 +1,65 @@ + +# ########################################## +# Used in 0042_discipline_type_picklist.py +# ########################################## + +from specifyweb.backend.context.app_resource import DISCIPLINE_NAMES + +DISCIPLINE_TYPE_PICKLIST_NAME = 'DisciplineType' + +def create_discipline_type_picklist(apps): + Collection = apps.get_model('specify', 'Collection') + Picklist = apps.get_model('specify', 'Picklist') + Picklistitem = apps.get_model('specify', 'Picklistitem') + + # Create a discipline type picklist for each collection + for collection in Collection.objects.all(): + picklist, created = Picklist.objects.get_or_create( + name=DISCIPLINE_TYPE_PICKLIST_NAME, + type=0, + collection=collection, + defaults={ + "issystem": True, + "readonly": True, + "sizelimit": -1, + "sorttype": 1, + } + ) + # If the picklist doesn't exist, create a new one + if created: + ordinal = 1 + items = [] + for value, title in DISCIPLINE_NAMES.items(): + items.append( + Picklistitem( + picklist=picklist, + ordinal=ordinal, + value=value, + title=title, + ) + ) + ordinal += 1 + Picklistitem.objects.bulk_create(items) + +def revert_discipline_type_picklist(apps): + Picklist = apps.get_model('specify', 'Picklist') + + Picklist.objects.filter(name=DISCIPLINE_TYPE_PICKLIST_NAME).delete() + +def update_discipline_type_splocalecontaineritem(apps): + Splocalecontaineritem = apps.get_model("specify", "Splocalecontaineritem") + + Splocalecontaineritem.objects.filter( + container__name="discipline", + container__schematype=0, + name="type", + ).update(picklistname=DISCIPLINE_TYPE_PICKLIST_NAME, isrequired=True) + +def revert_discipline_type_splocalecontaineritem(apps): + Splocalecontaineritem = apps.get_model("specify", "Splocalecontaineritem") + + Splocalecontaineritem.objects.filter( + container__name="discipline", + container__schematype=0, + name="type", + ).update(picklistname=None, isrequired=None) \ No newline at end of file diff --git a/specifyweb/specify/migration_utils/migration_helpers/_helper0034_accession_date_fields_helper.py b/specifyweb/specify/migration_utils/migration_helpers/_helper0034_accession_date_fields_helper.py new file mode 100644 index 00000000000..3738c658c38 --- /dev/null +++ b/specifyweb/specify/migration_utils/migration_helpers/_helper0034_accession_date_fields_helper.py @@ -0,0 +1,81 @@ +from specifyweb.specify.migration_utils.schema_writer import revert_table_field_schema_config, update_table_field_schema_config_with_defaults +from specifyweb.specify.migration_utils.sp7_schemaconfig import ( + MIGRATION_0034_FIELDS, + MIGRATION_0034_UPDATE_FIELDS, +) +# ########################################## +# Used in 0034_accession_date_fields.py +# ########################################## + +def update_accession_date_fields(apps): + def update_0034_fields(apps): + """ + Update table-field schema entries for plain field names + (e.g., MIGRATION_0034_FIELDS). + """ + Discipline = apps.get_model('specify', 'Discipline') + for discipline in Discipline.objects.all(): + for table, fields in MIGRATION_0034_FIELDS.items(): + for field_name in fields: + update_table_field_schema_config_with_defaults(table, discipline.id, field_name, apps) + + def update_0034_schema_config_field_desc(apps): + """ + Update field descriptions and display names using MIGRATION_0034_UPDATE_FIELDS + (tuple: (fieldName, newLabel, newDesc)). + """ + Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') + Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') + Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') + + for table, fields in MIGRATION_0034_UPDATE_FIELDS.items(): + containers = Splocalecontainer.objects.filter(name=table.lower()) + for container in containers: + for (field_name, new_name, new_desc) in fields: + items = Splocalecontaineritem.objects.filter( + container=container, + name__iexact=field_name + ) + for item in items: + item.ishidden = True + item.save() + desc_str = Splocaleitemstr.objects.filter(itemdesc_id=item.id).first() + name_str = Splocaleitemstr.objects.filter(itemname_id=item.id).first() + if desc_str is not None: + desc_str.text = new_desc + desc_str.save() + if name_str is not None: + name_str.text = new_name + name_str.save() + + update_0034_fields(apps) + update_0034_schema_config_field_desc(apps) + +def revert_update_accession_date_fields(apps): + def revert_0034_fields(apps): + """ + Revert table-field entries for plain field names. + """ + for table, fields in MIGRATION_0034_FIELDS.items(): + for field_name in fields: + revert_table_field_schema_config(table, field_name, apps) + + def revert_0034_schema_config_field_desc(apps): + """ + Revert the field name/description updates. + """ + Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') + Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') + + for table, fields in MIGRATION_0034_UPDATE_FIELDS.items(): + containers = Splocalecontainer.objects.filter(name=table.lower()) + for container in containers: + for (field_name, _, _) in fields: + items = Splocalecontaineritem.objects.filter( + container=container, + name__iexact=field_name + ) + # If needed, reset ishidden or revert text + + revert_0034_fields(apps) + revert_0034_schema_config_field_desc(apps) \ No newline at end of file diff --git a/specifyweb/specify/migration_utils/schema_writer.py b/specifyweb/specify/migration_utils/schema_writer.py index 9c81a92ceeb..d33b5d87b30 100644 --- a/specifyweb/specify/migration_utils/schema_writer.py +++ b/specifyweb/specify/migration_utils/schema_writer.py @@ -14,10 +14,13 @@ camel_to_spaced_title_case, find_missing_schema_config_fields, uncapitilize, - HIDDEN_FIELDS, datamodel_type_to_schematype ) +HIDDEN_FIELDS = [ + "timestampcreated", "timestampmodified", "version", "createdbyagent", "modifiedbyagent" +] + logger = logging.getLogger(__name__) class TableSchemaConfig(NamedTuple): From 722e1c7e86a418e7988ead62c3dd0672a2404f7b Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Mon, 15 Jun 2026 17:12:08 +0200 Subject: [PATCH 070/113] Refactor: Compartimentalize sp7_Schema_config_field to their own migration helper --- .../0002_schema_config_update_helper.py | 23 +- .../0004_stratigraphy_age_helper.py | 26 +- .../0007_schema_config_update_helper.py | 8 +- .../0008_schema_config_update_helper.py | 8 +- .../0012_add_cojo_to_schema_config_helper.py | 9 +- ..._collectionobjectgroup_parentcog_helper.py | 8 +- ...tonicunit_to_pc_in_schema_config_helper.py | 8 +- .../0021_update_hidden_geo_tables_helper.py | 8 +- .../0023_update_schema_config_text_helper.py | 78 +++- ...024_add_uniqueIdentifier_storage_helper.py | 8 +- .../0027_CO_children_helper.py | 14 +- ...remove_collectionobject_parentco_helper.py | 16 +- .../0032_add_quantities_gift_helper.py | 16 +- .../0033_update_paleo_desc_helper.py | 7 +- ...y => 0034_accession_date_fields_helper.py} | 19 +- .../0035_version_required_helper.py | 199 +++++++- ...9_agent_fields_for_loan_and_gift_helper.py | 13 +- .../0040_components_helper.py | 43 +- .../migration_utils/sp7_schemaconfig.py | 440 ------------------ 19 files changed, 444 insertions(+), 507 deletions(-) rename specifyweb/specify/migration_utils/migration_helpers/{_helper0034_accession_date_fields_helper.py => 0034_accession_date_fields_helper.py} (79%) delete mode 100644 specifyweb/specify/migration_utils/sp7_schemaconfig.py diff --git a/specifyweb/specify/migration_utils/migration_helpers/0002_schema_config_update_helper.py b/specifyweb/specify/migration_utils/migration_helpers/0002_schema_config_update_helper.py index 8fadc98dc2c..c308dd7bc50 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/0002_schema_config_update_helper.py +++ b/specifyweb/specify/migration_utils/migration_helpers/0002_schema_config_update_helper.py @@ -1,11 +1,28 @@ -from specifyweb.specify.migration_utils.sp7_schemaconfig import ( - MIGRATION_0002_TABLES, -) # ########################################## # Used in 0002_schema_config_update.py # ########################################## +MIGRATION_0002_TABLES = [ + ('CollectionObjectType', None), + ('CollectionObjectGroupType', None), + ('CollectionObjectGroup', None), + ('CollectionObjectGroupJoin', None), + ('SpUserExternalId', 'Stores provider identifiers and tokens for users who sign in using Single Sign On (SSO).'), + ('SpAttachmentDataSet', 'Holds attachment data sets.'), + ('UniquenessRule', 'Stores table names in the data model that have uniqueness rules configured for each discipline.'), + ('UniquenessRuleField', 'Stores field names in the data model that have uniqueness rules configured for each discipline, linked to UniquenessRule records.'), + ('Message', 'Stores user notifications.'), + ('SpMerging', 'Tracks record and task IDs of records being merged.'), + ('UserPolicy', 'Records permissions for a user within a collection.'), + ('UserRole', 'Records roles associated with ecify users.'), + ('Role', 'Stores names, descriptions, and collection information for user-created roles.'), + ('RolePolicy', 'Stores resource and action permissions for user-created roles within a collection.'), + ('LibraryRole', 'Stores names and descriptions of default roles that can be added to any collection.'), + ('LibraryRolePolicy', 'Stores resource and action permissions for library roles within a collection.'), + ('SpDataSet', 'Stores Specify Data Sets created during bulk import using the WorkBench, typically through spreadsheet uploads.') +] + from specifyweb.specify.migration_utils.schema_writer import update_table_schema_config_with_defaults diff --git a/specifyweb/specify/migration_utils/migration_helpers/0004_stratigraphy_age_helper.py b/specifyweb/specify/migration_utils/migration_helpers/0004_stratigraphy_age_helper.py index 79f154130c2..b2a92034ff2 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/0004_stratigraphy_age_helper.py +++ b/specifyweb/specify/migration_utils/migration_helpers/0004_stratigraphy_age_helper.py @@ -1,15 +1,29 @@ - -from specifyweb.specify.migration_utils.sp7_schemaconfig import ( - MIGRATION_0004_FIELDS, - MIGRATION_0004_TABLES, -) +from specifyweb.specify.migration_utils.schema_writer import revert_table_field_schema_config, revert_table_schema_config, update_table_field_schema_config_with_defaults, update_table_schema_config_with_defaults # ########################################## # Used in 0004_stratigraphy_age.py # ########################################## -from specifyweb.specify.migration_utils.schema_writer import revert_table_field_schema_config, revert_table_schema_config, update_table_field_schema_config_with_defaults, update_table_schema_config_with_defaults +MIGRATION_0004_TABLES = [ + ('AbsoluteAge', None), + ('RelativeAge', None), + ('TectonicUnitTreeDef', None), + ('TectonicUnitTreeDefItem', None), + ('TectonicUnit', None), + ('RelativeAgeCitation', None), + ('RelativeAgeAttachment', None), + ('AbsoluteAgeCitation', None), + ('AbsoluteAgeAttachment', None), +] + +MIGRATION_0004_FIELDS = { + 'CollectionObject': ['relativeAges', 'absoluteAges', 'collectionObjectType'], + 'Collection': ['collectionObjectType'], + 'GeographyTreeDef': ['discipline'], + 'GeologicTimePeriodTreeDef': ['discipline'], + 'LithoStratTreeDef': ['discipline'], +} AGETYPE_PICKLIST_NAME = 'AgeType' DEFAULT_AGE_TYPES = [ diff --git a/specifyweb/specify/migration_utils/migration_helpers/0007_schema_config_update_helper.py b/specifyweb/specify/migration_utils/migration_helpers/0007_schema_config_update_helper.py index 93e2f9d53e4..2a307dfc0af 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/0007_schema_config_update_helper.py +++ b/specifyweb/specify/migration_utils/migration_helpers/0007_schema_config_update_helper.py @@ -1,12 +1,14 @@ from specifyweb.specify.migration_utils.schema_writer import revert_table_field_schema_config, update_table_field_schema_config_with_defaults -from specifyweb.specify.migration_utils.sp7_schemaconfig import ( - MIGRATION_0007_FIELDS, -) # ########################################## # Used in 0007_schema_config_update.py # ########################################## +MIGRATION_0007_FIELDS = { + 'StorageTreeDef': ['institution'], + 'CollectionObjectGroup': ['children'] +} + COG_PICKLIST_NAME = 'COGTypes' COGTYPE_FIELD_NAME = 'cogType' SYSTEM_COGTYPE_PICKLIST_NAME = "SystemCOGTypes" diff --git a/specifyweb/specify/migration_utils/migration_helpers/0008_schema_config_update_helper.py b/specifyweb/specify/migration_utils/migration_helpers/0008_schema_config_update_helper.py index eba74b0873e..55b36443ac1 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/0008_schema_config_update_helper.py +++ b/specifyweb/specify/migration_utils/migration_helpers/0008_schema_config_update_helper.py @@ -1,11 +1,13 @@ from specifyweb.specify.migration_utils.schema_writer import revert_table_field_schema_config, update_table_field_schema_config_with_defaults -from specifyweb.specify.migration_utils.sp7_schemaconfig import ( - MIGRATION_0008_FIELDS, -) # ########################################## # Used in 0008_schema_config_update.py # ########################################## +MIGRATION_0008_FIELDS = { + 'AbsoluteAge': ['absoluteAgeCitations'], + 'RelativeAge': ['relativeAgeCitations'] +} + def update_relative_age_fields(apps): Discipline = apps.get_model('specify', 'Discipline') diff --git a/specifyweb/specify/migration_utils/migration_helpers/0012_add_cojo_to_schema_config_helper.py b/specifyweb/specify/migration_utils/migration_helpers/0012_add_cojo_to_schema_config_helper.py index 3ecf105a7e6..2cc63bfbee2 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/0012_add_cojo_to_schema_config_helper.py +++ b/specifyweb/specify/migration_utils/migration_helpers/0012_add_cojo_to_schema_config_helper.py @@ -1,11 +1,14 @@ from specifyweb.specify.migration_utils.schema_writer import revert_table_field_schema_config, update_table_field_schema_config_with_defaults -from specifyweb.specify.migration_utils.sp7_schemaconfig import ( - MIGRATION_0012_FIELDS, -) + # ########################################## # Used in 0012_add_cojo_to_schema_config.py # ########################################## +MIGRATION_0012_FIELDS = { + 'CollectionObjectGroup': ['cojo'], + 'CollectionObject': ['cojo'] +} + def add_cojo_to_schema_config(apps): Discipline = apps.get_model('specify', 'Discipline') for discipline in Discipline.objects.all(): diff --git a/specifyweb/specify/migration_utils/migration_helpers/0013_collectionobjectgroup_parentcog_helper.py b/specifyweb/specify/migration_utils/migration_helpers/0013_collectionobjectgroup_parentcog_helper.py index 88c02aba98b..71639bdb8c8 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/0013_collectionobjectgroup_parentcog_helper.py +++ b/specifyweb/specify/migration_utils/migration_helpers/0013_collectionobjectgroup_parentcog_helper.py @@ -1,10 +1,12 @@ -from specifyweb.specify.migration_utils.sp7_schemaconfig import ( - MIGRATION_0013_FIELDS, -) + # ########################################## # Used in 0013_collectionobjectgroup_parentcog.py # ########################################## +MIGRATION_0013_FIELDS = { + 'CollectionObjectGroup': ['parentCog'] +} + from specifyweb.specify.migration_utils.schema_writer import revert_table_field_schema_config, update_table_field_schema_config_with_defaults diff --git a/specifyweb/specify/migration_utils/migration_helpers/0020_add_tectonicunit_to_pc_in_schema_config_helper.py b/specifyweb/specify/migration_utils/migration_helpers/0020_add_tectonicunit_to_pc_in_schema_config_helper.py index 5d7e3b7df57..d149adb601e 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/0020_add_tectonicunit_to_pc_in_schema_config_helper.py +++ b/specifyweb/specify/migration_utils/migration_helpers/0020_add_tectonicunit_to_pc_in_schema_config_helper.py @@ -1,11 +1,13 @@ from specifyweb.specify.migration_utils.schema_writer import revert_table_field_schema_config, update_table_field_schema_config_with_defaults -from specifyweb.specify.migration_utils.sp7_schemaconfig import ( - MIGRATION_0020_FIELDS, -) + # ########################################## # Used in 0020_add_tectonicunit_to_pc_in_schema_config.py # ########################################## +MIGRATION_0020_FIELDS = { + 'PaleoContext': ['tectonicUnit'], +} + def add_tectonicunit_to_pc_in_schema_config(apps): Discipline = apps.get_model('specify', 'Discipline') for discipline in Discipline.objects.all(): diff --git a/specifyweb/specify/migration_utils/migration_helpers/0021_update_hidden_geo_tables_helper.py b/specifyweb/specify/migration_utils/migration_helpers/0021_update_hidden_geo_tables_helper.py index f91e9735d28..243daee2216 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/0021_update_hidden_geo_tables_helper.py +++ b/specifyweb/specify/migration_utils/migration_helpers/0021_update_hidden_geo_tables_helper.py @@ -1,11 +1,13 @@ from specifyweb.specify.models_utils.model_extras import GEOLOGY_DISCIPLINES, PALEO_DISCIPLINES -from specifyweb.specify.migration_utils.sp7_schemaconfig import ( - MIGRATION_0021_FIELDS, -) + # ########################################## # Used in 0021_update_hidden_geo_tables.py # ########################################## +MIGRATION_0021_FIELDS = { + 'CollectionObject': ['relativeAges', 'absoluteAges', 'cojo'], +} + def fix_hidden_geo_prop(apps, schema_editor=None): Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') diff --git a/specifyweb/specify/migration_utils/migration_helpers/0023_update_schema_config_text_helper.py b/specifyweb/specify/migration_utils/migration_helpers/0023_update_schema_config_text_helper.py index f4d523a4e7d..e91d40e06ac 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/0023_update_schema_config_text_helper.py +++ b/specifyweb/specify/migration_utils/migration_helpers/0023_update_schema_config_text_helper.py @@ -2,10 +2,6 @@ from django.db.models import Count from specifyweb.specify.migration_utils.schema_reader import _fields_without_explicit_hidden_override, _schema_override_hidden_values_for_discipline -from specifyweb.specify.migration_utils.sp7_schemaconfig import ( - MIGRATION_0023_FIELDS, - MIGRATION_0023_FIELDS_BIS, -) logger = logging.getLogger(__name__) @@ -13,6 +9,80 @@ # Used in 0023_update_schema_config_text.py # ########################################## + +MIGRATION_0023_FIELDS = { + 'CollectionObjectGroup': [ + ('guid', 'GUID', 'GUID'), + ('cogType', 'Type', 'Determines the logic Specify should use when managing the children within that COG'), + ('igsn', 'IGSN', 'An International Generic Sample Number (IGSN) provides an unambiguous globally unique and persistent identifier for physical samples.'), + ('cojo', 'Parent COG', 'This connects a Collection Object Group to its parent Collection Object Group, which is used for managing a hierarchy.'), + ('yesno2', 'YesNo2', 'YesNo2'), + ('yesno1', 'YesNo1', 'YesNo1'), + ], + + 'CollectionObjectGroupJoin' : [ + ('yesno2', 'YesNo2', 'YesNo2'), + ('isSubstrate', 'Is Substrate?', 'The Collection Object that serves as the physical base for other items within the COG. This designation is useful for COGs with shared substrates.'), + ('yesno1', 'YesNo1', 'YesNo1'), + ('isPrimary', 'Is Primary?', 'The Collection Object designated as the most significant item in a Consolidated COG. A CO child must be set as “primary” when using a “Consolidated” COG.'), + ('childCo', 'Child Collection Object', 'Child Collection Object'), + ('childCog', 'Child Collection Object Group', 'Child Collection Object Group'), + ('ParentCog', 'Parent', 'Parent Collection Object Group'), + ('yesno3', 'YesNo3', 'YesNo3'), + ], + + 'CollectionObjectGroupType' : [ + ('cogTypeId', 'Collection Object Group Type ID', 'Collection Object Group Type ID'), + ('yesno3', 'YesNo3', 'YesNo3'), + ], + + 'CollectionObjectType': [ + ('collectionObjectTypeId', 'Collection Object Type ID', 'Collection Object Type ID'), + ('taxonTreeDef', 'Taxon Tree', 'The Taxon Tree associated with this Collection Object Type'), + ], + + 'AbsoluteAge': [ + ('yesno2', 'YesNo2', 'YesNo2'), + ], + + 'RelativeAge': [ + ('yesno2', 'YesNo2', 'YesNo2'), + ('yesno1', 'YesNo1', 'YesNo1'), + ], + + 'CollectionObject': [ + ('collectionObjectType', 'Type', 'The type of object, such as a fish, mammal, mineral, rock, or meteorite.'), + ('cojo', 'Parent COG', 'Connects a Collection Object to its Collection Object Group'), + ], + + 'TectonicUnit': [ + ('guid', 'GUID', 'GUID'), + ('yesno1', 'YesNo1', 'YesNo1'), + ('tectonicUnitId', 'Tectonic Unit ID', 'Tectonic Unit Id'), + ('yesno2', 'YesNo2', 'YesNo2'), + ], + + 'TectonicUnitTreeDefItem': [ + ('createdbyagent', 'Created By Agent', 'Created By Agent'), + ('rankId', 'Rank ID', 'Rank Id'), + ] +} + +MIGRATION_0023_FIELDS_BIS = { + 'CollectionObjectGroup': ['guid', ' text3', 'decimal2', 'igsn', 'text2', 'collection', 'description', 'text1', 'cojo', 'decimal1', 'yesno3', 'integer3', 'yesno2', 'collectionObjectGroupId', 'integer2', 'yesno1', 'integer1', 'decimal3', ], + 'CollectionObjectGroupJoin' : ['yesno2', 'text1', 'yesno1', 'integer3', 'integer2', 'integer1', 'text3', 'yesno3', 'precedence', 'text2'], + 'CollectionObjectGroupType' : ['collection'], + 'CollectionObjectType': ['text3', 'collectionObjectTypeId', 'text2', 'text1', 'collection'], + 'AbsoluteAge': ['collectionDate', 'absoluteAgeId', 'date1', 'date2', 'yesno1', 'yesno2', 'agent1', 'number1', 'number2', 'collectionObject', 'absoluteAgeCitations', 'text1', 'text2'], + 'RelativeAge': ['number2', 'yesno2', 'relativeAgeId', 'relativeAgePeriod', 'text1', 'agent1', 'collectionDate', 'text2', 'agent2', 'date1', 'date2', 'collectionObject', 'relativeAgeCitations', 'number1', 'yesno1'], + 'CollectionObject': ['collectionObjectType', 'relativeAges', 'absoluteAges', 'cojo'], + 'AbsoluteAgeCitation': ['collectionMember', 'absoluteAgeCitationId'], + 'RelativeAgeCitation': ['relativeAgeCitationId', 'collectionMember'], + 'TectonicUnit': ['collectionMember', 'nodeNumber', 'yesno1', 'tectonicUnitId', 'number1', 'yesno2', 'number2', 'rankId', 'text1'], + 'TectonicUnitTreeDefItem': ['children', 'rankId', 'parent', 'treeDef', 'treeEntries', 'tectonicUnitTreeDefItemId'], + 'TectonicUnitTreeDef': ['discipline', 'treeEntries', 'tectonicUnitTreeDefId'] +} + def update_schema_config_field_desc(apps, schema_editor=None): Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') diff --git a/specifyweb/specify/migration_utils/migration_helpers/0024_add_uniqueIdentifier_storage_helper.py b/specifyweb/specify/migration_utils/migration_helpers/0024_add_uniqueIdentifier_storage_helper.py index 37d98dff604..d0f956abe82 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/0024_add_uniqueIdentifier_storage_helper.py +++ b/specifyweb/specify/migration_utils/migration_helpers/0024_add_uniqueIdentifier_storage_helper.py @@ -1,11 +1,13 @@ from specifyweb.specify.migration_utils.schema_writer import revert_table_field_schema_config, update_table_field_schema_config_with_defaults -from specifyweb.specify.migration_utils.sp7_schemaconfig import ( - MIGRATION_0024_FIELDS, -) + # ########################################## # Used in 0024_add_uniqueIdentifier_storage.py # ########################################## +MIGRATION_0024_FIELDS = { + 'Storage': ['uniqueIdentifier'], +} + def update_storage_unique_id_fields(apps): Discipline = apps.get_model('specify', 'Discipline') diff --git a/specifyweb/specify/migration_utils/migration_helpers/0027_CO_children_helper.py b/specifyweb/specify/migration_utils/migration_helpers/0027_CO_children_helper.py index fa7e90e001f..139476f66d9 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/0027_CO_children_helper.py +++ b/specifyweb/specify/migration_utils/migration_helpers/0027_CO_children_helper.py @@ -1,12 +1,18 @@ from specifyweb.specify.migration_utils.schema_writer import revert_table_field_schema_config, update_table_field_schema_config_with_defaults -from specifyweb.specify.migration_utils.sp7_schemaconfig import ( - MIGRATION_0027_FIELDS, - MIGRATION_0027_UPDATE_FIELDS, - ) # ########################################## # Used in 0027_CO_children.py # ########################################## +MIGRATION_0027_FIELDS = { + 'CollectionObject': ['parentCO', 'children'], +} +MIGRATION_0027_UPDATE_FIELDS = { + 'CollectionObject': [ + ('parentCO', 'Parent Collection Object', 'Parent CollectionObject'), + ('children', 'Children', 'Children'), + ] +} + def update_co_children_fields(apps): def update_discipline_fields(apps): Discipline = apps.get_model('specify', 'Discipline') diff --git a/specifyweb/specify/migration_utils/migration_helpers/0029_remove_collectionobject_parentco_helper.py b/specifyweb/specify/migration_utils/migration_helpers/0029_remove_collectionobject_parentco_helper.py index 612443d7d22..3b675c5c9f5 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/0029_remove_collectionobject_parentco_helper.py +++ b/specifyweb/specify/migration_utils/migration_helpers/0029_remove_collectionobject_parentco_helper.py @@ -1,12 +1,20 @@ from specifyweb.specify.migration_utils.schema_writer import revert_table_field_schema_config, update_table_field_schema_config_with_defaults -from specifyweb.specify.migration_utils.sp7_schemaconfig import ( - MIGRATION_0029_UPDATE_FIELDS, - MIGRATION_0029_FIELDS, -) + # ########################################## # Used in 0029_remove_collectionobject_parentco.py # ########################################## +MIGRATION_0029_FIELDS = { + 'CollectionObject': ['componentParent', 'components'], +} + +MIGRATION_0029_UPDATE_FIELDS = { + 'CollectionObject': [ + ('componentParent', 'Component Parent', 'Parent of a component Collection Object'), + ('components', 'Components', 'Component parts of a Collection Object'), + ] +} + def remove_collectionobject_parentco(apps): def update_fields(apps): Discipline = apps.get_model('specify', 'Discipline') diff --git a/specifyweb/specify/migration_utils/migration_helpers/0032_add_quantities_gift_helper.py b/specifyweb/specify/migration_utils/migration_helpers/0032_add_quantities_gift_helper.py index dcadd862bb7..8c117942a1d 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/0032_add_quantities_gift_helper.py +++ b/specifyweb/specify/migration_utils/migration_helpers/0032_add_quantities_gift_helper.py @@ -1,12 +1,20 @@ from specifyweb.specify.migration_utils.schema_writer import revert_table_field_schema_config, update_table_field_schema_config_with_defaults -from specifyweb.specify.migration_utils.sp7_schemaconfig import ( - MIGRATION_0032_FIELDS, - MIGRATION_0032_UPDATE_FIELDS, -) + # ########################################## # Used in 0032_add_quantities_gift.py # ########################################## +MIGRATION_0032_FIELDS = { + 'GiftPreparation': ['quantityResolved', 'quantityReturned'], +} + +MIGRATION_0032_UPDATE_FIELDS = { + 'GiftPreparation': [ + ('quantityResolved','Quantity Resolved', 'Number of specimens returned, deaccessioned or otherwise accounted for. (necessary for Lots).'), + ('quantityReturned', 'Quantity Returned', 'Number of specimens returned. (necessary for Lots)'), + ] +} + def add_quantities_gift(apps): def update_fields(apps): Discipline = apps.get_model('specify', 'Discipline') diff --git a/specifyweb/specify/migration_utils/migration_helpers/0033_update_paleo_desc_helper.py b/specifyweb/specify/migration_utils/migration_helpers/0033_update_paleo_desc_helper.py index 5bd058b58e4..b204daf8276 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/0033_update_paleo_desc_helper.py +++ b/specifyweb/specify/migration_utils/migration_helpers/0033_update_paleo_desc_helper.py @@ -1,11 +1,12 @@ -from specifyweb.specify.migration_utils.sp7_schemaconfig import ( - MIGRATION_0033_TABLES, -) # ########################################## # Used in 0033_update_paleo_desc.py # ########################################## +MIGRATION_0033_TABLES = [ + ('Paleocontext', 'Paleo Context provides contextual information on the chronostratigraphy, lithostratigraphy, and biostratigraphy of a collection object, collecting event, or locality.'), +] + def update_paleo_desc(apps): def fix_table_description(apps): Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') diff --git a/specifyweb/specify/migration_utils/migration_helpers/_helper0034_accession_date_fields_helper.py b/specifyweb/specify/migration_utils/migration_helpers/0034_accession_date_fields_helper.py similarity index 79% rename from specifyweb/specify/migration_utils/migration_helpers/_helper0034_accession_date_fields_helper.py rename to specifyweb/specify/migration_utils/migration_helpers/0034_accession_date_fields_helper.py index 3738c658c38..ceec0cac8b4 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/_helper0034_accession_date_fields_helper.py +++ b/specifyweb/specify/migration_utils/migration_helpers/0034_accession_date_fields_helper.py @@ -3,9 +3,22 @@ MIGRATION_0034_FIELDS, MIGRATION_0034_UPDATE_FIELDS, ) -# ########################################## -# Used in 0034_accession_date_fields.py -# ########################################## + +MIGRATION_0034_FIELDS = { + 'Accession': ['dateAccessionedPrecision', 'dateAcknowledgedPrecision', 'dateReceivedPrecision', 'date1', 'date1Precision', 'date2', 'date2Precision'], +} + +MIGRATION_0034_UPDATE_FIELDS = { + 'Accession': [ + ('dateAccessionedPrecision', 'Date Accessioned Precision', 'Date Accessioned Precision'), + ('dateAcknowledgedPrecision', 'Date Acknowledged Precision', 'Date Acknowledged Precision'), + ('dateReceivedPrecision', 'Date Received Precision', 'Date Received Precision'), + ('date1', 'Date 1', 'Date 1'), + ('date1Precision', 'Date 1 Precision', 'Date 1 Precision'), + ('date2', 'Date 2', 'Date 2'), + ('date2Precision', 'Date 2 Precision', 'Date 2 Precision'), + ] +} def update_accession_date_fields(apps): def update_0034_fields(apps): diff --git a/specifyweb/specify/migration_utils/migration_helpers/0035_version_required_helper.py b/specifyweb/specify/migration_utils/migration_helpers/0035_version_required_helper.py index 0d09141f906..39b2504bbd9 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/0035_version_required_helper.py +++ b/specifyweb/specify/migration_utils/migration_helpers/0035_version_required_helper.py @@ -1,11 +1,204 @@ from specifyweb.specify.migration_utils.schema_writer import update_table_field_schema_config_params -from specifyweb.specify.migration_utils.sp7_schemaconfig import ( - MIGRATION_0035_FIELDS, -) + # ########################################## # Used in 0035_version_required.py # ########################################## +MIGRATION_0035_FIELDS = { + 'AbsoluteAge': ['version'], + 'AbsoluteAgeAttachment': ['version'], + 'AbsoluteAgeCitation': ['version'], + 'Accession': ['version'], + 'AccessionAgent': ['version'], + 'AccessionAttachment': ['version'], + 'AccessionAuthorization': ['version'], + 'AccessionCitation': ['version'], + 'Address': ['version'], + 'AddressOfRecord': ['version'], + 'Agent': ['version'], + 'AgentAttachment': ['version'], + 'AgentGeography': ['version'], + 'AgentIdentifier': ['version'], + 'AgentSpecialty': ['version'], + 'AgentVariant': ['version'], + 'Appraisal': ['version'], + 'Attachment': ['version'], + 'AttachmentImageAttribute': ['version'], + 'AttachmentMetadata': ['version'], + 'AttachmentTag': ['version'], + 'AttributeDef': ['version'], + 'Author': ['version'], + 'AutoNumberingScheme': ['version'], + 'Borrow': ['version'], + 'BorrowAgent': ['version'], + 'BorrowAttachment': ['version'], + 'BorrowMaterial': ['version'], + 'BorrowReturnMaterial': ['version'], + 'CollectingEvent': ['version'], + 'CollectingEventAttachment': ['version'], + 'CollectingEventAttr': ['version'], + 'CollectingEventAttribute': ['version'], + 'CollectingEventAuthorization': ['version'], + 'CollectingTrip': ['version'], + 'CollectingTripAttachment': ['version'], + 'CollectingTripAttribute': ['version'], + 'CollectingTripAuthorization': ['version'], + 'Collection': ['version'], + 'CollectionObject': ['version'], + 'CollectionObjectAttachment': ['version'], + 'CollectionObjectAttr': ['version'], + 'CollectionObjectAttribute': ['version'], + 'CollectionObjectCitation': ['version'], + 'CollectionObjectGroup': ['version'], + 'CollectionObjectGroupJoin': ['version'], + 'CollectionObjectGroupType': ['version'], + 'CollectionObjectProperty': ['version'], + 'CollectionObjectType': ['version'], + 'CollectionRelationship': ['version'], + 'CollectionRelType': ['version'], + 'Collector': ['version'], + 'CommonNameTx': ['version'], + 'CommonNameTxCitation': ['version'], + 'ConservDescription': ['version'], + 'ConservDescriptionAttachment': ['version'], + 'ConservEvent': ['version'], + 'ConservEventAttachment': ['version'], + 'Container': ['version'], + 'DataType': ['version'], + 'Deaccession': ['version'], + 'DeaccessionAgent': ['version'], + 'DeaccessionAttachment': ['version'], + 'Determination': ['version'], + 'DeterminationCitation': ['version'], + 'Determiner': ['version'], + 'Discipline': ['version'], + 'Disposal': ['version'], + 'DisposalAgent': ['version'], + 'DisposalAttachment': ['version'], + 'DisposalPreparation': ['version'], + 'Division': ['version'], + 'DnaPrimer': ['version'], + 'DnaSequence': ['version'], + 'DnaSequenceAttachment': ['version'], + 'DnaSequencingRun': ['version'], + 'DnaSequencingRunAttachment': ['version'], + 'DnaSequencingRunCitation': ['version'], + 'ExchangeIn': ['version'], + 'ExchangeInAttachment': ['version'], + 'ExchangeInPrep': ['version'], + 'ExchangeOut': ['version'], + 'ExchangeOutAttachment': ['version'], + 'ExchangeOutPrep': ['version'], + 'Exsiccata': ['version'], + 'ExsiccataItem': ['version'], + 'Extractor': ['version'], + 'FieldNotebook': ['version'], + 'FieldNotebookAttachment': ['version'], + 'FieldNotebookPage': ['version'], + 'FieldNotebookPageAttachment': ['version'], + 'FieldNotebookPageSet': ['version'], + 'FieldNotebookPageSetAttachment': ['version'], + 'FundingAgent': ['version'], + 'GeoCoordDetail': ['version'], + 'Geography': ['version'], + 'GeographyTreeDef': ['version'], + 'GeographyTreeDefItem': ['version'], + 'GeologicTimePeriod': ['version'], + 'GeologicTimePeriodTreeDef': ['version'], + 'GeologicTimePeriodTreeDefItem': ['version'], + 'Gift': ['version'], + 'GiftAgent': ['version'], + 'GiftAttachment': ['version'], + 'GiftPreparation': ['version'], + 'GroupPerson': ['version'], + 'InfoRequest': ['version'], + 'Institution': ['version'], + 'InstitutionNetwork': ['version'], + 'Journal': ['version'], + 'LatLonPolygon': ['version'], + 'LithoStrat': ['version'], + 'LithoStratTreeDef': ['version'], + 'LithoStratTreeDefItem': ['version'], + 'Loan': ['version'], + 'LoanAgent': ['version'], + 'LoanAttachment': ['version'], + 'LoanPreparation': ['version'], + 'LoanReturnPreparation': ['version'], + 'Locality': ['version'], + 'LocalityAttachment': ['version'], + 'LocalityCitation': ['version'], + 'LocalityDetail': ['version'], + 'LocalityNameAlias': ['version'], + 'MaterialSample': ['version'], + 'MorphbankView': ['version'], + 'OtherIdentifier': ['version'], + 'PaleoContext': ['version'], + 'PcrPerson': ['version'], + 'Permit': ['version'], + 'PermitAttachment': ['version'], + 'PickList': ['version'], + 'PickListItem': ['version'], + 'Preparation': ['version'], + 'PreparationAttachment': ['version'], + 'PreparationAttr': ['version'], + 'PreparationAttribute': ['version'], + 'PreparationProperty': ['version'], + 'PrepType': ['version'], + 'Project': ['version'], + 'Recordset': ['version'], + 'ReferenceWork': ['version'], + 'ReferenceWorkAttachment': ['version'], + 'RelativeAge': ['version'], + 'RelativeAgeAttachment': ['version'], + 'RelativeAgeCitation': ['version'], + 'RepositoryAgreement': ['version'], + 'RepositoryAgreementAttachment': ['version'], + 'Shipment': ['version'], + 'SpAppResource': ['version'], + 'SpAppResourceData': ['version'], + 'SpAppResourceDir': ['version'], + 'SpAuditLog': ['version'], + 'SpAuditLogField': ['version'], + 'SpecifyUser': ['version'], + 'SpExportSchema': ['version'], + 'SpExportSchemaItem': ['version'], + 'SpExportSchemaItemMapping': ['version'], + 'SpExportSchemaMapping': ['version'], + 'SpFieldValueDefault': ['version'], + 'SpLocaleContainer': ['version'], + 'SpLocaleContainerItem': ['version'], + 'SpLocaleItemStr': ['version'], + 'SpPrincipal': ['version'], + 'SpQuery': ['version'], + 'SpQueryField': ['version'], + 'SpReport': ['version'], + 'SpSymbiotaInstance': ['version'], + 'SpTaskSemaphore': ['version'], + 'SpVersion': ['version'], + 'SpViewSetObj': ['version'], + 'SpVisualQuery': ['version'], + 'Storage': ['version'], + 'StorageAttachment': ['version'], + 'StorageTreeDef': ['version'], + 'StorageTreeDefItem': ['version'], + 'Taxon': ['version'], + 'TaxonAttachment': ['version'], + 'TaxonAttribute': ['version'], + 'TaxonCitation': ['version'], + 'TaxonTreeDef': ['version'], + 'TaxonTreeDefItem': ['version'], + 'TectonicUnit': ['version'], + 'TectonicUnitTreeDef': ['version'], + 'TectonicUnitTreeDefItem': ['version'], + 'TreatmentEvent': ['version'], + 'TreatmentEventAttachment': ['version'], + 'VoucherRelationship': ['version'], + 'Workbench': ['version'], + 'WorkbenchRowExportedRelationship': ['version'], + 'WorkbenchTemplate': ['version'], + 'WorkbenchTemplateMappingItem': ['version'], +} + def update_version_required(apps): Discipline = apps.get_model('specify', 'Discipline') updated_config_params = { diff --git a/specifyweb/specify/migration_utils/migration_helpers/0039_agent_fields_for_loan_and_gift_helper.py b/specifyweb/specify/migration_utils/migration_helpers/0039_agent_fields_for_loan_and_gift_helper.py index 5d2fcb2c929..720d91c5df7 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/0039_agent_fields_for_loan_and_gift_helper.py +++ b/specifyweb/specify/migration_utils/migration_helpers/0039_agent_fields_for_loan_and_gift_helper.py @@ -1,10 +1,13 @@ -from specifyweb.specify.migration_utils.sp7_schemaconfig import ( - MIGRATION_0038_FIELDS, -) + # ########################################## # Used in 0039_agent_fields_for_loan_and_gift.py # ########################################## +MIGRATION_0039_FIELDS = { + 'Loan': ['agent1', 'agent2', 'agent3', 'agent4', 'agent5'], + 'Gift': ['agent1', 'agent2', 'agent3', 'agent4', 'agent5'], +} + from specifyweb.specify.migration_utils.schema_writer import revert_table_field_schema_config, update_table_field_schema_config_with_defaults @@ -14,11 +17,11 @@ def update_loan_and_gift_agent_fields(apps): "ishidden": True } for discipline in Discipline.objects.all(): - for table, fields in MIGRATION_0038_FIELDS.items(): + for table, fields in MIGRATION_0039_FIELDS.items(): for field_name in fields: update_table_field_schema_config_with_defaults(table, discipline.id, field_name, apps, defaults=field_defaults) def revert_loan_and_gift_agent_fields(apps): - for table, fields in MIGRATION_0038_FIELDS.items(): + for table, fields in MIGRATION_0039_FIELDS.items(): for field_name in fields: revert_table_field_schema_config(table, field_name, apps) \ No newline at end of file diff --git a/specifyweb/specify/migration_utils/migration_helpers/0040_components_helper.py b/specifyweb/specify/migration_utils/migration_helpers/0040_components_helper.py index daba2bab0b1..bcffcfe8a9e 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/0040_components_helper.py +++ b/specifyweb/specify/migration_utils/migration_helpers/0040_components_helper.py @@ -1,15 +1,44 @@ from specifyweb.specify.migration_utils.schema_writer import revert_table_field_schema_config, revert_table_schema_config, update_table_field_schema_config_with_defaults, update_table_schema_config_with_defaults -from specifyweb.specify.migration_utils.sp7_schemaconfig import ( - MIGRATION_0029_UPDATE_FIELDS, - MIGRATION_0040_TABLES, - MIGRATION_0040_FIELDS, - MIGRATION_0040_UPDATE_FIELDS, - MIGRATION_0040_HIDDEN_FIELDS, -) + # ########################################## # Used in 0040_components.py # ########################################## +MIGRATION_0040_TABLES = [ + ('Component', None), +] + +MIGRATION_0040_FIELDS = { + 'CollectionObject': ['components'], + 'Taxon': ['components'], + 'Agent': ['components'], + 'RelativeAge': ['component'], + 'AbsoluteAge': ['component'], +} + +MIGRATION_0040_UPDATE_FIELDS = { + 'Component': [ + ('type', 'Type', 'Determines the valid options for component names.'), + ('name', 'Name', 'The name from a taxon tree corresponding to the chosen type.'), + ('verbatimName', 'Verbatim Name', 'The original name printed or associated with the component.'), + ('role', 'Role', 'Define the role or purpose of the component in the overall collection.'), + ('proportion', 'Proportion', 'Specify the proportion of the component relative to the whole.'), + ('uniqueIdentifier', 'Unique Identifier', 'Uniquely identifies each component record'), + ('catalogNumber', 'Catalog Number', 'User-assigned identifier for the component'), + ], +} + +MIGRATION_0040_HIDDEN_FIELDS = { + 'Component': ['componentid','verbatimname','role', 'proportion','uniqueidentifier','text1','text2','text3', 'text4','text5','text6', 'yesno1','yesno2','yesno3','yesno4','yesno5','yesno6','integer1','integer2','integer3','integer4','integer5','integer6','number1', 'number2','number3','number4','number5','number6','version','collectionobject', 'absoluteages', 'relativeages', 'identifieddate', 'identifiedby'] +} + +MIGRATION_0029_UPDATE_FIELDS = { + 'CollectionObject': [ + ('componentParent', 'Component Parent', 'Parent of a component Collection Object'), + ('components', 'Components', 'Component parts of a Collection Object'), + ] +} + def remove_componentparent_item(apps): revert_table_field_schema_config("CollectionObject", "componentParent", apps) diff --git a/specifyweb/specify/migration_utils/sp7_schemaconfig.py b/specifyweb/specify/migration_utils/sp7_schemaconfig.py deleted file mode 100644 index 7e331639d17..00000000000 --- a/specifyweb/specify/migration_utils/sp7_schemaconfig.py +++ /dev/null @@ -1,440 +0,0 @@ -""" -These represent changes to the SchemaConfig tables -SpLocaleContainer, SpLocaleContainerItem, and SpLocaleItemStr -in migrations from 0002-0016 - -These are needed in this file because there was a bug in migrations which was -later resolved in migration 0016, so both the migration files and the bug-fix -migration file could utilize the same source -""" - -# SpLocalContainer Changes -# of the form (TableName, Table Description) - -MIGRATION_0002_TABLES = [ - ('CollectionObjectType', None), - ('CollectionObjectGroupType', None), - ('CollectionObjectGroup', None), - ('CollectionObjectGroupJoin', None), - ('SpUserExternalId', 'Stores provider identifiers and tokens for users who sign in using Single Sign On (SSO).'), - ('SpAttachmentDataSet', 'Holds attachment data sets.'), - ('UniquenessRule', 'Stores table names in the data model that have uniqueness rules configured for each discipline.'), - ('UniquenessRuleField', 'Stores field names in the data model that have uniqueness rules configured for each discipline, linked to UniquenessRule records.'), - ('Message', 'Stores user notifications.'), - ('SpMerging', 'Tracks record and task IDs of records being merged.'), - ('UserPolicy', 'Records permissions for a user within a collection.'), - ('UserRole', 'Records roles associated with ecify users.'), - ('Role', 'Stores names, descriptions, and collection information for user-created roles.'), - ('RolePolicy', 'Stores resource and action permissions for user-created roles within a collection.'), - ('LibraryRole', 'Stores names and descriptions of default roles that can be added to any collection.'), - ('LibraryRolePolicy', 'Stores resource and action permissions for library roles within a collection.'), - ('SpDataSet', 'Stores Specify Data Sets created during bulk import using the WorkBench, typically through spreadsheet uploads.') -] - -MIGRATION_0004_TABLES = [ - ('AbsoluteAge', None), - ('RelativeAge', None), - ('TectonicUnitTreeDef', None), - ('TectonicUnitTreeDefItem', None), - ('TectonicUnit', None), - ('RelativeAgeCitation', None), - ('RelativeAgeAttachment', None), - ('AbsoluteAgeCitation', None), - ('AbsoluteAgeAttachment', None), -] - -# SpLocaleContainerItem Changes -# of the form {TableName: [...addedFields]} - -MIGRATION_0004_FIELDS = { - 'CollectionObject': ['relativeAges', 'absoluteAges', 'collectionObjectType'], - 'Collection': ['collectionObjectType'], - 'GeographyTreeDef': ['discipline'], - 'GeologicTimePeriodTreeDef': ['discipline'], - 'LithoStratTreeDef': ['discipline'], -} - -MIGRATION_0007_FIELDS = { - 'StorageTreeDef': ['institution'], - 'CollectionObjectGroup': ['children'] -} - -MIGRATION_0008_FIELDS = { - 'AbsoluteAge': ['absoluteAgeCitations'], - 'RelativeAge': ['relativeAgeCitations'] -} - -MIGRATION_0012_FIELDS = { - 'CollectionObjectGroup': ['cojo'], - 'CollectionObject': ['cojo'] -} - -MIGRATION_0013_FIELDS = { - 'CollectionObjectGroup': ['parentCog'] -} - -MIGRATION_0020_FIELDS = { - 'PaleoContext': ['tectonicUnit'], -} - -MIGRATION_0021_FIELDS = { - 'CollectionObject': ['relativeAges', 'absoluteAges', 'cojo'], -} - -MIGRATION_0023_FIELDS = { - 'CollectionObjectGroup': [ - ('guid', 'GUID', 'GUID'), - ('cogType', 'Type', 'Determines the logic Specify should use when managing the children within that COG'), - ('igsn', 'IGSN', 'An International Generic Sample Number (IGSN) provides an unambiguous globally unique and persistent identifier for physical samples.'), - ('cojo', 'Parent COG', 'This connects a Collection Object Group to its parent Collection Object Group, which is used for managing a hierarchy.'), - ('yesno2', 'YesNo2', 'YesNo2'), - ('yesno1', 'YesNo1', 'YesNo1'), - ], - - 'CollectionObjectGroupJoin' : [ - ('yesno2', 'YesNo2', 'YesNo2'), - ('isSubstrate', 'Is Substrate?', 'The Collection Object that serves as the physical base for other items within the COG. This designation is useful for COGs with shared substrates.'), - ('yesno1', 'YesNo1', 'YesNo1'), - ('isPrimary', 'Is Primary?', 'The Collection Object designated as the most significant item in a Consolidated COG. A CO child must be set as “primary” when using a “Consolidated” COG.'), - ('childCo', 'Child Collection Object', 'Child Collection Object'), - ('childCog', 'Child Collection Object Group', 'Child Collection Object Group'), - ('ParentCog', 'Parent', 'Parent Collection Object Group'), - ('yesno3', 'YesNo3', 'YesNo3'), - ], - - 'CollectionObjectGroupType' : [ - ('cogTypeId', 'Collection Object Group Type ID', 'Collection Object Group Type ID'), - ('yesno3', 'YesNo3', 'YesNo3'), - ], - - 'CollectionObjectType': [ - ('collectionObjectTypeId', 'Collection Object Type ID', 'Collection Object Type ID'), - ('taxonTreeDef', 'Taxon Tree', 'The Taxon Tree associated with this Collection Object Type'), - ], - - 'AbsoluteAge': [ - ('yesno2', 'YesNo2', 'YesNo2'), - ], - - 'RelativeAge': [ - ('yesno2', 'YesNo2', 'YesNo2'), - ('yesno1', 'YesNo1', 'YesNo1'), - ], - - 'CollectionObject': [ - ('collectionObjectType', 'Type', 'The type of object, such as a fish, mammal, mineral, rock, or meteorite.'), - ('cojo', 'Parent COG', 'Connects a Collection Object to its Collection Object Group'), - ], - - 'TectonicUnit': [ - ('guid', 'GUID', 'GUID'), - ('yesno1', 'YesNo1', 'YesNo1'), - ('tectonicUnitId', 'Tectonic Unit ID', 'Tectonic Unit Id'), - ('yesno2', 'YesNo2', 'YesNo2'), - ], - - 'TectonicUnitTreeDefItem': [ - ('createdbyagent', 'Created By Agent', 'Created By Agent'), - ('rankId', 'Rank ID', 'Rank Id'), - ] -} - -MIGRATION_0023_FIELDS_BIS = { - 'CollectionObjectGroup': ['guid', ' text3', 'decimal2', 'igsn', 'text2', 'collection', 'description', 'text1', 'cojo', 'decimal1', 'yesno3', 'integer3', 'yesno2', 'collectionObjectGroupId', 'integer2', 'yesno1', 'integer1', 'decimal3', ], - 'CollectionObjectGroupJoin' : ['yesno2', 'text1', 'yesno1', 'integer3', 'integer2', 'integer1', 'text3', 'yesno3', 'precedence', 'text2'], - 'CollectionObjectGroupType' : ['collection'], - 'CollectionObjectType': ['text3', 'collectionObjectTypeId', 'text2', 'text1', 'collection'], - 'AbsoluteAge': ['collectionDate', 'absoluteAgeId', 'date1', 'date2', 'yesno1', 'yesno2', 'agent1', 'number1', 'number2', 'collectionObject', 'absoluteAgeCitations', 'text1', 'text2'], - 'RelativeAge': ['number2', 'yesno2', 'relativeAgeId', 'relativeAgePeriod', 'text1', 'agent1', 'collectionDate', 'text2', 'agent2', 'date1', 'date2', 'collectionObject', 'relativeAgeCitations', 'number1', 'yesno1'], - 'CollectionObject': ['collectionObjectType', 'relativeAges', 'absoluteAges', 'cojo'], - 'AbsoluteAgeCitation': ['collectionMember', 'absoluteAgeCitationId'], - 'RelativeAgeCitation': ['relativeAgeCitationId', 'collectionMember'], - 'TectonicUnit': ['collectionMember', 'nodeNumber', 'yesno1', 'tectonicUnitId', 'number1', 'yesno2', 'number2', 'rankId', 'text1'], - 'TectonicUnitTreeDefItem': ['children', 'rankId', 'parent', 'treeDef', 'treeEntries', 'tectonicUnitTreeDefItemId'], - 'TectonicUnitTreeDef': ['discipline', 'treeEntries', 'tectonicUnitTreeDefId'] -} - -MIGRATION_0024_FIELDS = { - 'Storage': ['uniqueIdentifier'], -} - -MIGRATION_0027_FIELDS = { - 'CollectionObject': ['parentCO', 'children'], -} - -MIGRATION_0027_UPDATE_FIELDS = { - 'CollectionObject': [ - ('parentCO', 'Parent Collection Object', 'Parent CollectionObject'), - ('children', 'Children', 'Children'), - ] -} - -MIGRATION_0029_FIELDS = { - 'CollectionObject': ['componentParent', 'components'], -} - -MIGRATION_0029_UPDATE_FIELDS = { - 'CollectionObject': [ - ('componentParent', 'Component Parent', 'Parent of a component Collection Object'), - ('components', 'Components', 'Component parts of a Collection Object'), - ] -} - -MIGRATION_0032_FIELDS = { - 'GiftPreparation': ['quantityResolved', 'quantityReturned'], -} - -MIGRATION_0032_UPDATE_FIELDS = { - 'GiftPreparation': [ - ('quantityResolved','Quantity Resolved', 'Number of specimens returned, deaccessioned or otherwise accounted for. (necessary for Lots).'), - ('quantityReturned', 'Quantity Returned', 'Number of specimens returned. (necessary for Lots)'), - ] -} - -MIGRATION_0033_TABLES = [ - ('Paleocontext', 'Paleo Context provides contextual information on the chronostratigraphy, lithostratigraphy, and biostratigraphy of a collection object, collecting event, or locality.'), -] - -MIGRATION_0034_FIELDS = { - 'Accession': ['dateAccessionedPrecision', 'dateAcknowledgedPrecision', 'dateReceivedPrecision', 'date1', 'date1Precision', 'date2', 'date2Precision'], -} - -MIGRATION_0034_UPDATE_FIELDS = { - 'Accession': [ - ('dateAccessionedPrecision', 'Date Accessioned Precision', 'Date Accessioned Precision'), - ('dateAcknowledgedPrecision', 'Date Acknowledged Precision', 'Date Acknowledged Precision'), - ('dateReceivedPrecision', 'Date Received Precision', 'Date Received Precision'), - ('date1', 'Date 1', 'Date 1'), - ('date1Precision', 'Date 1 Precision', 'Date 1 Precision'), - ('date2', 'Date 2', 'Date 2'), - ('date2Precision', 'Date 2 Precision', 'Date 2 Precision'), - ] -} - -MIGRATION_0035_FIELDS = { - 'AbsoluteAge': ['version'], - 'AbsoluteAgeAttachment': ['version'], - 'AbsoluteAgeCitation': ['version'], - 'Accession': ['version'], - 'AccessionAgent': ['version'], - 'AccessionAttachment': ['version'], - 'AccessionAuthorization': ['version'], - 'AccessionCitation': ['version'], - 'Address': ['version'], - 'AddressOfRecord': ['version'], - 'Agent': ['version'], - 'AgentAttachment': ['version'], - 'AgentGeography': ['version'], - 'AgentIdentifier': ['version'], - 'AgentSpecialty': ['version'], - 'AgentVariant': ['version'], - 'Appraisal': ['version'], - 'Attachment': ['version'], - 'AttachmentImageAttribute': ['version'], - 'AttachmentMetadata': ['version'], - 'AttachmentTag': ['version'], - 'AttributeDef': ['version'], - 'Author': ['version'], - 'AutoNumberingScheme': ['version'], - 'Borrow': ['version'], - 'BorrowAgent': ['version'], - 'BorrowAttachment': ['version'], - 'BorrowMaterial': ['version'], - 'BorrowReturnMaterial': ['version'], - 'CollectingEvent': ['version'], - 'CollectingEventAttachment': ['version'], - 'CollectingEventAttr': ['version'], - 'CollectingEventAttribute': ['version'], - 'CollectingEventAuthorization': ['version'], - 'CollectingTrip': ['version'], - 'CollectingTripAttachment': ['version'], - 'CollectingTripAttribute': ['version'], - 'CollectingTripAuthorization': ['version'], - 'Collection': ['version'], - 'CollectionObject': ['version'], - 'CollectionObjectAttachment': ['version'], - 'CollectionObjectAttr': ['version'], - 'CollectionObjectAttribute': ['version'], - 'CollectionObjectCitation': ['version'], - 'CollectionObjectGroup': ['version'], - 'CollectionObjectGroupJoin': ['version'], - 'CollectionObjectGroupType': ['version'], - 'CollectionObjectProperty': ['version'], - 'CollectionObjectType': ['version'], - 'CollectionRelationship': ['version'], - 'CollectionRelType': ['version'], - 'Collector': ['version'], - 'CommonNameTx': ['version'], - 'CommonNameTxCitation': ['version'], - 'ConservDescription': ['version'], - 'ConservDescriptionAttachment': ['version'], - 'ConservEvent': ['version'], - 'ConservEventAttachment': ['version'], - 'Container': ['version'], - 'DataType': ['version'], - 'Deaccession': ['version'], - 'DeaccessionAgent': ['version'], - 'DeaccessionAttachment': ['version'], - 'Determination': ['version'], - 'DeterminationCitation': ['version'], - 'Determiner': ['version'], - 'Discipline': ['version'], - 'Disposal': ['version'], - 'DisposalAgent': ['version'], - 'DisposalAttachment': ['version'], - 'DisposalPreparation': ['version'], - 'Division': ['version'], - 'DnaPrimer': ['version'], - 'DnaSequence': ['version'], - 'DnaSequenceAttachment': ['version'], - 'DnaSequencingRun': ['version'], - 'DnaSequencingRunAttachment': ['version'], - 'DnaSequencingRunCitation': ['version'], - 'ExchangeIn': ['version'], - 'ExchangeInAttachment': ['version'], - 'ExchangeInPrep': ['version'], - 'ExchangeOut': ['version'], - 'ExchangeOutAttachment': ['version'], - 'ExchangeOutPrep': ['version'], - 'Exsiccata': ['version'], - 'ExsiccataItem': ['version'], - 'Extractor': ['version'], - 'FieldNotebook': ['version'], - 'FieldNotebookAttachment': ['version'], - 'FieldNotebookPage': ['version'], - 'FieldNotebookPageAttachment': ['version'], - 'FieldNotebookPageSet': ['version'], - 'FieldNotebookPageSetAttachment': ['version'], - 'FundingAgent': ['version'], - 'GeoCoordDetail': ['version'], - 'Geography': ['version'], - 'GeographyTreeDef': ['version'], - 'GeographyTreeDefItem': ['version'], - 'GeologicTimePeriod': ['version'], - 'GeologicTimePeriodTreeDef': ['version'], - 'GeologicTimePeriodTreeDefItem': ['version'], - 'Gift': ['version'], - 'GiftAgent': ['version'], - 'GiftAttachment': ['version'], - 'GiftPreparation': ['version'], - 'GroupPerson': ['version'], - 'InfoRequest': ['version'], - 'Institution': ['version'], - 'InstitutionNetwork': ['version'], - 'Journal': ['version'], - 'LatLonPolygon': ['version'], - 'LithoStrat': ['version'], - 'LithoStratTreeDef': ['version'], - 'LithoStratTreeDefItem': ['version'], - 'Loan': ['version'], - 'LoanAgent': ['version'], - 'LoanAttachment': ['version'], - 'LoanPreparation': ['version'], - 'LoanReturnPreparation': ['version'], - 'Locality': ['version'], - 'LocalityAttachment': ['version'], - 'LocalityCitation': ['version'], - 'LocalityDetail': ['version'], - 'LocalityNameAlias': ['version'], - 'MaterialSample': ['version'], - 'MorphbankView': ['version'], - 'OtherIdentifier': ['version'], - 'PaleoContext': ['version'], - 'PcrPerson': ['version'], - 'Permit': ['version'], - 'PermitAttachment': ['version'], - 'PickList': ['version'], - 'PickListItem': ['version'], - 'Preparation': ['version'], - 'PreparationAttachment': ['version'], - 'PreparationAttr': ['version'], - 'PreparationAttribute': ['version'], - 'PreparationProperty': ['version'], - 'PrepType': ['version'], - 'Project': ['version'], - 'Recordset': ['version'], - 'ReferenceWork': ['version'], - 'ReferenceWorkAttachment': ['version'], - 'RelativeAge': ['version'], - 'RelativeAgeAttachment': ['version'], - 'RelativeAgeCitation': ['version'], - 'RepositoryAgreement': ['version'], - 'RepositoryAgreementAttachment': ['version'], - 'Shipment': ['version'], - 'SpAppResource': ['version'], - 'SpAppResourceData': ['version'], - 'SpAppResourceDir': ['version'], - 'SpAuditLog': ['version'], - 'SpAuditLogField': ['version'], - 'SpecifyUser': ['version'], - 'SpExportSchema': ['version'], - 'SpExportSchemaItem': ['version'], - 'SpExportSchemaItemMapping': ['version'], - 'SpExportSchemaMapping': ['version'], - 'SpFieldValueDefault': ['version'], - 'SpLocaleContainer': ['version'], - 'SpLocaleContainerItem': ['version'], - 'SpLocaleItemStr': ['version'], - 'SpPrincipal': ['version'], - 'SpQuery': ['version'], - 'SpQueryField': ['version'], - 'SpReport': ['version'], - 'SpSymbiotaInstance': ['version'], - 'SpTaskSemaphore': ['version'], - 'SpVersion': ['version'], - 'SpViewSetObj': ['version'], - 'SpVisualQuery': ['version'], - 'Storage': ['version'], - 'StorageAttachment': ['version'], - 'StorageTreeDef': ['version'], - 'StorageTreeDefItem': ['version'], - 'Taxon': ['version'], - 'TaxonAttachment': ['version'], - 'TaxonAttribute': ['version'], - 'TaxonCitation': ['version'], - 'TaxonTreeDef': ['version'], - 'TaxonTreeDefItem': ['version'], - 'TectonicUnit': ['version'], - 'TectonicUnitTreeDef': ['version'], - 'TectonicUnitTreeDefItem': ['version'], - 'TreatmentEvent': ['version'], - 'TreatmentEventAttachment': ['version'], - 'VoucherRelationship': ['version'], - 'Workbench': ['version'], - 'WorkbenchRowExportedRelationship': ['version'], - 'WorkbenchTemplate': ['version'], - 'WorkbenchTemplateMappingItem': ['version'], -} - -MIGRATION_0038_FIELDS = { - 'Loan': ['agent1', 'agent2', 'agent3', 'agent4', 'agent5'], - 'Gift': ['agent1', 'agent2', 'agent3', 'agent4', 'agent5'], -} - -MIGRATION_0040_TABLES = [ - ('Component', None), -] - -MIGRATION_0040_FIELDS = { - 'CollectionObject': ['components'], - 'Taxon': ['components'], - 'Agent': ['components'], - 'RelativeAge': ['component'], - 'AbsoluteAge': ['component'], -} - -MIGRATION_0040_UPDATE_FIELDS = { - 'Component': [ - ('type', 'Type', 'Determines the valid options for component names.'), - ('name', 'Name', 'The name from a taxon tree corresponding to the chosen type.'), - ('verbatimName', 'Verbatim Name', 'The original name printed or associated with the component.'), - ('role', 'Role', 'Define the role or purpose of the component in the overall collection.'), - ('proportion', 'Proportion', 'Specify the proportion of the component relative to the whole.'), - ('uniqueIdentifier', 'Unique Identifier', 'Uniquely identifies each component record'), - ('catalogNumber', 'Catalog Number', 'User-assigned identifier for the component'), - ], -} - -MIGRATION_0040_HIDDEN_FIELDS = { - 'Component': ['componentid','verbatimname','role', 'proportion','uniqueidentifier','text1','text2','text3', 'text4','text5','text6', 'yesno1','yesno2','yesno3','yesno4','yesno5','yesno6','integer1','integer2','integer3','integer4','integer5','integer6','number1', 'number2','number3','number4','number5','number6','version','collectionobject', 'absoluteages', 'relativeages', 'identifieddate', 'identifiedby'] -} From 919267c49696eddd46916a7f52c53cc480447465 Mon Sep 17 00:00:00 2001 From: melton-jason Date: Mon, 15 Jun 2026 10:24:24 -0500 Subject: [PATCH 071/113] feat: delete TectonicUnit tree in reverse migration This is an alternative to only deleting the default TectonicUnit trees/ranks/nodes. The approach on this commit allows earlier reverse migrations (such as 0006_fix_tectonic_tree_fields) to complete regardless of user customizations--because the user customizations are removed --- .../specify/migrations/0009_tectonic_ranks.py | 109 ++---------------- 1 file changed, 11 insertions(+), 98 deletions(-) diff --git a/specifyweb/specify/migrations/0009_tectonic_ranks.py b/specifyweb/specify/migrations/0009_tectonic_ranks.py index 975fb3570b1..a245ef43ccb 100644 --- a/specifyweb/specify/migrations/0009_tectonic_ranks.py +++ b/specifyweb/specify/migrations/0009_tectonic_ranks.py @@ -1,107 +1,28 @@ from django.db import migrations -from django.db.models import Exists, OuterRef, Subquery from specifyweb.specify.migration_utils.tectonic_ranks import ( create_default_tectonic_ranks, create_root_tectonic_node, - DEFAULT_RANKS ) -def revert_create_root_tectonic_node(apps, schema_editor=None): - TectonicUnit = apps.get_model('specify', 'TectonicUnit') - TectonicUnitTreeDefItem = apps.get_model('specify', 'TectonicUnitTreeDefItem') - - # Technically at this point a user could have more than just the root node - # in the tree, so only delete the TectonicUnit nodes which were created - # from create_root_tectonic_node and are alone in the tree - TectonicUnit.objects.annotate( - has_children_nodes=Exists( - TectonicUnit.objects.filter( - parent=OuterRef("pk") - ) - ) - ).filter( - parent__isnull=True, - has_children_nodes=False, - acceptedtectonicunit__isnull=True, - name="Root" - ).delete() - - # Delete the Root TectonicUnit rank if there are no nodes in the tree and - # no children rank reference the Root rank - TectonicUnitTreeDefItem.objects.annotate( - has_nodes=Exists( - TectonicUnit.objects.filter( - definitionitem=OuterRef("pk") - ) - ), - has_child_rank=Exists( - TectonicUnitTreeDefItem.objects.filter( - parent=OuterRef("pk") - ) - ) - ).filter( - has_nodes=False, - has_child_rank=False, - name="Root" - ).delete() - -# REFACTOR: Optimize this -def revert_default_tectonic_ranks(apps, schema_editor=None): +def delete_tectonicunit_trees(apps, schema_editor=None): TectonicUnit = apps.get_model('specify', 'TectonicUnit') TectonicUnitTreeDefItem = apps.get_model('specify', 'TectonicUnitTreeDefItem') TectonicTreeDef = apps.get_model('specify', 'TectonicUnitTreeDef') Discipline = apps.get_model('specify', 'Discipline') - for default_rank in reversed(DEFAULT_RANKS): - tree_def_items = TectonicUnitTreeDefItem.objects.annotate( - has_child_rank=Exists( - TectonicUnitTreeDefItem.objects.filter( - parent=OuterRef("pk") - ) - ) - ).filter( - has_child_rank=False, - name=default_rank["name"], - # rankid=default_rank["rankid"] - ) + TectonicUnit.objects.all().update(parent=None, acceptedtectonicunit=None) + TectonicUnit.objects.delete() - units_to_delete = TectonicUnit.objects.annotate( - has_children_nodes=Exists( - TectonicUnit.objects.filter( - parent=OuterRef("pk") - ) - ) - ).filter( - has_children_nodes=False, - definitionitem__in=tree_def_items - ) - TectonicUnit.objects.filter( - acceptedtectonicunit_id__in=units_to_delete.values_list('pk', flat=True) - ).update( - acceptedtectonicunit=None, - isaccepted=True - ) + TectonicUnitTreeDefItem.objects.all().update(parent=None) + TectonicUnitTreeDefItem.objects.all().delete() - units_to_delete.delete() - tree_def_items.delete() + Discipline.objects.all().update(tectonicunittreedef=None) + TectonicTreeDef.objects.all().delete() - empty_tree_defs = TectonicTreeDef.objects.annotate( - has_ranks=Exists( - TectonicUnitTreeDefItem.objects.filter( - treedef=OuterRef("pk") - ) - ) - ).filter( - has_ranks=False - ) - - Discipline.objects.filter( - tectonicunittreedef_id__in=empty_tree_defs.values_list('pk', flat=True) - ).update( - tectonicunittreedef=None - ) - empty_tree_defs.delete() +def consolidated_python_django_migration_operations(apps, schema_editor): + create_default_tectonic_ranks(apps) + create_root_tectonic_node(apps) class Migration(migrations.Migration): @@ -109,18 +30,10 @@ class Migration(migrations.Migration): ('specify', '0008_ageCitations_fix'), ] - def consolidated_python_django_migration_operations(apps, schema_editor): - create_default_tectonic_ranks(apps) - create_root_tectonic_node(apps) - - def revert_cosolidated_python_django_migration_operations(apps, schema_editor): - revert_create_root_tectonic_node(apps, schema_editor) - revert_default_tectonic_ranks(apps, schema_editor) - operations = [ migrations.RunPython( consolidated_python_django_migration_operations, - revert_cosolidated_python_django_migration_operations, + delete_tectonicunit_trees, atomic=True, ) ] From b1608c259d20ac922214059e7fe8c8a85d14ef68 Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Mon, 15 Jun 2026 17:25:57 +0200 Subject: [PATCH 072/113] Refactor: Import change --- .../backend/workbench/migrations/0007_spdatasetattachment.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specifyweb/backend/workbench/migrations/0007_spdatasetattachment.py b/specifyweb/backend/workbench/migrations/0007_spdatasetattachment.py index 392eb67f7a8..86663bfc1c6 100644 --- a/specifyweb/backend/workbench/migrations/0007_spdatasetattachment.py +++ b/specifyweb/backend/workbench/migrations/0007_spdatasetattachment.py @@ -6,8 +6,8 @@ from django.db import migrations, models import django.db.models.deletion import django.utils.timezone +from specifyweb.specify.migration_utils.schema_writer import revert_table_field_schema_config, revert_table_schema_config, update_table_field_schema_config_with_defaults, update_table_schema_config_with_defaults import specifyweb.specify.models -from specifyweb.specify.migration_utils.migration_helpers import update_table_field_schema_config_with_defaults, update_table_schema_config_with_defaults, revert_table_field_schema_config, revert_table_schema_config MIGRATION_0007_TABLES = [ ('SpDataSetAttachment', 'An attachment temporarily associated with a Specify Data Set for use in a WorkBench upload.') From 8382581305ce107739246f0cedc63ac9136d22b0 Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Mon, 15 Jun 2026 17:56:45 +0200 Subject: [PATCH 073/113] Refactor: Remove usc imports --- ...py => helper_0002_schema_config_update.py} | 0 ...lper.py => helper_0003_cotype_picklist.py} | 0 ...per.py => helper_0004_stratigraphy_age.py} | 0 ...py => helper_0007_schema_config_update.py} | 0 ...py => helper_0008_schema_config_update.py} | 0 ... helper_0012_add_cojo_to_schema_config.py} | 0 ...r_0013_collectionobjectgroup_parentcog.py} | 0 ....py => helper_0015_add_version_to_ages.py} | 0 ...r.py => helper_0017_schemaconfig_fixes.py} | 0 ...er.py => helper_0018_cot_catnum_schema.py} | 0 ...dd_tectonicunit_to_pc_in_schema_config.py} | 0 ...> helper_0021_update_hidden_geo_tables.py} | 0 ... helper_0023_update_schema_config_text.py} | 0 ...lper_0024_add_uniqueIdentifier_storage.py} | 0 ...n_helper.py => helper_0027_CO_children.py} | 0 ..._0029_remove_collectionobject_parentco.py} | 0 ....py => helper_0032_add_quantities_gift.py} | 0 ...er.py => helper_0033_update_paleo_desc.py} | 0 ...y => helper_0034_accession_date_fields.py} | 0 ...per.py => helper_0035_version_required.py} | 0 ...er_0039_agent_fields_for_loan_and_gift.py} | 0 ...ts_helper.py => helper_0040_components.py} | 2 +- ...> helper_0042_discipline_type_picklist.py} | 0 specifyweb/specify/migrations/0002_geo.py | 9 ++++---- .../migrations/0003_cotype_picklist.py | 10 ++++----- .../migrations/0004_stratigraphy_age.py | 9 ++++---- .../migrations/0007_schema_config_update.py | 21 ++++++++++--------- .../migrations/0008_ageCitations_fix.py | 5 +++-- .../0012_add_cojo_to_schema_config.py | 5 +++-- .../0013_collectionobjectgroup_parentcog.py | 5 +++-- .../migrations/0015_add_version_to_ages.py | 5 +++-- .../migrations/0017_schemaconfig_fixes.py | 3 ++- .../migrations/0018_cot_catnum_schema.py | 5 +++-- ...add_tectonicunit_to_pc_in_schema_config.py | 5 +++-- .../0021_update_hidden_geo_tables.py | 3 ++- .../0023_update_schema_config_text.py | 5 +++-- .../0024_add_uniqueIdentifier_storage.py | 5 +++-- .../specify/migrations/0027_CO_children.py | 5 +++-- .../0029_remove_collectionobject_parentco.py | 5 +++-- .../migrations/0032_add_quantities_gift.py | 5 +++-- .../migrations/0033_update_paleo_desc.py | 4 ++-- .../migrations/0034_accession_date_fields.py | 6 +++--- .../migrations/0035_version_required.py | 7 ++++--- .../0039_agent_fields_for_loan_and_gift.py | 5 +++-- .../specify/migrations/0040_components.py | 20 +++++++++--------- .../0042_discipline_type_picklist.py | 11 +++++----- 46 files changed, 92 insertions(+), 73 deletions(-) rename specifyweb/specify/migration_utils/migration_helpers/{0002_schema_config_update_helper.py => helper_0002_schema_config_update.py} (100%) rename specifyweb/specify/migration_utils/migration_helpers/{0003_cotype_picklist_helper.py => helper_0003_cotype_picklist.py} (100%) rename specifyweb/specify/migration_utils/migration_helpers/{0004_stratigraphy_age_helper.py => helper_0004_stratigraphy_age.py} (100%) rename specifyweb/specify/migration_utils/migration_helpers/{0007_schema_config_update_helper.py => helper_0007_schema_config_update.py} (100%) rename specifyweb/specify/migration_utils/migration_helpers/{0008_schema_config_update_helper.py => helper_0008_schema_config_update.py} (100%) rename specifyweb/specify/migration_utils/migration_helpers/{0012_add_cojo_to_schema_config_helper.py => helper_0012_add_cojo_to_schema_config.py} (100%) rename specifyweb/specify/migration_utils/migration_helpers/{0013_collectionobjectgroup_parentcog_helper.py => helper_0013_collectionobjectgroup_parentcog.py} (100%) rename specifyweb/specify/migration_utils/migration_helpers/{0015_add_version_to_ages_helper.py => helper_0015_add_version_to_ages.py} (100%) rename specifyweb/specify/migration_utils/migration_helpers/{0017_schemaconfig_fixes_helper.py => helper_0017_schemaconfig_fixes.py} (100%) rename specifyweb/specify/migration_utils/migration_helpers/{0018_cot_catnum_schema_helper.py => helper_0018_cot_catnum_schema.py} (100%) rename specifyweb/specify/migration_utils/migration_helpers/{0020_add_tectonicunit_to_pc_in_schema_config_helper.py => helper_0020_add_tectonicunit_to_pc_in_schema_config.py} (100%) rename specifyweb/specify/migration_utils/migration_helpers/{0021_update_hidden_geo_tables_helper.py => helper_0021_update_hidden_geo_tables.py} (100%) rename specifyweb/specify/migration_utils/migration_helpers/{0023_update_schema_config_text_helper.py => helper_0023_update_schema_config_text.py} (100%) rename specifyweb/specify/migration_utils/migration_helpers/{0024_add_uniqueIdentifier_storage_helper.py => helper_0024_add_uniqueIdentifier_storage.py} (100%) rename specifyweb/specify/migration_utils/migration_helpers/{0027_CO_children_helper.py => helper_0027_CO_children.py} (100%) rename specifyweb/specify/migration_utils/migration_helpers/{0029_remove_collectionobject_parentco_helper.py => helper_0029_remove_collectionobject_parentco.py} (100%) rename specifyweb/specify/migration_utils/migration_helpers/{0032_add_quantities_gift_helper.py => helper_0032_add_quantities_gift.py} (100%) rename specifyweb/specify/migration_utils/migration_helpers/{0033_update_paleo_desc_helper.py => helper_0033_update_paleo_desc.py} (100%) rename specifyweb/specify/migration_utils/migration_helpers/{0034_accession_date_fields_helper.py => helper_0034_accession_date_fields.py} (100%) rename specifyweb/specify/migration_utils/migration_helpers/{0035_version_required_helper.py => helper_0035_version_required.py} (100%) rename specifyweb/specify/migration_utils/migration_helpers/{0039_agent_fields_for_loan_and_gift_helper.py => helper_0039_agent_fields_for_loan_and_gift.py} (100%) rename specifyweb/specify/migration_utils/migration_helpers/{0040_components_helper.py => helper_0040_components.py} (99%) rename specifyweb/specify/migration_utils/migration_helpers/{0042_discipline_type_picklist_helper.py => helper_0042_discipline_type_picklist.py} (100%) diff --git a/specifyweb/specify/migration_utils/migration_helpers/0002_schema_config_update_helper.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0002_schema_config_update.py similarity index 100% rename from specifyweb/specify/migration_utils/migration_helpers/0002_schema_config_update_helper.py rename to specifyweb/specify/migration_utils/migration_helpers/helper_0002_schema_config_update.py diff --git a/specifyweb/specify/migration_utils/migration_helpers/0003_cotype_picklist_helper.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0003_cotype_picklist.py similarity index 100% rename from specifyweb/specify/migration_utils/migration_helpers/0003_cotype_picklist_helper.py rename to specifyweb/specify/migration_utils/migration_helpers/helper_0003_cotype_picklist.py diff --git a/specifyweb/specify/migration_utils/migration_helpers/0004_stratigraphy_age_helper.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0004_stratigraphy_age.py similarity index 100% rename from specifyweb/specify/migration_utils/migration_helpers/0004_stratigraphy_age_helper.py rename to specifyweb/specify/migration_utils/migration_helpers/helper_0004_stratigraphy_age.py diff --git a/specifyweb/specify/migration_utils/migration_helpers/0007_schema_config_update_helper.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0007_schema_config_update.py similarity index 100% rename from specifyweb/specify/migration_utils/migration_helpers/0007_schema_config_update_helper.py rename to specifyweb/specify/migration_utils/migration_helpers/helper_0007_schema_config_update.py diff --git a/specifyweb/specify/migration_utils/migration_helpers/0008_schema_config_update_helper.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0008_schema_config_update.py similarity index 100% rename from specifyweb/specify/migration_utils/migration_helpers/0008_schema_config_update_helper.py rename to specifyweb/specify/migration_utils/migration_helpers/helper_0008_schema_config_update.py diff --git a/specifyweb/specify/migration_utils/migration_helpers/0012_add_cojo_to_schema_config_helper.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0012_add_cojo_to_schema_config.py similarity index 100% rename from specifyweb/specify/migration_utils/migration_helpers/0012_add_cojo_to_schema_config_helper.py rename to specifyweb/specify/migration_utils/migration_helpers/helper_0012_add_cojo_to_schema_config.py diff --git a/specifyweb/specify/migration_utils/migration_helpers/0013_collectionobjectgroup_parentcog_helper.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0013_collectionobjectgroup_parentcog.py similarity index 100% rename from specifyweb/specify/migration_utils/migration_helpers/0013_collectionobjectgroup_parentcog_helper.py rename to specifyweb/specify/migration_utils/migration_helpers/helper_0013_collectionobjectgroup_parentcog.py diff --git a/specifyweb/specify/migration_utils/migration_helpers/0015_add_version_to_ages_helper.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0015_add_version_to_ages.py similarity index 100% rename from specifyweb/specify/migration_utils/migration_helpers/0015_add_version_to_ages_helper.py rename to specifyweb/specify/migration_utils/migration_helpers/helper_0015_add_version_to_ages.py diff --git a/specifyweb/specify/migration_utils/migration_helpers/0017_schemaconfig_fixes_helper.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0017_schemaconfig_fixes.py similarity index 100% rename from specifyweb/specify/migration_utils/migration_helpers/0017_schemaconfig_fixes_helper.py rename to specifyweb/specify/migration_utils/migration_helpers/helper_0017_schemaconfig_fixes.py diff --git a/specifyweb/specify/migration_utils/migration_helpers/0018_cot_catnum_schema_helper.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0018_cot_catnum_schema.py similarity index 100% rename from specifyweb/specify/migration_utils/migration_helpers/0018_cot_catnum_schema_helper.py rename to specifyweb/specify/migration_utils/migration_helpers/helper_0018_cot_catnum_schema.py diff --git a/specifyweb/specify/migration_utils/migration_helpers/0020_add_tectonicunit_to_pc_in_schema_config_helper.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0020_add_tectonicunit_to_pc_in_schema_config.py similarity index 100% rename from specifyweb/specify/migration_utils/migration_helpers/0020_add_tectonicunit_to_pc_in_schema_config_helper.py rename to specifyweb/specify/migration_utils/migration_helpers/helper_0020_add_tectonicunit_to_pc_in_schema_config.py diff --git a/specifyweb/specify/migration_utils/migration_helpers/0021_update_hidden_geo_tables_helper.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0021_update_hidden_geo_tables.py similarity index 100% rename from specifyweb/specify/migration_utils/migration_helpers/0021_update_hidden_geo_tables_helper.py rename to specifyweb/specify/migration_utils/migration_helpers/helper_0021_update_hidden_geo_tables.py diff --git a/specifyweb/specify/migration_utils/migration_helpers/0023_update_schema_config_text_helper.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0023_update_schema_config_text.py similarity index 100% rename from specifyweb/specify/migration_utils/migration_helpers/0023_update_schema_config_text_helper.py rename to specifyweb/specify/migration_utils/migration_helpers/helper_0023_update_schema_config_text.py diff --git a/specifyweb/specify/migration_utils/migration_helpers/0024_add_uniqueIdentifier_storage_helper.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0024_add_uniqueIdentifier_storage.py similarity index 100% rename from specifyweb/specify/migration_utils/migration_helpers/0024_add_uniqueIdentifier_storage_helper.py rename to specifyweb/specify/migration_utils/migration_helpers/helper_0024_add_uniqueIdentifier_storage.py diff --git a/specifyweb/specify/migration_utils/migration_helpers/0027_CO_children_helper.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0027_CO_children.py similarity index 100% rename from specifyweb/specify/migration_utils/migration_helpers/0027_CO_children_helper.py rename to specifyweb/specify/migration_utils/migration_helpers/helper_0027_CO_children.py diff --git a/specifyweb/specify/migration_utils/migration_helpers/0029_remove_collectionobject_parentco_helper.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0029_remove_collectionobject_parentco.py similarity index 100% rename from specifyweb/specify/migration_utils/migration_helpers/0029_remove_collectionobject_parentco_helper.py rename to specifyweb/specify/migration_utils/migration_helpers/helper_0029_remove_collectionobject_parentco.py diff --git a/specifyweb/specify/migration_utils/migration_helpers/0032_add_quantities_gift_helper.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0032_add_quantities_gift.py similarity index 100% rename from specifyweb/specify/migration_utils/migration_helpers/0032_add_quantities_gift_helper.py rename to specifyweb/specify/migration_utils/migration_helpers/helper_0032_add_quantities_gift.py diff --git a/specifyweb/specify/migration_utils/migration_helpers/0033_update_paleo_desc_helper.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0033_update_paleo_desc.py similarity index 100% rename from specifyweb/specify/migration_utils/migration_helpers/0033_update_paleo_desc_helper.py rename to specifyweb/specify/migration_utils/migration_helpers/helper_0033_update_paleo_desc.py diff --git a/specifyweb/specify/migration_utils/migration_helpers/0034_accession_date_fields_helper.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0034_accession_date_fields.py similarity index 100% rename from specifyweb/specify/migration_utils/migration_helpers/0034_accession_date_fields_helper.py rename to specifyweb/specify/migration_utils/migration_helpers/helper_0034_accession_date_fields.py diff --git a/specifyweb/specify/migration_utils/migration_helpers/0035_version_required_helper.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0035_version_required.py similarity index 100% rename from specifyweb/specify/migration_utils/migration_helpers/0035_version_required_helper.py rename to specifyweb/specify/migration_utils/migration_helpers/helper_0035_version_required.py diff --git a/specifyweb/specify/migration_utils/migration_helpers/0039_agent_fields_for_loan_and_gift_helper.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0039_agent_fields_for_loan_and_gift.py similarity index 100% rename from specifyweb/specify/migration_utils/migration_helpers/0039_agent_fields_for_loan_and_gift_helper.py rename to specifyweb/specify/migration_utils/migration_helpers/helper_0039_agent_fields_for_loan_and_gift.py diff --git a/specifyweb/specify/migration_utils/migration_helpers/0040_components_helper.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0040_components.py similarity index 99% rename from specifyweb/specify/migration_utils/migration_helpers/0040_components_helper.py rename to specifyweb/specify/migration_utils/migration_helpers/helper_0040_components.py index bcffcfe8a9e..93cbfe6f97d 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/0040_components_helper.py +++ b/specifyweb/specify/migration_utils/migration_helpers/helper_0040_components.py @@ -92,7 +92,7 @@ def update_schema_config_field_desc_for_components(apps, schema_editor=None): language="en", ).update(text=new_name) -def update_hidden_prop_for_compoenents(apps, schema_editor=None): +def update_hidden_prop_for_components(apps, schema_editor=None): Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') for table, fields in MIGRATION_0040_FIELDS.items(): diff --git a/specifyweb/specify/migration_utils/migration_helpers/0042_discipline_type_picklist_helper.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0042_discipline_type_picklist.py similarity index 100% rename from specifyweb/specify/migration_utils/migration_helpers/0042_discipline_type_picklist_helper.py rename to specifyweb/specify/migration_utils/migration_helpers/helper_0042_discipline_type_picklist.py diff --git a/specifyweb/specify/migrations/0002_geo.py b/specifyweb/specify/migrations/0002_geo.py index a23f82be669..380f1344aae 100644 --- a/specifyweb/specify/migrations/0002_geo.py +++ b/specifyweb/specify/migrations/0002_geo.py @@ -5,10 +5,11 @@ from django.db import migrations, models # from django.db.models import F import django.utils.timezone +from specifyweb.specify.migration_utils.migration_helpers.helper_0002_schema_config_update import MIGRATION_0002_TABLES, create_geo_table_schema_config_with_defaults +from specifyweb.specify.migration_utils.schema_writer import revert_table_schema_config from specifyweb.specify.models import ( protect_with_blockers ) -from specifyweb.specify.migration_utils.sp7_schemaconfig import MIGRATION_0002_TABLES as SCHEMA_CONFIG_TABLES from specifyweb.specify.migration_utils import migration_helpers as usc from specifyweb.specify.migration_utils.default_cots import ( create_cogtype_type_picklist, @@ -59,8 +60,8 @@ def revert_cogtype_type_picklist(apps): cog_type_picklist.delete() def revert_geo_table_schema_config_with_defaults(apps): - for table, _ in SCHEMA_CONFIG_TABLES: - usc.revert_table_schema_config(table, apps) + for table, _ in MIGRATION_0002_TABLES: + revert_table_schema_config(table, apps) class Migration(migrations.Migration): @@ -73,7 +74,7 @@ class Migration(migrations.Migration): def consolidated_python_django_migration_operations(apps, schema_editor): create_default_collection_types(apps) create_default_discipline_for_tree_defs(apps) - usc.create_geo_table_schema_config_with_defaults(apps) + create_geo_table_schema_config_with_defaults(apps) create_cogtype_type_picklist(apps) set_discipline_for_taxon_treedefs(apps) diff --git a/specifyweb/specify/migrations/0003_cotype_picklist.py b/specifyweb/specify/migrations/0003_cotype_picklist.py index 2d915601df7..67e17cb8639 100644 --- a/specifyweb/specify/migrations/0003_cotype_picklist.py +++ b/specifyweb/specify/migrations/0003_cotype_picklist.py @@ -1,6 +1,6 @@ from django.db import migrations -from specifyweb.specify.migration_utils import migration_helpers as usc from specifyweb.specify.migration_utils.default_cots import create_cotype_picklist, COTYPE_PICKLIST_NAME +from specifyweb.specify.migration_utils.migration_helpers.helper_0003_cotype_picklist import COT_FIELD_NAME, COT_TEXT, create_cotype_splocalecontaineritem def revert_cotype_picklist(apps): Picklist = apps.get_model('specify', 'Picklist') @@ -11,17 +11,17 @@ def revert_cotype_splocalecontaineritem(apps): Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') Splocaleitemstr.objects.filter( - text=usc.COT_TEXT, + text=COT_TEXT, itemdesc__container__name="collectionobject", itemdesc__container__schematype=0, ).delete() Splocaleitemstr.objects.filter( - text=usc.COT_TEXT, + text=COT_TEXT, itemname__container__name="collectionobject", itemname__container__schematype=0, ).delete() Splocalecontaineritem.objects.filter( - name=usc.COT_FIELD_NAME, container__name="collectionobject", container__schematype=0 + name=COT_FIELD_NAME, container__name="collectionobject", container__schematype=0 ).delete() class Migration(migrations.Migration): @@ -31,7 +31,7 @@ class Migration(migrations.Migration): def apply_migration(apps, schema_editor): create_cotype_picklist(apps) - usc.create_cotype_splocalecontaineritem(apps) + create_cotype_splocalecontaineritem(apps) def revert_migration(apps, schema_editor): revert_cotype_picklist(apps) diff --git a/specifyweb/specify/migrations/0004_stratigraphy_age.py b/specifyweb/specify/migrations/0004_stratigraphy_age.py index 76ec91ab8b4..bb6fe7b705c 100644 --- a/specifyweb/specify/migrations/0004_stratigraphy_age.py +++ b/specifyweb/specify/migrations/0004_stratigraphy_age.py @@ -3,6 +3,7 @@ from django.db import migrations, models import django.db.models.deletion import django.utils.timezone +from specifyweb.specify.migration_utils.migration_helpers.helper_0004_stratigraphy_age import AGETYPE_PICKLIST_NAME, create_agetype_picklist, create_strat_table_schema_config_with_defaults, revert_strat_table_schema_config_with_defaults from specifyweb.specify.models import protect_with_blockers from specifyweb.specify.migration_utils import migration_helpers as usc @@ -12,7 +13,7 @@ def revert_agetype_picklist(apps): PicklistItem = apps.get_model('specify', 'Picklistitem') for collection in Collection.objects.all(): - age_type_pick_lists = Picklist.objects.filter(name=usc.AGETYPE_PICKLIST_NAME, collection=collection) + age_type_pick_lists = Picklist.objects.filter(name=AGETYPE_PICKLIST_NAME, collection=collection) for age_type_pick_list in age_type_pick_lists: PicklistItem.objects.filter(picklist=age_type_pick_list).delete() @@ -25,11 +26,11 @@ class Migration(migrations.Migration): ] def consolidated_python_django_migration_operations(apps, schema_editor): - usc.create_strat_table_schema_config_with_defaults(apps) - usc.create_agetype_picklist(apps) + create_strat_table_schema_config_with_defaults(apps) + create_agetype_picklist(apps) def revert_cosolidated_python_django_migration_operations(apps, schema_editor): - usc.revert_strat_table_schema_config_with_defaults(apps) + revert_strat_table_schema_config_with_defaults(apps) revert_agetype_picklist(apps) operations = [ diff --git a/specifyweb/specify/migrations/0007_schema_config_update.py b/specifyweb/specify/migrations/0007_schema_config_update.py index 0dcbd329636..bacc16d1660 100644 --- a/specifyweb/specify/migrations/0007_schema_config_update.py +++ b/specifyweb/specify/migrations/0007_schema_config_update.py @@ -17,6 +17,7 @@ import django.db.models.deletion from specifyweb.specify.migration_utils import migration_helpers as usc +from specifyweb.specify.migration_utils.migration_helpers.helper_0007_schema_config_update import create_cogtype_picklist, revert_cog_type_fields, revert_cogtype_picklist, revert_cogtype_splocalecontaineritem, revert_cogtype_type_splocalecontaineritem, revert_systemcogtypes_picklist, update_cog_type_fields, update_cogtype_splocalecontaineritem, update_cogtype_type_splocalecontaineritem, update_systemcogtypes_picklist class Migration(migrations.Migration): dependencies = [ @@ -24,18 +25,18 @@ class Migration(migrations.Migration): ] def apply_migration(apps, schema_editor): - usc.update_cog_type_fields(apps) - usc.create_cogtype_picklist(apps) - usc.update_cogtype_splocalecontaineritem(apps) - usc.update_systemcogtypes_picklist(apps) - usc.update_cogtype_type_splocalecontaineritem(apps) + update_cog_type_fields(apps) + create_cogtype_picklist(apps) + update_cogtype_splocalecontaineritem(apps) + update_systemcogtypes_picklist(apps) + update_cogtype_type_splocalecontaineritem(apps) def revert_migration(apps, schema_editor): - usc.revert_cog_type_fields(apps) - usc.revert_cogtype_picklist(apps) - usc.revert_cogtype_splocalecontaineritem(apps) - usc.revert_systemcogtypes_picklist(apps) - usc.revert_cogtype_type_splocalecontaineritem(apps) + revert_cog_type_fields(apps) + revert_cogtype_picklist(apps) + revert_cogtype_splocalecontaineritem(apps) + revert_systemcogtypes_picklist(apps) + revert_cogtype_type_splocalecontaineritem(apps) operations = [ migrations.AlterField( diff --git a/specifyweb/specify/migrations/0008_ageCitations_fix.py b/specifyweb/specify/migrations/0008_ageCitations_fix.py index fc1606c1051..ea2d0ee28a4 100644 --- a/specifyweb/specify/migrations/0008_ageCitations_fix.py +++ b/specifyweb/specify/migrations/0008_ageCitations_fix.py @@ -1,6 +1,7 @@ # Generated by Django 3.2.15 on 2024-10-23 14:31 from django.db import migrations, models +from specifyweb.specify.migration_utils.migration_helpers.helper_0008_schema_config_update import revert_relative_age_fields, update_relative_age_fields import specifyweb.specify.models from specifyweb.specify.migration_utils import migration_helpers as usc @@ -12,10 +13,10 @@ class Migration(migrations.Migration): ] def apply_migration(apps, schema_editor): - usc.update_relative_age_fields(apps) + update_relative_age_fields(apps) def revert_migration(apps, schema_editor): - usc.revert_relative_age_fields(apps) + revert_relative_age_fields(apps) operations = [ migrations.AddField( diff --git a/specifyweb/specify/migrations/0012_add_cojo_to_schema_config.py b/specifyweb/specify/migrations/0012_add_cojo_to_schema_config.py index 61e5f04af83..140ed847865 100644 --- a/specifyweb/specify/migrations/0012_add_cojo_to_schema_config.py +++ b/specifyweb/specify/migrations/0012_add_cojo_to_schema_config.py @@ -3,6 +3,7 @@ """ from django.db import migrations from specifyweb.specify.migration_utils import migration_helpers as usc +from specifyweb.specify.migration_utils.migration_helpers.helper_0012_add_cojo_to_schema_config import add_cojo_to_schema_config, remove_cojo_from_schema_config class Migration(migrations.Migration): @@ -11,10 +12,10 @@ class Migration(migrations.Migration): ] def apply_migration(apps, schema_editor): - usc.add_cojo_to_schema_config(apps) + add_cojo_to_schema_config(apps) def revert_migration(apps, schema_editor): - usc.remove_cojo_from_schema_config(apps) + remove_cojo_from_schema_config(apps) operations = [ migrations.RunPython(apply_migration, revert_migration, atomic=True), diff --git a/specifyweb/specify/migrations/0013_collectionobjectgroup_parentcog.py b/specifyweb/specify/migrations/0013_collectionobjectgroup_parentcog.py index b38aecac955..f8c274caab2 100644 --- a/specifyweb/specify/migrations/0013_collectionobjectgroup_parentcog.py +++ b/specifyweb/specify/migrations/0013_collectionobjectgroup_parentcog.py @@ -1,6 +1,7 @@ # Generated by Django 3.2.15 on 2024-11-19 15:29 from django.db import migrations, models +from specifyweb.specify.migration_utils.migration_helpers.helper_0013_collectionobjectgroup_parentcog import revert_update_cog_schema_config, update_cog_schema_config import specifyweb.specify.models from specifyweb.specify.migration_utils import migration_helpers as usc @@ -11,10 +12,10 @@ class Migration(migrations.Migration): ] def apply_migration(apps, schema_editor): - usc.update_cog_schema_config(apps) + update_cog_schema_config(apps) def revert_migration(apps, schema_editor): - usc.revert_update_cog_schema_config(apps) + revert_update_cog_schema_config(apps) operations = [ migrations.RemoveField( diff --git a/specifyweb/specify/migrations/0015_add_version_to_ages.py b/specifyweb/specify/migrations/0015_add_version_to_ages.py index bca41f9c0e6..187f3807bac 100644 --- a/specifyweb/specify/migrations/0015_add_version_to_ages.py +++ b/specifyweb/specify/migrations/0015_add_version_to_ages.py @@ -2,6 +2,7 @@ from django.db import migrations, models from specifyweb.specify.migration_utils import migration_helpers as usc +from specifyweb.specify.migration_utils.migration_helpers.helper_0015_add_version_to_ages import revert_update_age_schema_config, update_age_schema_config class Migration(migrations.Migration): @@ -10,10 +11,10 @@ class Migration(migrations.Migration): ] def apply_migration(apps, schema_editor): - usc.update_age_schema_config(apps) + update_age_schema_config(apps) def revert_migration(apps, schema_editor): - usc.revert_update_age_schema_config(apps) + revert_update_age_schema_config(apps) operations = [ migrations.AddField( diff --git a/specifyweb/specify/migrations/0017_schemaconfig_fixes.py b/specifyweb/specify/migrations/0017_schemaconfig_fixes.py index 764408cf258..13012009364 100644 --- a/specifyweb/specify/migrations/0017_schemaconfig_fixes.py +++ b/specifyweb/specify/migrations/0017_schemaconfig_fixes.py @@ -2,6 +2,7 @@ from django.db import migrations from specifyweb.specify.migration_utils import migration_helpers as usc +from specifyweb.specify.migration_utils.migration_helpers.helper_0017_schemaconfig_fixes import schemaconfig_fixes """ This migration fixes two bugs introduced in other migrations by the functions @@ -20,6 +21,6 @@ class Migration(migrations.Migration): ] operations = [ - migrations.RunPython(usc.schemaconfig_fixes, + migrations.RunPython(schemaconfig_fixes, migrations.RunPython.noop, atomic=True) ] diff --git a/specifyweb/specify/migrations/0018_cot_catnum_schema.py b/specifyweb/specify/migrations/0018_cot_catnum_schema.py index 252b9c916c5..e35fa535efb 100644 --- a/specifyweb/specify/migrations/0018_cot_catnum_schema.py +++ b/specifyweb/specify/migrations/0018_cot_catnum_schema.py @@ -2,6 +2,7 @@ from django.db import migrations from specifyweb.specify.migration_utils import migration_helpers as usc +from specifyweb.specify.migration_utils.migration_helpers.helper_0018_cot_catnum_schema import add_cot_catnum_to_schema, remove_cot_catnum_from_schema class Migration(migrations.Migration): @@ -10,6 +11,6 @@ class Migration(migrations.Migration): ] operations = [ - migrations.RunPython(usc.add_cot_catnum_to_schema, - usc.remove_cot_catnum_from_schema, atomic=True) + migrations.RunPython(add_cot_catnum_to_schema, + remove_cot_catnum_from_schema, atomic=True) ] diff --git a/specifyweb/specify/migrations/0020_add_tectonicunit_to_pc_in_schema_config.py b/specifyweb/specify/migrations/0020_add_tectonicunit_to_pc_in_schema_config.py index 15b97746045..eac2f2ca10f 100644 --- a/specifyweb/specify/migrations/0020_add_tectonicunit_to_pc_in_schema_config.py +++ b/specifyweb/specify/migrations/0020_add_tectonicunit_to_pc_in_schema_config.py @@ -3,6 +3,7 @@ """ from django.db import migrations from specifyweb.specify.migration_utils import migration_helpers as usc +from specifyweb.specify.migration_utils.migration_helpers.helper_0020_add_tectonicunit_to_pc_in_schema_config import add_tectonicunit_to_pc_in_schema_config, remove_tectonicunit_from_pc_schema_config class Migration(migrations.Migration): @@ -11,10 +12,10 @@ class Migration(migrations.Migration): ] def apply_migration(apps, schema_editor): - usc.add_tectonicunit_to_pc_in_schema_config(apps) + add_tectonicunit_to_pc_in_schema_config(apps) def revert_migration(apps, schema_editor): - usc.remove_tectonicunit_from_pc_schema_config(apps) + remove_tectonicunit_from_pc_schema_config(apps) operations = [ migrations.RunPython(apply_migration, revert_migration, atomic=True), diff --git a/specifyweb/specify/migrations/0021_update_hidden_geo_tables.py b/specifyweb/specify/migrations/0021_update_hidden_geo_tables.py index a3d3ec0e0ed..d2a6b4eb846 100644 --- a/specifyweb/specify/migrations/0021_update_hidden_geo_tables.py +++ b/specifyweb/specify/migrations/0021_update_hidden_geo_tables.py @@ -4,6 +4,7 @@ from django.db import migrations from specifyweb.specify.migration_utils import migration_helpers as usc +from specifyweb.specify.migration_utils.migration_helpers.helper_0021_update_hidden_geo_tables import fix_hidden_geo_prop, reverse_fix_hidden_geo_prop from specifyweb.specify.migration_utils.sp7_schemaconfig import MIGRATION_0021_FIELDS as SCHEMA_CONFIG_MOD_TABLE_FIELDS from specifyweb.specify.models_utils.model_extras import GEOLOGY_DISCIPLINES, PALEO_DISCIPLINES @@ -59,6 +60,6 @@ class Migration(migrations.Migration): ] operations = [ - migrations.RunPython(usc.fix_hidden_geo_prop, usc.reverse_fix_hidden_geo_prop, atomic=True) + migrations.RunPython(fix_hidden_geo_prop, reverse_fix_hidden_geo_prop, atomic=True) ] # migrations.RunPython(fix_hidden_geo_prop, reverse_fix_hidden_geo_prop, atomic=True) diff --git a/specifyweb/specify/migrations/0023_update_schema_config_text.py b/specifyweb/specify/migrations/0023_update_schema_config_text.py index f39ce2da439..1040172b898 100644 --- a/specifyweb/specify/migrations/0023_update_schema_config_text.py +++ b/specifyweb/specify/migrations/0023_update_schema_config_text.py @@ -4,6 +4,7 @@ from django.db import migrations from specifyweb.specify.migration_utils import migration_helpers as usc +from specifyweb.specify.migration_utils.migration_helpers.helper_0023_update_schema_config_text import reverse_update_hidden_prop, reverse_update_schema_config_field_desc, update_hidden_prop, update_schema_config_field_desc class Migration(migrations.Migration): dependencies = [ @@ -15,9 +16,9 @@ class Migration(migrations.Migration): operations = [ migrations.RunPython( - usc.update_schema_config_field_desc, usc.reverse_update_schema_config_field_desc, atomic=True + update_schema_config_field_desc, reverse_update_schema_config_field_desc, atomic=True ), migrations.RunPython( - usc.update_hidden_prop, usc.reverse_update_hidden_prop, atomic=True + update_hidden_prop, reverse_update_hidden_prop, atomic=True ), ] \ No newline at end of file diff --git a/specifyweb/specify/migrations/0024_add_uniqueIdentifier_storage.py b/specifyweb/specify/migrations/0024_add_uniqueIdentifier_storage.py index 6c13d3756f8..81c57a31092 100644 --- a/specifyweb/specify/migrations/0024_add_uniqueIdentifier_storage.py +++ b/specifyweb/specify/migrations/0024_add_uniqueIdentifier_storage.py @@ -1,6 +1,7 @@ from django.db import migrations, models from specifyweb.backend.businessrules.uniqueness_rules import DEFAULT_UNIQUENESS_RULES from specifyweb.specify.migration_utils import migration_helpers as usc +from specifyweb.specify.migration_utils.migration_helpers.helper_0024_add_uniqueIdentifier_storage import revert_storage_unique_id_fields, update_storage_unique_id_fields class Migration(migrations.Migration): @@ -9,10 +10,10 @@ class Migration(migrations.Migration): ] def apply_migration(apps, schema_editor): - usc.update_storage_unique_id_fields(apps) + update_storage_unique_id_fields(apps) def revert_migration(apps, schema_editor): - usc.revert_storage_unique_id_fields(apps) + revert_storage_unique_id_fields(apps) operations = [ migrations.AddField( diff --git a/specifyweb/specify/migrations/0027_CO_children.py b/specifyweb/specify/migrations/0027_CO_children.py index fd9ab5eb6cb..6e80473eac2 100644 --- a/specifyweb/specify/migrations/0027_CO_children.py +++ b/specifyweb/specify/migrations/0027_CO_children.py @@ -3,6 +3,7 @@ from django.db import migrations, models import django.db.models.deletion from specifyweb.specify.migration_utils import migration_helpers as usc +from specifyweb.specify.migration_utils.migration_helpers.helper_0027_CO_children import revert_co_children_fields, update_co_children_fields class Migration(migrations.Migration): @@ -11,10 +12,10 @@ class Migration(migrations.Migration): ] def apply_migration(apps, schema_editor): - usc.update_co_children_fields(apps) + update_co_children_fields(apps) def revert_migration(apps, schema_editor): - usc.revert_co_children_fields(apps) + revert_co_children_fields(apps) operations = [ migrations.AddField( diff --git a/specifyweb/specify/migrations/0029_remove_collectionobject_parentco.py b/specifyweb/specify/migrations/0029_remove_collectionobject_parentco.py index 497e40f3e99..758648f1e99 100644 --- a/specifyweb/specify/migrations/0029_remove_collectionobject_parentco.py +++ b/specifyweb/specify/migrations/0029_remove_collectionobject_parentco.py @@ -4,6 +4,7 @@ import django.db.models.deletion from specifyweb.specify.migration_utils import migration_helpers as usc +from specifyweb.specify.migration_utils.migration_helpers.helper_0029_remove_collectionobject_parentco import remove_collectionobject_parentco, revert_remove_collectionobject_parentco class Migration(migrations.Migration): dependencies = [ @@ -11,10 +12,10 @@ class Migration(migrations.Migration): ] def apply_migration(apps, schema_editor): - usc.remove_collectionobject_parentco(apps) + remove_collectionobject_parentco(apps) def revert_migration(apps, schema_editor): - usc.revert_remove_collectionobject_parentco(apps) + revert_remove_collectionobject_parentco(apps) operations = [ migrations.RemoveField( diff --git a/specifyweb/specify/migrations/0032_add_quantities_gift.py b/specifyweb/specify/migrations/0032_add_quantities_gift.py index 5e779710a1f..ab2a9bef797 100644 --- a/specifyweb/specify/migrations/0032_add_quantities_gift.py +++ b/specifyweb/specify/migrations/0032_add_quantities_gift.py @@ -4,6 +4,7 @@ from django.apps import apps as specify_apps from specifyweb.specify.migration_utils import migration_helpers as usc +from specifyweb.specify.migration_utils.migration_helpers.helper_0032_add_quantities_gift import add_quantities_gift, revert_add_quantities_gift class Migration(migrations.Migration): @@ -12,10 +13,10 @@ class Migration(migrations.Migration): ] def apply_migration(apps, schema_editor): - usc.add_quantities_gift(apps) + add_quantities_gift(apps) def revert_migration(apps, schema_editor): - usc.revert_add_quantities_gift(apps) + revert_add_quantities_gift(apps) operations = [ migrations.AddField( diff --git a/specifyweb/specify/migrations/0033_update_paleo_desc.py b/specifyweb/specify/migrations/0033_update_paleo_desc.py index 240e77e3a9b..e7a84af43eb 100644 --- a/specifyweb/specify/migrations/0033_update_paleo_desc.py +++ b/specifyweb/specify/migrations/0033_update_paleo_desc.py @@ -1,8 +1,8 @@ from django.db import migrations -from specifyweb.specify.migration_utils import migration_helpers as usc +from specifyweb.specify.migration_utils.migration_helpers.helper_0033_update_paleo_desc import update_paleo_desc def schemaconfig_fixes(apps, schema_editor): - usc.update_paleo_desc(apps) + update_paleo_desc(apps) class Migration(migrations.Migration): dependencies = [ diff --git a/specifyweb/specify/migrations/0034_accession_date_fields.py b/specifyweb/specify/migrations/0034_accession_date_fields.py index 5bdf85ef066..ae57af89ed2 100644 --- a/specifyweb/specify/migrations/0034_accession_date_fields.py +++ b/specifyweb/specify/migrations/0034_accession_date_fields.py @@ -1,13 +1,13 @@ # Generated by Django 4.2.18 on 2025-06-12 23:10 from django.db import migrations, models -from specifyweb.specify.migration_utils import migration_helpers as usc +from specifyweb.specify.migration_utils.migration_helpers.helper_0034_accession_date_fields import revert_update_accession_date_fields, update_accession_date_fields def apply_migration(apps, schema_editor): - usc.update_accession_date_fields(apps) + update_accession_date_fields(apps) def revert_migration(apps, schema_editor): - usc.revert_update_accession_date_fields(apps) + revert_update_accession_date_fields(apps) class Migration(migrations.Migration): diff --git a/specifyweb/specify/migrations/0035_version_required.py b/specifyweb/specify/migrations/0035_version_required.py index df805f2faa1..539db4a8479 100644 --- a/specifyweb/specify/migrations/0035_version_required.py +++ b/specifyweb/specify/migrations/0035_version_required.py @@ -1,13 +1,14 @@ # Generated by Django 3.2.15 on 2025-04-02 15:28 from django.db import migrations, models -from specifyweb.specify.migration_utils import migration_helpers as usc + +from specifyweb.specify.migration_utils.migration_helpers.helper_0035_version_required import revert_version_required, update_version_required def apply_migration(apps, schema_editor): - usc.update_version_required(apps) + update_version_required(apps) def revert_migration(apps, schema_editor): - usc.revert_version_required(apps) + revert_version_required(apps) class Migration(migrations.Migration): diff --git a/specifyweb/specify/migrations/0039_agent_fields_for_loan_and_gift.py b/specifyweb/specify/migrations/0039_agent_fields_for_loan_and_gift.py index 22825b4361e..e6e1ab28295 100644 --- a/specifyweb/specify/migrations/0039_agent_fields_for_loan_and_gift.py +++ b/specifyweb/specify/migrations/0039_agent_fields_for_loan_and_gift.py @@ -2,15 +2,16 @@ from django.apps import apps as specify_apps from django.db import migrations, models +from specifyweb.specify.migration_utils.migration_helpers.helper_0039_agent_fields_for_loan_and_gift import revert_loan_and_gift_agent_fields, update_loan_and_gift_agent_fields from specifyweb.specify.models import protect_with_blockers from specifyweb.specify.migration_utils import migration_helpers as usc def consolidated_0038_forward(apps, schema_editor): - usc.update_loan_and_gift_agent_fields(apps) + update_loan_and_gift_agent_fields(apps) def consolidated_0038_backward(apps, schema_editor): - usc.revert_loan_and_gift_agent_fields(apps) + revert_loan_and_gift_agent_fields(apps) class Migration(migrations.Migration): diff --git a/specifyweb/specify/migrations/0040_components.py b/specifyweb/specify/migrations/0040_components.py index aa693ec3537..35cd94522ba 100644 --- a/specifyweb/specify/migrations/0040_components.py +++ b/specifyweb/specify/migrations/0040_components.py @@ -3,8 +3,8 @@ from django.db import migrations, models import django.db.models.deletion import django.utils.timezone +from specifyweb.specify.migration_utils.migration_helpers.helper_0040_components import create_cotype_splocalecontaineritem_for_components, create_table_schema_config_with_defaults, hide_component_fields, remove_0029_schema_config_fields, restore_0029_schema_config_fields, reverse_hide_component_fields, revert_table_schema_config_with_defaults, update_hidden_prop_for_components, update_schema_config_field_desc_for_components import specifyweb.specify.models -from specifyweb.specify.migration_utils import migration_helpers as usc from specifyweb.specify.models import protect_with_blockers class Migration(migrations.Migration): @@ -14,17 +14,17 @@ class Migration(migrations.Migration): ] def consolidated_python_django_migration_operations(apps, schema_editor): - usc.remove_0029_schema_config_fields(apps, schema_editor) - usc.create_table_schema_config_with_defaults(apps, schema_editor) - usc.update_schema_config_field_desc_for_components(apps, schema_editor) - usc.update_hidden_prop_for_compoenents(apps, schema_editor) - usc.create_cotype_splocalecontaineritem_for_components(apps) - usc.hide_component_fields(apps, schema_editor) + remove_0029_schema_config_fields(apps, schema_editor) + create_table_schema_config_with_defaults(apps, schema_editor) + update_schema_config_field_desc_for_components(apps, schema_editor) + update_hidden_prop_for_components(apps, schema_editor) + create_cotype_splocalecontaineritem_for_components(apps) + hide_component_fields(apps, schema_editor) def revert_cosolidated_python_django_migration_operations(apps, schema_editor): - usc.restore_0029_schema_config_fields(apps, schema_editor) - usc.revert_table_schema_config_with_defaults(apps, schema_editor) - usc.reverse_hide_component_fields(apps, schema_editor) + restore_0029_schema_config_fields(apps, schema_editor) + revert_table_schema_config_with_defaults(apps, schema_editor) + reverse_hide_component_fields(apps, schema_editor) operations = [ migrations.CreateModel( diff --git a/specifyweb/specify/migrations/0042_discipline_type_picklist.py b/specifyweb/specify/migrations/0042_discipline_type_picklist.py index 0c18ee81c0a..2ccb098476a 100644 --- a/specifyweb/specify/migrations/0042_discipline_type_picklist.py +++ b/specifyweb/specify/migrations/0042_discipline_type_picklist.py @@ -1,5 +1,6 @@ from django.db import migrations -from specifyweb.specify.migration_utils import migration_helpers as usc + +from specifyweb.specify.migration_utils.migration_helpers.helper_0042_discipline_type_picklist import create_discipline_type_picklist, revert_discipline_type_picklist, revert_discipline_type_splocalecontaineritem, update_discipline_type_splocalecontaineritem class Migration(migrations.Migration): dependencies = [ @@ -7,12 +8,12 @@ class Migration(migrations.Migration): ] def apply_migration(apps, schema_editor): - usc.create_discipline_type_picklist(apps) - usc.update_discipline_type_splocalecontaineritem(apps) + create_discipline_type_picklist(apps) + update_discipline_type_splocalecontaineritem(apps) def revert_migration(apps, schema_editor): - usc.revert_discipline_type_picklist(apps) - usc.revert_discipline_type_splocalecontaineritem(apps) + revert_discipline_type_picklist(apps) + revert_discipline_type_splocalecontaineritem(apps) operations = [ migrations.RunPython( From 4de042ba990575eaf87dabebdc291c5e4171ba87 Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Mon, 15 Jun 2026 18:04:18 +0200 Subject: [PATCH 074/113] Cleaning --- specifyweb/specify/migrations/0002_geo.py | 2 +- specifyweb/specify/migrations/0003_cotype_picklist.py | 3 +-- specifyweb/specify/migrations/0004_stratigraphy_age.py | 3 ++- specifyweb/specify/migrations/0007_schema_config_update.py | 3 +-- specifyweb/specify/migrations/0008_ageCitations_fix.py | 2 +- .../specify/migrations/0012_add_cojo_to_schema_config.py | 2 +- .../migrations/0013_collectionobjectgroup_parentcog.py | 2 +- specifyweb/specify/migrations/0015_add_version_to_ages.py | 3 +-- specifyweb/specify/migrations/0017_schemaconfig_fixes.py | 2 +- specifyweb/specify/migrations/0018_cot_catnum_schema.py | 2 +- .../0020_add_tectonicunit_to_pc_in_schema_config.py | 2 +- .../specify/migrations/0021_update_hidden_geo_tables.py | 5 +---- .../specify/migrations/0023_update_schema_config_text.py | 2 +- .../specify/migrations/0024_add_uniqueIdentifier_storage.py | 2 +- specifyweb/specify/migrations/0027_CO_children.py | 2 +- .../migrations/0029_remove_collectionobject_parentco.py | 2 +- specifyweb/specify/migrations/0032_add_quantities_gift.py | 2 +- specifyweb/specify/migrations/0033_update_paleo_desc.py | 2 +- specifyweb/specify/migrations/0034_accession_date_fields.py | 2 +- specifyweb/specify/migrations/0035_version_required.py | 2 +- .../migrations/0039_agent_fields_for_loan_and_gift.py | 4 +--- specifyweb/specify/migrations/0040_components.py | 2 +- .../specify/migrations/0042_discipline_type_picklist.py | 2 +- 23 files changed, 24 insertions(+), 31 deletions(-) diff --git a/specifyweb/specify/migrations/0002_geo.py b/specifyweb/specify/migrations/0002_geo.py index 380f1344aae..1906cc72531 100644 --- a/specifyweb/specify/migrations/0002_geo.py +++ b/specifyweb/specify/migrations/0002_geo.py @@ -5,7 +5,7 @@ from django.db import migrations, models # from django.db.models import F import django.utils.timezone -from specifyweb.specify.migration_utils.migration_helpers.helper_0002_schema_config_update import MIGRATION_0002_TABLES, create_geo_table_schema_config_with_defaults +from specifyweb.specify.migration_utils.migration_helpers import MIGRATION_0002_TABLES, create_geo_table_schema_config_with_defaults from specifyweb.specify.migration_utils.schema_writer import revert_table_schema_config from specifyweb.specify.models import ( protect_with_blockers diff --git a/specifyweb/specify/migrations/0003_cotype_picklist.py b/specifyweb/specify/migrations/0003_cotype_picklist.py index 67e17cb8639..baa329143ac 100644 --- a/specifyweb/specify/migrations/0003_cotype_picklist.py +++ b/specifyweb/specify/migrations/0003_cotype_picklist.py @@ -1,7 +1,6 @@ from django.db import migrations from specifyweb.specify.migration_utils.default_cots import create_cotype_picklist, COTYPE_PICKLIST_NAME -from specifyweb.specify.migration_utils.migration_helpers.helper_0003_cotype_picklist import COT_FIELD_NAME, COT_TEXT, create_cotype_splocalecontaineritem - +from specifyweb.specify.migration_utils.migration_helpers import COT_FIELD_NAME, COT_TEXT, create_cotype_splocalecontaineritem def revert_cotype_picklist(apps): Picklist = apps.get_model('specify', 'Picklist') Picklist.objects.filter(name=COTYPE_PICKLIST_NAME).delete() diff --git a/specifyweb/specify/migrations/0004_stratigraphy_age.py b/specifyweb/specify/migrations/0004_stratigraphy_age.py index bb6fe7b705c..63ce69856c8 100644 --- a/specifyweb/specify/migrations/0004_stratigraphy_age.py +++ b/specifyweb/specify/migrations/0004_stratigraphy_age.py @@ -3,7 +3,8 @@ from django.db import migrations, models import django.db.models.deletion import django.utils.timezone -from specifyweb.specify.migration_utils.migration_helpers.helper_0004_stratigraphy_age import AGETYPE_PICKLIST_NAME, create_agetype_picklist, create_strat_table_schema_config_with_defaults, revert_strat_table_schema_config_with_defaults +from specifyweb.specify.migration_utils.migration_helpers import AGETYPE_PICKLIST_NAME, create_agetype_picklist, create_strat_table_schema_config_with_defaults, revert_strat_table_schema_config_with_defaults + from specifyweb.specify.models import protect_with_blockers from specifyweb.specify.migration_utils import migration_helpers as usc diff --git a/specifyweb/specify/migrations/0007_schema_config_update.py b/specifyweb/specify/migrations/0007_schema_config_update.py index bacc16d1660..447908b47c6 100644 --- a/specifyweb/specify/migrations/0007_schema_config_update.py +++ b/specifyweb/specify/migrations/0007_schema_config_update.py @@ -16,8 +16,7 @@ from django.db import migrations, models import django.db.models.deletion -from specifyweb.specify.migration_utils import migration_helpers as usc -from specifyweb.specify.migration_utils.migration_helpers.helper_0007_schema_config_update import create_cogtype_picklist, revert_cog_type_fields, revert_cogtype_picklist, revert_cogtype_splocalecontaineritem, revert_cogtype_type_splocalecontaineritem, revert_systemcogtypes_picklist, update_cog_type_fields, update_cogtype_splocalecontaineritem, update_cogtype_type_splocalecontaineritem, update_systemcogtypes_picklist +from specifyweb.specify.migration_utils.migration_helpers import create_cogtype_picklist, revert_cog_type_fields, revert_cogtype_picklist, revert_cogtype_splocalecontaineritem, revert_cogtype_type_splocalecontaineritem, revert_systemcogtypes_picklist, update_cog_type_fields, update_cogtype_splocalecontaineritem, update_cogtype_type_splocalecontaineritem, update_systemcogtypes_picklist class Migration(migrations.Migration): dependencies = [ diff --git a/specifyweb/specify/migrations/0008_ageCitations_fix.py b/specifyweb/specify/migrations/0008_ageCitations_fix.py index ea2d0ee28a4..f82df5a4a29 100644 --- a/specifyweb/specify/migrations/0008_ageCitations_fix.py +++ b/specifyweb/specify/migrations/0008_ageCitations_fix.py @@ -1,7 +1,7 @@ # Generated by Django 3.2.15 on 2024-10-23 14:31 from django.db import migrations, models -from specifyweb.specify.migration_utils.migration_helpers.helper_0008_schema_config_update import revert_relative_age_fields, update_relative_age_fields +from specifyweb.specify.migration_utils.migration_helpers import revert_relative_age_fields, update_relative_age_fields import specifyweb.specify.models from specifyweb.specify.migration_utils import migration_helpers as usc diff --git a/specifyweb/specify/migrations/0012_add_cojo_to_schema_config.py b/specifyweb/specify/migrations/0012_add_cojo_to_schema_config.py index 140ed847865..b5bfe90a542 100644 --- a/specifyweb/specify/migrations/0012_add_cojo_to_schema_config.py +++ b/specifyweb/specify/migrations/0012_add_cojo_to_schema_config.py @@ -3,7 +3,7 @@ """ from django.db import migrations from specifyweb.specify.migration_utils import migration_helpers as usc -from specifyweb.specify.migration_utils.migration_helpers.helper_0012_add_cojo_to_schema_config import add_cojo_to_schema_config, remove_cojo_from_schema_config +from specifyweb.specify.migration_utils.migration_helpers import add_cojo_to_schema_config, remove_cojo_from_schema_config class Migration(migrations.Migration): diff --git a/specifyweb/specify/migrations/0013_collectionobjectgroup_parentcog.py b/specifyweb/specify/migrations/0013_collectionobjectgroup_parentcog.py index f8c274caab2..51b3f2ce6b2 100644 --- a/specifyweb/specify/migrations/0013_collectionobjectgroup_parentcog.py +++ b/specifyweb/specify/migrations/0013_collectionobjectgroup_parentcog.py @@ -1,7 +1,7 @@ # Generated by Django 3.2.15 on 2024-11-19 15:29 from django.db import migrations, models -from specifyweb.specify.migration_utils.migration_helpers.helper_0013_collectionobjectgroup_parentcog import revert_update_cog_schema_config, update_cog_schema_config +from specifyweb.specify.migration_utils.migration_helpers import revert_update_cog_schema_config, update_cog_schema_config import specifyweb.specify.models from specifyweb.specify.migration_utils import migration_helpers as usc diff --git a/specifyweb/specify/migrations/0015_add_version_to_ages.py b/specifyweb/specify/migrations/0015_add_version_to_ages.py index 187f3807bac..66dffbfedf6 100644 --- a/specifyweb/specify/migrations/0015_add_version_to_ages.py +++ b/specifyweb/specify/migrations/0015_add_version_to_ages.py @@ -1,8 +1,7 @@ # Generated by Django 3.2.15 on 2024-12-03 18:59 from django.db import migrations, models -from specifyweb.specify.migration_utils import migration_helpers as usc -from specifyweb.specify.migration_utils.migration_helpers.helper_0015_add_version_to_ages import revert_update_age_schema_config, update_age_schema_config +from specifyweb.specify.migration_utils.migration_helpers import revert_update_age_schema_config, update_age_schema_config class Migration(migrations.Migration): diff --git a/specifyweb/specify/migrations/0017_schemaconfig_fixes.py b/specifyweb/specify/migrations/0017_schemaconfig_fixes.py index 13012009364..538288601cc 100644 --- a/specifyweb/specify/migrations/0017_schemaconfig_fixes.py +++ b/specifyweb/specify/migrations/0017_schemaconfig_fixes.py @@ -2,7 +2,7 @@ from django.db import migrations from specifyweb.specify.migration_utils import migration_helpers as usc -from specifyweb.specify.migration_utils.migration_helpers.helper_0017_schemaconfig_fixes import schemaconfig_fixes +from specifyweb.specify.migration_utils.migration_helpers import schemaconfig_fixes """ This migration fixes two bugs introduced in other migrations by the functions diff --git a/specifyweb/specify/migrations/0018_cot_catnum_schema.py b/specifyweb/specify/migrations/0018_cot_catnum_schema.py index e35fa535efb..18102ed098c 100644 --- a/specifyweb/specify/migrations/0018_cot_catnum_schema.py +++ b/specifyweb/specify/migrations/0018_cot_catnum_schema.py @@ -2,7 +2,7 @@ from django.db import migrations from specifyweb.specify.migration_utils import migration_helpers as usc -from specifyweb.specify.migration_utils.migration_helpers.helper_0018_cot_catnum_schema import add_cot_catnum_to_schema, remove_cot_catnum_from_schema +from specifyweb.specify.migration_utils.migration_helpers import add_cot_catnum_to_schema, remove_cot_catnum_from_schema class Migration(migrations.Migration): diff --git a/specifyweb/specify/migrations/0020_add_tectonicunit_to_pc_in_schema_config.py b/specifyweb/specify/migrations/0020_add_tectonicunit_to_pc_in_schema_config.py index eac2f2ca10f..7628f9ef315 100644 --- a/specifyweb/specify/migrations/0020_add_tectonicunit_to_pc_in_schema_config.py +++ b/specifyweb/specify/migrations/0020_add_tectonicunit_to_pc_in_schema_config.py @@ -3,7 +3,7 @@ """ from django.db import migrations from specifyweb.specify.migration_utils import migration_helpers as usc -from specifyweb.specify.migration_utils.migration_helpers.helper_0020_add_tectonicunit_to_pc_in_schema_config import add_tectonicunit_to_pc_in_schema_config, remove_tectonicunit_from_pc_schema_config +from specifyweb.specify.migration_utils.migration_helpers import add_tectonicunit_to_pc_in_schema_config, remove_tectonicunit_from_pc_schema_config class Migration(migrations.Migration): diff --git a/specifyweb/specify/migrations/0021_update_hidden_geo_tables.py b/specifyweb/specify/migrations/0021_update_hidden_geo_tables.py index d2a6b4eb846..138a948b745 100644 --- a/specifyweb/specify/migrations/0021_update_hidden_geo_tables.py +++ b/specifyweb/specify/migrations/0021_update_hidden_geo_tables.py @@ -3,10 +3,7 @@ """ from django.db import migrations -from specifyweb.specify.migration_utils import migration_helpers as usc -from specifyweb.specify.migration_utils.migration_helpers.helper_0021_update_hidden_geo_tables import fix_hidden_geo_prop, reverse_fix_hidden_geo_prop -from specifyweb.specify.migration_utils.sp7_schemaconfig import MIGRATION_0021_FIELDS as SCHEMA_CONFIG_MOD_TABLE_FIELDS -from specifyweb.specify.models_utils.model_extras import GEOLOGY_DISCIPLINES, PALEO_DISCIPLINES +from specifyweb.specify.migration_utils.migration_helpers import fix_hidden_geo_prop, reverse_fix_hidden_geo_prop # def fix_hidden_geo_prop(apps, schema_editor): # Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') diff --git a/specifyweb/specify/migrations/0023_update_schema_config_text.py b/specifyweb/specify/migrations/0023_update_schema_config_text.py index 1040172b898..4a3a4ce0aa0 100644 --- a/specifyweb/specify/migrations/0023_update_schema_config_text.py +++ b/specifyweb/specify/migrations/0023_update_schema_config_text.py @@ -4,7 +4,7 @@ from django.db import migrations from specifyweb.specify.migration_utils import migration_helpers as usc -from specifyweb.specify.migration_utils.migration_helpers.helper_0023_update_schema_config_text import reverse_update_hidden_prop, reverse_update_schema_config_field_desc, update_hidden_prop, update_schema_config_field_desc +from specifyweb.specify.migration_utils.migration_helpers import reverse_update_hidden_prop, reverse_update_schema_config_field_desc, update_hidden_prop, update_schema_config_field_desc class Migration(migrations.Migration): dependencies = [ diff --git a/specifyweb/specify/migrations/0024_add_uniqueIdentifier_storage.py b/specifyweb/specify/migrations/0024_add_uniqueIdentifier_storage.py index 81c57a31092..371053e2c37 100644 --- a/specifyweb/specify/migrations/0024_add_uniqueIdentifier_storage.py +++ b/specifyweb/specify/migrations/0024_add_uniqueIdentifier_storage.py @@ -1,7 +1,7 @@ from django.db import migrations, models from specifyweb.backend.businessrules.uniqueness_rules import DEFAULT_UNIQUENESS_RULES from specifyweb.specify.migration_utils import migration_helpers as usc -from specifyweb.specify.migration_utils.migration_helpers.helper_0024_add_uniqueIdentifier_storage import revert_storage_unique_id_fields, update_storage_unique_id_fields +from specifyweb.specify.migration_utils.migration_helpers import revert_storage_unique_id_fields, update_storage_unique_id_fields class Migration(migrations.Migration): diff --git a/specifyweb/specify/migrations/0027_CO_children.py b/specifyweb/specify/migrations/0027_CO_children.py index 6e80473eac2..2033c23c3f8 100644 --- a/specifyweb/specify/migrations/0027_CO_children.py +++ b/specifyweb/specify/migrations/0027_CO_children.py @@ -3,7 +3,7 @@ from django.db import migrations, models import django.db.models.deletion from specifyweb.specify.migration_utils import migration_helpers as usc -from specifyweb.specify.migration_utils.migration_helpers.helper_0027_CO_children import revert_co_children_fields, update_co_children_fields +from specifyweb.specify.migration_utils.migration_helpers import revert_co_children_fields, update_co_children_fields class Migration(migrations.Migration): diff --git a/specifyweb/specify/migrations/0029_remove_collectionobject_parentco.py b/specifyweb/specify/migrations/0029_remove_collectionobject_parentco.py index 758648f1e99..54eb14b2289 100644 --- a/specifyweb/specify/migrations/0029_remove_collectionobject_parentco.py +++ b/specifyweb/specify/migrations/0029_remove_collectionobject_parentco.py @@ -4,7 +4,7 @@ import django.db.models.deletion from specifyweb.specify.migration_utils import migration_helpers as usc -from specifyweb.specify.migration_utils.migration_helpers.helper_0029_remove_collectionobject_parentco import remove_collectionobject_parentco, revert_remove_collectionobject_parentco +from specifyweb.specify.migration_utils.migration_helpers import remove_collectionobject_parentco, revert_remove_collectionobject_parentco class Migration(migrations.Migration): dependencies = [ diff --git a/specifyweb/specify/migrations/0032_add_quantities_gift.py b/specifyweb/specify/migrations/0032_add_quantities_gift.py index ab2a9bef797..fa9c31c60cb 100644 --- a/specifyweb/specify/migrations/0032_add_quantities_gift.py +++ b/specifyweb/specify/migrations/0032_add_quantities_gift.py @@ -4,7 +4,7 @@ from django.apps import apps as specify_apps from specifyweb.specify.migration_utils import migration_helpers as usc -from specifyweb.specify.migration_utils.migration_helpers.helper_0032_add_quantities_gift import add_quantities_gift, revert_add_quantities_gift +from specifyweb.specify.migration_utils.migration_helpers import add_quantities_gift, revert_add_quantities_gift class Migration(migrations.Migration): diff --git a/specifyweb/specify/migrations/0033_update_paleo_desc.py b/specifyweb/specify/migrations/0033_update_paleo_desc.py index e7a84af43eb..627668f951e 100644 --- a/specifyweb/specify/migrations/0033_update_paleo_desc.py +++ b/specifyweb/specify/migrations/0033_update_paleo_desc.py @@ -1,5 +1,5 @@ from django.db import migrations -from specifyweb.specify.migration_utils.migration_helpers.helper_0033_update_paleo_desc import update_paleo_desc +from specifyweb.specify.migration_utils.migration_helpers import update_paleo_desc def schemaconfig_fixes(apps, schema_editor): update_paleo_desc(apps) diff --git a/specifyweb/specify/migrations/0034_accession_date_fields.py b/specifyweb/specify/migrations/0034_accession_date_fields.py index ae57af89ed2..783ffeffdf8 100644 --- a/specifyweb/specify/migrations/0034_accession_date_fields.py +++ b/specifyweb/specify/migrations/0034_accession_date_fields.py @@ -1,7 +1,7 @@ # Generated by Django 4.2.18 on 2025-06-12 23:10 from django.db import migrations, models -from specifyweb.specify.migration_utils.migration_helpers.helper_0034_accession_date_fields import revert_update_accession_date_fields, update_accession_date_fields +from specifyweb.specify.migration_utils.migration_helpers import revert_update_accession_date_fields, update_accession_date_fields def apply_migration(apps, schema_editor): update_accession_date_fields(apps) diff --git a/specifyweb/specify/migrations/0035_version_required.py b/specifyweb/specify/migrations/0035_version_required.py index 539db4a8479..cbbb68eb80f 100644 --- a/specifyweb/specify/migrations/0035_version_required.py +++ b/specifyweb/specify/migrations/0035_version_required.py @@ -2,7 +2,7 @@ from django.db import migrations, models -from specifyweb.specify.migration_utils.migration_helpers.helper_0035_version_required import revert_version_required, update_version_required +from specifyweb.specify.migration_utils.migration_helpers import revert_version_required, update_version_required def apply_migration(apps, schema_editor): update_version_required(apps) diff --git a/specifyweb/specify/migrations/0039_agent_fields_for_loan_and_gift.py b/specifyweb/specify/migrations/0039_agent_fields_for_loan_and_gift.py index e6e1ab28295..b54aa36c3af 100644 --- a/specifyweb/specify/migrations/0039_agent_fields_for_loan_and_gift.py +++ b/specifyweb/specify/migrations/0039_agent_fields_for_loan_and_gift.py @@ -2,11 +2,9 @@ from django.apps import apps as specify_apps from django.db import migrations, models -from specifyweb.specify.migration_utils.migration_helpers.helper_0039_agent_fields_for_loan_and_gift import revert_loan_and_gift_agent_fields, update_loan_and_gift_agent_fields +from specifyweb.specify.migration_utils.migration_helpers import revert_loan_and_gift_agent_fields, update_loan_and_gift_agent_fields from specifyweb.specify.models import protect_with_blockers -from specifyweb.specify.migration_utils import migration_helpers as usc - def consolidated_0038_forward(apps, schema_editor): update_loan_and_gift_agent_fields(apps) diff --git a/specifyweb/specify/migrations/0040_components.py b/specifyweb/specify/migrations/0040_components.py index 35cd94522ba..4afdb3a342e 100644 --- a/specifyweb/specify/migrations/0040_components.py +++ b/specifyweb/specify/migrations/0040_components.py @@ -3,7 +3,7 @@ from django.db import migrations, models import django.db.models.deletion import django.utils.timezone -from specifyweb.specify.migration_utils.migration_helpers.helper_0040_components import create_cotype_splocalecontaineritem_for_components, create_table_schema_config_with_defaults, hide_component_fields, remove_0029_schema_config_fields, restore_0029_schema_config_fields, reverse_hide_component_fields, revert_table_schema_config_with_defaults, update_hidden_prop_for_components, update_schema_config_field_desc_for_components +from specifyweb.specify.migration_utils.migration_helpers import create_cotype_splocalecontaineritem_for_components, create_table_schema_config_with_defaults, hide_component_fields, remove_0029_schema_config_fields, restore_0029_schema_config_fields, reverse_hide_component_fields, revert_table_schema_config_with_defaults, update_hidden_prop_for_components, update_schema_config_field_desc_for_components import specifyweb.specify.models from specifyweb.specify.models import protect_with_blockers diff --git a/specifyweb/specify/migrations/0042_discipline_type_picklist.py b/specifyweb/specify/migrations/0042_discipline_type_picklist.py index 2ccb098476a..c0abd7f07f5 100644 --- a/specifyweb/specify/migrations/0042_discipline_type_picklist.py +++ b/specifyweb/specify/migrations/0042_discipline_type_picklist.py @@ -1,6 +1,6 @@ from django.db import migrations -from specifyweb.specify.migration_utils.migration_helpers.helper_0042_discipline_type_picklist import create_discipline_type_picklist, revert_discipline_type_picklist, revert_discipline_type_splocalecontaineritem, update_discipline_type_splocalecontaineritem +from specifyweb.specify.migration_utils.migration_helpers import create_discipline_type_picklist, revert_discipline_type_picklist, revert_discipline_type_splocalecontaineritem, update_discipline_type_splocalecontaineritem class Migration(migrations.Migration): dependencies = [ From f9fe47e23ba2d52fd82de03d00f349fe620a7084 Mon Sep 17 00:00:00 2001 From: melton-jason Date: Mon, 15 Jun 2026 12:13:08 -0500 Subject: [PATCH 075/113] fix: use TectonicUnit QuerySet instead of manager --- specifyweb/specify/migrations/0009_tectonic_ranks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specifyweb/specify/migrations/0009_tectonic_ranks.py b/specifyweb/specify/migrations/0009_tectonic_ranks.py index a245ef43ccb..f9201c2c7df 100644 --- a/specifyweb/specify/migrations/0009_tectonic_ranks.py +++ b/specifyweb/specify/migrations/0009_tectonic_ranks.py @@ -12,7 +12,7 @@ def delete_tectonicunit_trees(apps, schema_editor=None): Discipline = apps.get_model('specify', 'Discipline') TectonicUnit.objects.all().update(parent=None, acceptedtectonicunit=None) - TectonicUnit.objects.delete() + TectonicUnit.objects.all().delete() TectonicUnitTreeDefItem.objects.all().update(parent=None) TectonicUnitTreeDefItem.objects.all().delete() From 4a5d1b4b85bce417dfcb676a5982a7740184ee32 Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Tue, 16 Jun 2026 12:10:37 +0200 Subject: [PATCH 076/113] Refactor: Add init file to migration helper app --- .../migration_utils/migration_helpers/__init__.py | 1 + .../helper_0017_schemaconfig_fixes.py | 15 ++++++--------- .../helper_0034_accession_date_fields.py | 4 ---- specifyweb/specify/migrations/0002_geo.py | 2 +- .../specify/migrations/0003_cotype_picklist.py | 2 +- .../specify/migrations/0004_stratigraphy_age.py | 2 +- .../migrations/0007_schema_config_update.py | 2 +- .../specify/migrations/0008_ageCitations_fix.py | 2 +- .../migrations/0012_add_cojo_to_schema_config.py | 2 +- .../0013_collectionobjectgroup_parentcog.py | 2 +- .../migrations/0015_add_version_to_ages.py | 2 +- .../specify/migrations/0017_schemaconfig_fixes.py | 2 +- .../specify/migrations/0018_cot_catnum_schema.py | 2 +- ...020_add_tectonicunit_to_pc_in_schema_config.py | 2 +- .../migrations/0021_update_hidden_geo_tables.py | 2 +- .../migrations/0023_update_schema_config_text.py | 2 +- .../0024_add_uniqueIdentifier_storage.py | 2 +- specifyweb/specify/migrations/0027_CO_children.py | 2 +- .../0029_remove_collectionobject_parentco.py | 2 +- .../migrations/0032_add_quantities_gift.py | 2 +- .../specify/migrations/0033_update_paleo_desc.py | 2 +- .../migrations/0034_accession_date_fields.py | 2 +- .../specify/migrations/0035_version_required.py | 2 +- .../0039_agent_fields_for_loan_and_gift.py | 2 +- specifyweb/specify/migrations/0040_components.py | 2 +- .../migrations/0042_discipline_type_picklist.py | 2 +- 26 files changed, 30 insertions(+), 36 deletions(-) create mode 100644 specifyweb/specify/migration_utils/migration_helpers/__init__.py diff --git a/specifyweb/specify/migration_utils/migration_helpers/__init__.py b/specifyweb/specify/migration_utils/migration_helpers/__init__.py new file mode 100644 index 00000000000..0ea0a5a1f0c --- /dev/null +++ b/specifyweb/specify/migration_utils/migration_helpers/__init__.py @@ -0,0 +1 @@ +# Package initialization file \ No newline at end of file diff --git a/specifyweb/specify/migration_utils/migration_helpers/helper_0017_schemaconfig_fixes.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0017_schemaconfig_fixes.py index 8b0b55b23d5..b1ea296ab20 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/helper_0017_schemaconfig_fixes.py +++ b/specifyweb/specify/migration_utils/migration_helpers/helper_0017_schemaconfig_fixes.py @@ -3,15 +3,12 @@ import logging -from specifyweb.specify.migration_utils.sp7_schemaconfig import ( - MIGRATION_0002_TABLES, - MIGRATION_0004_FIELDS, - MIGRATION_0004_TABLES, - MIGRATION_0007_FIELDS, - MIGRATION_0008_FIELDS, - MIGRATION_0012_FIELDS, - MIGRATION_0013_FIELDS, -) +from specifyweb.specify.migration_utils.migration_helpers.helper_0002_schema_config_update import MIGRATION_0002_TABLES +from specifyweb.specify.migration_utils.migration_helpers.helper_0004_stratigraphy_age import MIGRATION_0004_FIELDS, MIGRATION_0004_TABLES +from specifyweb.specify.migration_utils.migration_helpers.helper_0007_schema_config_update import MIGRATION_0007_FIELDS +from specifyweb.specify.migration_utils.migration_helpers.helper_0008_schema_config_update import MIGRATION_0008_FIELDS +from specifyweb.specify.migration_utils.migration_helpers.helper_0012_add_cojo_to_schema_config import MIGRATION_0012_FIELDS +from specifyweb.specify.migration_utils.migration_helpers.helper_0013_collectionobjectgroup_parentcog import MIGRATION_0013_FIELDS # ########################################## # Used in 0017_schemaconfig_fixes.py # ########################################## diff --git a/specifyweb/specify/migration_utils/migration_helpers/helper_0034_accession_date_fields.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0034_accession_date_fields.py index ceec0cac8b4..8c8d1cbb9d8 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/helper_0034_accession_date_fields.py +++ b/specifyweb/specify/migration_utils/migration_helpers/helper_0034_accession_date_fields.py @@ -1,8 +1,4 @@ from specifyweb.specify.migration_utils.schema_writer import revert_table_field_schema_config, update_table_field_schema_config_with_defaults -from specifyweb.specify.migration_utils.sp7_schemaconfig import ( - MIGRATION_0034_FIELDS, - MIGRATION_0034_UPDATE_FIELDS, -) MIGRATION_0034_FIELDS = { 'Accession': ['dateAccessionedPrecision', 'dateAcknowledgedPrecision', 'dateReceivedPrecision', 'date1', 'date1Precision', 'date2', 'date2Precision'], diff --git a/specifyweb/specify/migrations/0002_geo.py b/specifyweb/specify/migrations/0002_geo.py index 1906cc72531..380f1344aae 100644 --- a/specifyweb/specify/migrations/0002_geo.py +++ b/specifyweb/specify/migrations/0002_geo.py @@ -5,7 +5,7 @@ from django.db import migrations, models # from django.db.models import F import django.utils.timezone -from specifyweb.specify.migration_utils.migration_helpers import MIGRATION_0002_TABLES, create_geo_table_schema_config_with_defaults +from specifyweb.specify.migration_utils.migration_helpers.helper_0002_schema_config_update import MIGRATION_0002_TABLES, create_geo_table_schema_config_with_defaults from specifyweb.specify.migration_utils.schema_writer import revert_table_schema_config from specifyweb.specify.models import ( protect_with_blockers diff --git a/specifyweb/specify/migrations/0003_cotype_picklist.py b/specifyweb/specify/migrations/0003_cotype_picklist.py index baa329143ac..a7c465bf31d 100644 --- a/specifyweb/specify/migrations/0003_cotype_picklist.py +++ b/specifyweb/specify/migrations/0003_cotype_picklist.py @@ -1,6 +1,6 @@ from django.db import migrations from specifyweb.specify.migration_utils.default_cots import create_cotype_picklist, COTYPE_PICKLIST_NAME -from specifyweb.specify.migration_utils.migration_helpers import COT_FIELD_NAME, COT_TEXT, create_cotype_splocalecontaineritem +from specifyweb.specify.migration_utils.migration_helpers.helper_0003_cotype_picklist import COT_FIELD_NAME, COT_TEXT, create_cotype_splocalecontaineritem def revert_cotype_picklist(apps): Picklist = apps.get_model('specify', 'Picklist') Picklist.objects.filter(name=COTYPE_PICKLIST_NAME).delete() diff --git a/specifyweb/specify/migrations/0004_stratigraphy_age.py b/specifyweb/specify/migrations/0004_stratigraphy_age.py index 63ce69856c8..468bc3fa25e 100644 --- a/specifyweb/specify/migrations/0004_stratigraphy_age.py +++ b/specifyweb/specify/migrations/0004_stratigraphy_age.py @@ -3,7 +3,7 @@ from django.db import migrations, models import django.db.models.deletion import django.utils.timezone -from specifyweb.specify.migration_utils.migration_helpers import AGETYPE_PICKLIST_NAME, create_agetype_picklist, create_strat_table_schema_config_with_defaults, revert_strat_table_schema_config_with_defaults +from specifyweb.specify.migration_utils.migration_helpers.helper_0004_stratigraphy_age import AGETYPE_PICKLIST_NAME, create_agetype_picklist, create_strat_table_schema_config_with_defaults, revert_strat_table_schema_config_with_defaults from specifyweb.specify.models import protect_with_blockers from specifyweb.specify.migration_utils import migration_helpers as usc diff --git a/specifyweb/specify/migrations/0007_schema_config_update.py b/specifyweb/specify/migrations/0007_schema_config_update.py index 447908b47c6..db7123e709a 100644 --- a/specifyweb/specify/migrations/0007_schema_config_update.py +++ b/specifyweb/specify/migrations/0007_schema_config_update.py @@ -16,7 +16,7 @@ from django.db import migrations, models import django.db.models.deletion -from specifyweb.specify.migration_utils.migration_helpers import create_cogtype_picklist, revert_cog_type_fields, revert_cogtype_picklist, revert_cogtype_splocalecontaineritem, revert_cogtype_type_splocalecontaineritem, revert_systemcogtypes_picklist, update_cog_type_fields, update_cogtype_splocalecontaineritem, update_cogtype_type_splocalecontaineritem, update_systemcogtypes_picklist +from specifyweb.specify.migration_utils.migration_helpers.helper_0007_schema_config_update import create_cogtype_picklist, revert_cog_type_fields, revert_cogtype_picklist, revert_cogtype_splocalecontaineritem, revert_cogtype_type_splocalecontaineritem, revert_systemcogtypes_picklist, update_cog_type_fields, update_cogtype_splocalecontaineritem, update_cogtype_type_splocalecontaineritem, update_systemcogtypes_picklist class Migration(migrations.Migration): dependencies = [ diff --git a/specifyweb/specify/migrations/0008_ageCitations_fix.py b/specifyweb/specify/migrations/0008_ageCitations_fix.py index f82df5a4a29..ea2d0ee28a4 100644 --- a/specifyweb/specify/migrations/0008_ageCitations_fix.py +++ b/specifyweb/specify/migrations/0008_ageCitations_fix.py @@ -1,7 +1,7 @@ # Generated by Django 3.2.15 on 2024-10-23 14:31 from django.db import migrations, models -from specifyweb.specify.migration_utils.migration_helpers import revert_relative_age_fields, update_relative_age_fields +from specifyweb.specify.migration_utils.migration_helpers.helper_0008_schema_config_update import revert_relative_age_fields, update_relative_age_fields import specifyweb.specify.models from specifyweb.specify.migration_utils import migration_helpers as usc diff --git a/specifyweb/specify/migrations/0012_add_cojo_to_schema_config.py b/specifyweb/specify/migrations/0012_add_cojo_to_schema_config.py index b5bfe90a542..140ed847865 100644 --- a/specifyweb/specify/migrations/0012_add_cojo_to_schema_config.py +++ b/specifyweb/specify/migrations/0012_add_cojo_to_schema_config.py @@ -3,7 +3,7 @@ """ from django.db import migrations from specifyweb.specify.migration_utils import migration_helpers as usc -from specifyweb.specify.migration_utils.migration_helpers import add_cojo_to_schema_config, remove_cojo_from_schema_config +from specifyweb.specify.migration_utils.migration_helpers.helper_0012_add_cojo_to_schema_config import add_cojo_to_schema_config, remove_cojo_from_schema_config class Migration(migrations.Migration): diff --git a/specifyweb/specify/migrations/0013_collectionobjectgroup_parentcog.py b/specifyweb/specify/migrations/0013_collectionobjectgroup_parentcog.py index 51b3f2ce6b2..f8c274caab2 100644 --- a/specifyweb/specify/migrations/0013_collectionobjectgroup_parentcog.py +++ b/specifyweb/specify/migrations/0013_collectionobjectgroup_parentcog.py @@ -1,7 +1,7 @@ # Generated by Django 3.2.15 on 2024-11-19 15:29 from django.db import migrations, models -from specifyweb.specify.migration_utils.migration_helpers import revert_update_cog_schema_config, update_cog_schema_config +from specifyweb.specify.migration_utils.migration_helpers.helper_0013_collectionobjectgroup_parentcog import revert_update_cog_schema_config, update_cog_schema_config import specifyweb.specify.models from specifyweb.specify.migration_utils import migration_helpers as usc diff --git a/specifyweb/specify/migrations/0015_add_version_to_ages.py b/specifyweb/specify/migrations/0015_add_version_to_ages.py index 66dffbfedf6..e656ace03a1 100644 --- a/specifyweb/specify/migrations/0015_add_version_to_ages.py +++ b/specifyweb/specify/migrations/0015_add_version_to_ages.py @@ -1,7 +1,7 @@ # Generated by Django 3.2.15 on 2024-12-03 18:59 from django.db import migrations, models -from specifyweb.specify.migration_utils.migration_helpers import revert_update_age_schema_config, update_age_schema_config +from specifyweb.specify.migration_utils.migration_helpers.helper_0015_add_version_to_ages import revert_update_age_schema_config, update_age_schema_config class Migration(migrations.Migration): diff --git a/specifyweb/specify/migrations/0017_schemaconfig_fixes.py b/specifyweb/specify/migrations/0017_schemaconfig_fixes.py index 538288601cc..13012009364 100644 --- a/specifyweb/specify/migrations/0017_schemaconfig_fixes.py +++ b/specifyweb/specify/migrations/0017_schemaconfig_fixes.py @@ -2,7 +2,7 @@ from django.db import migrations from specifyweb.specify.migration_utils import migration_helpers as usc -from specifyweb.specify.migration_utils.migration_helpers import schemaconfig_fixes +from specifyweb.specify.migration_utils.migration_helpers.helper_0017_schemaconfig_fixes import schemaconfig_fixes """ This migration fixes two bugs introduced in other migrations by the functions diff --git a/specifyweb/specify/migrations/0018_cot_catnum_schema.py b/specifyweb/specify/migrations/0018_cot_catnum_schema.py index 18102ed098c..e35fa535efb 100644 --- a/specifyweb/specify/migrations/0018_cot_catnum_schema.py +++ b/specifyweb/specify/migrations/0018_cot_catnum_schema.py @@ -2,7 +2,7 @@ from django.db import migrations from specifyweb.specify.migration_utils import migration_helpers as usc -from specifyweb.specify.migration_utils.migration_helpers import add_cot_catnum_to_schema, remove_cot_catnum_from_schema +from specifyweb.specify.migration_utils.migration_helpers.helper_0018_cot_catnum_schema import add_cot_catnum_to_schema, remove_cot_catnum_from_schema class Migration(migrations.Migration): diff --git a/specifyweb/specify/migrations/0020_add_tectonicunit_to_pc_in_schema_config.py b/specifyweb/specify/migrations/0020_add_tectonicunit_to_pc_in_schema_config.py index 7628f9ef315..eac2f2ca10f 100644 --- a/specifyweb/specify/migrations/0020_add_tectonicunit_to_pc_in_schema_config.py +++ b/specifyweb/specify/migrations/0020_add_tectonicunit_to_pc_in_schema_config.py @@ -3,7 +3,7 @@ """ from django.db import migrations from specifyweb.specify.migration_utils import migration_helpers as usc -from specifyweb.specify.migration_utils.migration_helpers import add_tectonicunit_to_pc_in_schema_config, remove_tectonicunit_from_pc_schema_config +from specifyweb.specify.migration_utils.migration_helpers.helper_0020_add_tectonicunit_to_pc_in_schema_config import add_tectonicunit_to_pc_in_schema_config, remove_tectonicunit_from_pc_schema_config class Migration(migrations.Migration): diff --git a/specifyweb/specify/migrations/0021_update_hidden_geo_tables.py b/specifyweb/specify/migrations/0021_update_hidden_geo_tables.py index 138a948b745..81bd1efe945 100644 --- a/specifyweb/specify/migrations/0021_update_hidden_geo_tables.py +++ b/specifyweb/specify/migrations/0021_update_hidden_geo_tables.py @@ -3,7 +3,7 @@ """ from django.db import migrations -from specifyweb.specify.migration_utils.migration_helpers import fix_hidden_geo_prop, reverse_fix_hidden_geo_prop +from specifyweb.specify.migration_utils.migration_helpers.helper_0021_update_hidden_geo_tables import fix_hidden_geo_prop, reverse_fix_hidden_geo_prop # def fix_hidden_geo_prop(apps, schema_editor): # Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') diff --git a/specifyweb/specify/migrations/0023_update_schema_config_text.py b/specifyweb/specify/migrations/0023_update_schema_config_text.py index 4a3a4ce0aa0..1040172b898 100644 --- a/specifyweb/specify/migrations/0023_update_schema_config_text.py +++ b/specifyweb/specify/migrations/0023_update_schema_config_text.py @@ -4,7 +4,7 @@ from django.db import migrations from specifyweb.specify.migration_utils import migration_helpers as usc -from specifyweb.specify.migration_utils.migration_helpers import reverse_update_hidden_prop, reverse_update_schema_config_field_desc, update_hidden_prop, update_schema_config_field_desc +from specifyweb.specify.migration_utils.migration_helpers.helper_0023_update_schema_config_text import reverse_update_hidden_prop, reverse_update_schema_config_field_desc, update_hidden_prop, update_schema_config_field_desc class Migration(migrations.Migration): dependencies = [ diff --git a/specifyweb/specify/migrations/0024_add_uniqueIdentifier_storage.py b/specifyweb/specify/migrations/0024_add_uniqueIdentifier_storage.py index 371053e2c37..81c57a31092 100644 --- a/specifyweb/specify/migrations/0024_add_uniqueIdentifier_storage.py +++ b/specifyweb/specify/migrations/0024_add_uniqueIdentifier_storage.py @@ -1,7 +1,7 @@ from django.db import migrations, models from specifyweb.backend.businessrules.uniqueness_rules import DEFAULT_UNIQUENESS_RULES from specifyweb.specify.migration_utils import migration_helpers as usc -from specifyweb.specify.migration_utils.migration_helpers import revert_storage_unique_id_fields, update_storage_unique_id_fields +from specifyweb.specify.migration_utils.migration_helpers.helper_0024_add_uniqueIdentifier_storage import revert_storage_unique_id_fields, update_storage_unique_id_fields class Migration(migrations.Migration): diff --git a/specifyweb/specify/migrations/0027_CO_children.py b/specifyweb/specify/migrations/0027_CO_children.py index 2033c23c3f8..6e80473eac2 100644 --- a/specifyweb/specify/migrations/0027_CO_children.py +++ b/specifyweb/specify/migrations/0027_CO_children.py @@ -3,7 +3,7 @@ from django.db import migrations, models import django.db.models.deletion from specifyweb.specify.migration_utils import migration_helpers as usc -from specifyweb.specify.migration_utils.migration_helpers import revert_co_children_fields, update_co_children_fields +from specifyweb.specify.migration_utils.migration_helpers.helper_0027_CO_children import revert_co_children_fields, update_co_children_fields class Migration(migrations.Migration): diff --git a/specifyweb/specify/migrations/0029_remove_collectionobject_parentco.py b/specifyweb/specify/migrations/0029_remove_collectionobject_parentco.py index 54eb14b2289..758648f1e99 100644 --- a/specifyweb/specify/migrations/0029_remove_collectionobject_parentco.py +++ b/specifyweb/specify/migrations/0029_remove_collectionobject_parentco.py @@ -4,7 +4,7 @@ import django.db.models.deletion from specifyweb.specify.migration_utils import migration_helpers as usc -from specifyweb.specify.migration_utils.migration_helpers import remove_collectionobject_parentco, revert_remove_collectionobject_parentco +from specifyweb.specify.migration_utils.migration_helpers.helper_0029_remove_collectionobject_parentco import remove_collectionobject_parentco, revert_remove_collectionobject_parentco class Migration(migrations.Migration): dependencies = [ diff --git a/specifyweb/specify/migrations/0032_add_quantities_gift.py b/specifyweb/specify/migrations/0032_add_quantities_gift.py index fa9c31c60cb..ab2a9bef797 100644 --- a/specifyweb/specify/migrations/0032_add_quantities_gift.py +++ b/specifyweb/specify/migrations/0032_add_quantities_gift.py @@ -4,7 +4,7 @@ from django.apps import apps as specify_apps from specifyweb.specify.migration_utils import migration_helpers as usc -from specifyweb.specify.migration_utils.migration_helpers import add_quantities_gift, revert_add_quantities_gift +from specifyweb.specify.migration_utils.migration_helpers.helper_0032_add_quantities_gift import add_quantities_gift, revert_add_quantities_gift class Migration(migrations.Migration): diff --git a/specifyweb/specify/migrations/0033_update_paleo_desc.py b/specifyweb/specify/migrations/0033_update_paleo_desc.py index 627668f951e..e7a84af43eb 100644 --- a/specifyweb/specify/migrations/0033_update_paleo_desc.py +++ b/specifyweb/specify/migrations/0033_update_paleo_desc.py @@ -1,5 +1,5 @@ from django.db import migrations -from specifyweb.specify.migration_utils.migration_helpers import update_paleo_desc +from specifyweb.specify.migration_utils.migration_helpers.helper_0033_update_paleo_desc import update_paleo_desc def schemaconfig_fixes(apps, schema_editor): update_paleo_desc(apps) diff --git a/specifyweb/specify/migrations/0034_accession_date_fields.py b/specifyweb/specify/migrations/0034_accession_date_fields.py index 783ffeffdf8..ae57af89ed2 100644 --- a/specifyweb/specify/migrations/0034_accession_date_fields.py +++ b/specifyweb/specify/migrations/0034_accession_date_fields.py @@ -1,7 +1,7 @@ # Generated by Django 4.2.18 on 2025-06-12 23:10 from django.db import migrations, models -from specifyweb.specify.migration_utils.migration_helpers import revert_update_accession_date_fields, update_accession_date_fields +from specifyweb.specify.migration_utils.migration_helpers.helper_0034_accession_date_fields import revert_update_accession_date_fields, update_accession_date_fields def apply_migration(apps, schema_editor): update_accession_date_fields(apps) diff --git a/specifyweb/specify/migrations/0035_version_required.py b/specifyweb/specify/migrations/0035_version_required.py index cbbb68eb80f..539db4a8479 100644 --- a/specifyweb/specify/migrations/0035_version_required.py +++ b/specifyweb/specify/migrations/0035_version_required.py @@ -2,7 +2,7 @@ from django.db import migrations, models -from specifyweb.specify.migration_utils.migration_helpers import revert_version_required, update_version_required +from specifyweb.specify.migration_utils.migration_helpers.helper_0035_version_required import revert_version_required, update_version_required def apply_migration(apps, schema_editor): update_version_required(apps) diff --git a/specifyweb/specify/migrations/0039_agent_fields_for_loan_and_gift.py b/specifyweb/specify/migrations/0039_agent_fields_for_loan_and_gift.py index b54aa36c3af..cde3ac1a6ce 100644 --- a/specifyweb/specify/migrations/0039_agent_fields_for_loan_and_gift.py +++ b/specifyweb/specify/migrations/0039_agent_fields_for_loan_and_gift.py @@ -2,7 +2,7 @@ from django.apps import apps as specify_apps from django.db import migrations, models -from specifyweb.specify.migration_utils.migration_helpers import revert_loan_and_gift_agent_fields, update_loan_and_gift_agent_fields +from specifyweb.specify.migration_utils.migration_helpers.helper_0039_agent_fields_for_loan_and_gift import revert_loan_and_gift_agent_fields, update_loan_and_gift_agent_fields from specifyweb.specify.models import protect_with_blockers def consolidated_0038_forward(apps, schema_editor): diff --git a/specifyweb/specify/migrations/0040_components.py b/specifyweb/specify/migrations/0040_components.py index 4afdb3a342e..35cd94522ba 100644 --- a/specifyweb/specify/migrations/0040_components.py +++ b/specifyweb/specify/migrations/0040_components.py @@ -3,7 +3,7 @@ from django.db import migrations, models import django.db.models.deletion import django.utils.timezone -from specifyweb.specify.migration_utils.migration_helpers import create_cotype_splocalecontaineritem_for_components, create_table_schema_config_with_defaults, hide_component_fields, remove_0029_schema_config_fields, restore_0029_schema_config_fields, reverse_hide_component_fields, revert_table_schema_config_with_defaults, update_hidden_prop_for_components, update_schema_config_field_desc_for_components +from specifyweb.specify.migration_utils.migration_helpers.helper_0040_components import create_cotype_splocalecontaineritem_for_components, create_table_schema_config_with_defaults, hide_component_fields, remove_0029_schema_config_fields, restore_0029_schema_config_fields, reverse_hide_component_fields, revert_table_schema_config_with_defaults, update_hidden_prop_for_components, update_schema_config_field_desc_for_components import specifyweb.specify.models from specifyweb.specify.models import protect_with_blockers diff --git a/specifyweb/specify/migrations/0042_discipline_type_picklist.py b/specifyweb/specify/migrations/0042_discipline_type_picklist.py index c0abd7f07f5..2ccb098476a 100644 --- a/specifyweb/specify/migrations/0042_discipline_type_picklist.py +++ b/specifyweb/specify/migrations/0042_discipline_type_picklist.py @@ -1,6 +1,6 @@ from django.db import migrations -from specifyweb.specify.migration_utils.migration_helpers import create_discipline_type_picklist, revert_discipline_type_picklist, revert_discipline_type_splocalecontaineritem, update_discipline_type_splocalecontaineritem +from specifyweb.specify.migration_utils.migration_helpers.helper_0042_discipline_type_picklist import create_discipline_type_picklist, revert_discipline_type_picklist, revert_discipline_type_splocalecontaineritem, update_discipline_type_splocalecontaineritem class Migration(migrations.Migration): dependencies = [ From e269935cb589b647b67d1fc67f073c6e4ab300ac Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Tue, 16 Jun 2026 12:23:24 +0200 Subject: [PATCH 077/113] fix: Imports --- .../migration_utils/migration_helpers/helper_0040_components.py | 1 + specifyweb/specify/migrations/0040_components.py | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/specifyweb/specify/migration_utils/migration_helpers/helper_0040_components.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0040_components.py index 93cbfe6f97d..9ec2d19f118 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/helper_0040_components.py +++ b/specifyweb/specify/migration_utils/migration_helpers/helper_0040_components.py @@ -1,4 +1,5 @@ from specifyweb.specify.migration_utils.schema_writer import revert_table_field_schema_config, revert_table_schema_config, update_table_field_schema_config_with_defaults, update_table_schema_config_with_defaults +from django.db.models import Q # ########################################## # Used in 0040_components.py diff --git a/specifyweb/specify/migrations/0040_components.py b/specifyweb/specify/migrations/0040_components.py index 35cd94522ba..dccb9f1d764 100644 --- a/specifyweb/specify/migrations/0040_components.py +++ b/specifyweb/specify/migrations/0040_components.py @@ -1,10 +1,8 @@ -from django.apps import apps as specify_apps from django.db import migrations, models import django.db.models.deletion import django.utils.timezone from specifyweb.specify.migration_utils.migration_helpers.helper_0040_components import create_cotype_splocalecontaineritem_for_components, create_table_schema_config_with_defaults, hide_component_fields, remove_0029_schema_config_fields, restore_0029_schema_config_fields, reverse_hide_component_fields, revert_table_schema_config_with_defaults, update_hidden_prop_for_components, update_schema_config_field_desc_for_components -import specifyweb.specify.models from specifyweb.specify.models import protect_with_blockers class Migration(migrations.Migration): From 9b7eb9b1ca40eb21c4c45ba87e1e3f45087ea5fe Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Tue, 16 Jun 2026 12:33:51 +0200 Subject: [PATCH 078/113] fix: Imports --- specifyweb/backend/setup_tool/schema_defaults.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specifyweb/backend/setup_tool/schema_defaults.py b/specifyweb/backend/setup_tool/schema_defaults.py index 0af1052db51..853023ef8cd 100644 --- a/specifyweb/backend/setup_tool/schema_defaults.py +++ b/specifyweb/backend/setup_tool/schema_defaults.py @@ -1,5 +1,5 @@ from specifyweb.specify.models_utils.models_by_table_id import model_names_by_table_id -from specifyweb.specify.migration_utils.migration_helpers import update_table_schema_config_with_defaults +from specifyweb.specify.migration_utils.schema_writer import update_table_schema_config_with_defaults from specifyweb.celery_tasks import app from .utils import load_json_from_file from .task_tracking import queue_discipline_background_task, finish_discipline_background_task From 4f93c13cdfa908590aeb2ac5dd87337a0a8e5985 Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Tue, 16 Jun 2026 13:03:55 +0200 Subject: [PATCH 079/113] fix: Typo --- .env | 62 ++++--------------- .../commands/run_key_migration_functions.py | 2 +- 2 files changed, 13 insertions(+), 51 deletions(-) diff --git a/.env b/.env index 71fe3b0c430..99709bb1e0e 100644 --- a/.env +++ b/.env @@ -1,70 +1,32 @@ DATABASE_HOST=mariadb DATABASE_PORT=3306 -MYSQL_ROOT_PASSWORD=password -DATABASE_NAME=specify +MYSQL_ROOT_PASSWORD=root +DATABASE_NAME=ciscollections_2025_09_19 -# The following are database users with specific roles and privileges. -# If the migrator and app user are not defined, the system will use the master user credentials. -# See documenation https://discourse.specifysoftware.org/t/new-blank-database-creation-database-user-levels/3023 -# MASTER Database User -# Full database administrator, used for initial setup and migrations requiring elevated privileges. -# This user should already be setup before running Specify. +# When running Specify 7 for the first time or during updates that +# require migrations, ensure that the MASTER_NAME and MASTER_PASSWORD +# are set to the root username and password. This will ensure proper +# execution of Django migrations during the ixnitial setup. +# After launching Specify and verifying the update is complete, you can +# safely replace these credentials with the master SQL user name and password. MASTER_NAME=root -MASTER_PASSWORD=password -MASTER_HOST=% - -# MIGRATOR Database User -# User with elevated privileges to perform migrations (create/drop/modify tables, etc.), for Django migration steps. -# Make sure that the user is unique to just one database, otherwise use master. -MIGRATOR_NAME=specify_migrator -MIGRATOR_PASSWORD=specify_migrator -MIGRATOR_HOST=% - -# APP Database User -# Normal runtime database user that performs application-level operations. -# Make sure that the user is unique to just one database, otherwise use master. -APP_USER_NAME=specify_user -APP_USER_PASSWORD=specify_user -APP_HOST=% - -# Enabling this option allows administrators with access to the -# backend Specify instance to log in as any user for support -# purposes without knowing their password. -# https://discourse.specifysoftware.org/t/allow-support-login-documentation/2838 -ALLOW_SUPPORT_LOGIN=false -# The amount of time in seconds each token is valid for -SUPPORT_LOGIN_TTL = 180 +MASTER_PASSWORD=root # Make sure to set the `SECRET_KEY` to a unique value SECRET_KEY=change_this_to_some_unique_random_string ASSET_SERVER_URL=http://host.docker.internal/web_asset_store.xml + # Make sure to set the `ASSET_SERVER_KEY` to a unique value ASSET_SERVER_KEY=your_asset_server_access_key -# Information to connect to a Redis database -# Specify will use this database as a process broker and storage for temporary -# values -REDIS_HOST=redis -REDIS_PORT=6379 -REDIS_DB_INDEX=0 - REPORT_RUNNER_HOST=report-runner REPORT_RUNNER_PORT=8080 CELERY_BROKER_URL=redis://redis/0 CELERY_RESULT_BACKEND=redis://redis/1 -# Local time zone for this installation. Choices can be found here: -# https://en.wikipedia.org/wiki/List_of_tz_zones_by_name -# although not all choices may be available on all operating systems. -# On Unix systems, a value of None will cause Django to use the same -# timezone as the operating system. -# If running in a Windows environment this must be set to the same as your -# system time zone. -TIME_ZONE = America/Chicago - # This variable controls the Specify 7 logging level. Possible values # are: # * DEBUG: Low level system information for debugging purposes. @@ -75,7 +37,7 @@ TIME_ZONE = America/Chicago LOG_LEVEL=WARNING # Set this variable to `true` to run Specify 7 in debug mode. This -# should only be used during development and troubleshooting and not -# during general use. Django applications leak memory when operated +# should only be used during development and troubleshooting and not +# during general use. Django applications leak memory when operated # continuously in debug mode. SP7_DEBUG=true diff --git a/specifyweb/specify/management/commands/run_key_migration_functions.py b/specifyweb/specify/management/commands/run_key_migration_functions.py index 8b82afbea10..2750a093ca6 100644 --- a/specifyweb/specify/management/commands/run_key_migration_functions.py +++ b/specifyweb/specify/management/commands/run_key_migration_functions.py @@ -21,7 +21,7 @@ ) from specifyweb.backend.permissions.initialize import initialize from specifyweb.specify.migration_utils import migration_helpers as usc -from specifyweb.specify.migration_utils.Deduplication import deduplicate_schema_config_orm +from specifyweb.specify.migration_utils.deduplication import deduplicate_schema_config_orm from specifyweb.specify.migration_utils.router import use_migration_connection from specifyweb.specify.migration_utils.misc_migrations import make_selectseries_false from specifyweb.specify.migration_utils.tectonic_ranks import create_default_tectonic_ranks, create_root_tectonic_node, fix_tectonic_unit_treedef_discipline_links From f002c2f9429efa4cfd4ba749a350bc657ab916bc Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Tue, 16 Jun 2026 15:03:50 +0200 Subject: [PATCH 080/113] Refactor: Remove usc from run key migration --- .../commands/run_key_migration_functions.py | 75 +++++++++++-------- 1 file changed, 44 insertions(+), 31 deletions(-) diff --git a/specifyweb/specify/management/commands/run_key_migration_functions.py b/specifyweb/specify/management/commands/run_key_migration_functions.py index 2750a093ca6..ef281eb29ba 100644 --- a/specifyweb/specify/management/commands/run_key_migration_functions.py +++ b/specifyweb/specify/management/commands/run_key_migration_functions.py @@ -22,6 +22,19 @@ from specifyweb.backend.permissions.initialize import initialize from specifyweb.specify.migration_utils import migration_helpers as usc from specifyweb.specify.migration_utils.deduplication import deduplicate_schema_config_orm +from specifyweb.specify.migration_utils.migration_helpers.helper_0002_schema_config_update import create_geo_table_schema_config_with_defaults +from specifyweb.specify.migration_utils.migration_helpers.helper_0003_cotype_picklist import create_cotype_splocalecontaineritem +from specifyweb.specify.migration_utils.migration_helpers.helper_0004_stratigraphy_age import create_agetype_picklist, create_strat_table_schema_config_with_defaults +from specifyweb.specify.migration_utils.migration_helpers.helper_0007_schema_config_update import create_cogtype_picklist +from specifyweb.specify.migration_utils.migration_helpers.helper_0008_schema_config_update import update_relative_age_fields +from specifyweb.specify.migration_utils.migration_helpers.helper_0012_add_cojo_to_schema_config import add_cojo_to_schema_config +from specifyweb.specify.migration_utils.migration_helpers.helper_0013_collectionobjectgroup_parentcog import update_cog_schema_config +from specifyweb.specify.migration_utils.migration_helpers.helper_0015_add_version_to_ages import update_age_schema_config +from specifyweb.specify.migration_utils.migration_helpers.helper_0020_add_tectonicunit_to_pc_in_schema_config import add_tectonicunit_to_pc_in_schema_config +from specifyweb.specify.migration_utils.migration_helpers.helper_0024_add_uniqueIdentifier_storage import update_storage_unique_id_fields +from specifyweb.specify.migration_utils.migration_helpers.helper_0039_agent_fields_for_loan_and_gift import update_loan_and_gift_agent_fields +from specifyweb.specify.migration_utils.migration_helpers.helper_0040_components import create_table_schema_config_with_defaults, remove_componentparent_item +from specifyweb.specify.migration_utils.migration_helpers.helper_0042_discipline_type_picklist import create_discipline_type_picklist from specifyweb.specify.migration_utils.router import use_migration_connection from specifyweb.specify.migration_utils.misc_migrations import make_selectseries_false from specifyweb.specify.migration_utils.tectonic_ranks import create_default_tectonic_ranks, create_root_tectonic_node, fix_tectonic_unit_treedef_discipline_links @@ -64,46 +77,46 @@ def apply_schema_overrides_for_all_disciplines(_apps): # update_table_schema_config_with_defaults funcs = [ # usc.update_all_table_schema_config_with_defaults, - usc.create_geo_table_schema_config_with_defaults, # specify 0002 - usc.create_cotype_splocalecontaineritem, # specify 0003 - usc.create_strat_table_schema_config_with_defaults, # specify 0004 - getting skip warnings - usc.create_agetype_picklist, # specify 0004 + create_geo_table_schema_config_with_defaults, # specify 0002 + create_cotype_splocalecontaineritem, # specify 0003 + create_strat_table_schema_config_with_defaults, # specify 0004 - getting skip warnings + create_agetype_picklist, # specify 0004 # BUG: This should really only be run in the context of the migration, - # and not on startup. See the below BUG comment above usc.update_hidden_prop - # usc.update_cog_type_fields, # specify 0007 - usc.create_cogtype_picklist, # specify 0007 + # and not on startup. See the below BUG comment above update_hidden_prop + # update_cog_type_fields, # specify 0007 + create_cogtype_picklist, # specify 0007 # BUG: These also shouldn't be run with this suite. These are one way # data migrations in the contect of migrations meant to resolve # eariler migrations. # The functions can be destructive as we can't really discern whether # or not these functions should be applied - # usc.update_cogtype_splocalecontaineritem, # specify 0007 - # usc.update_systemcogtypes_picklist, # specify 0007 - # usc.update_cogtype_type_splocalecontaineritem, # specify 0007 - usc.update_relative_age_fields, # specify 0008 - usc.add_cojo_to_schema_config, # specify 0012 - usc.update_cog_schema_config, # specify 0013 - usc.update_age_schema_config, # specify 0015 - # usc.schemaconfig_fixes, # specify 0017 - # usc.add_cot_catnum_to_schema, # specify 0018 - usc.add_tectonicunit_to_pc_in_schema_config, # specify 0020 - # usc.fix_hidden_geo_prop, # specify 0021 - # usc.update_schema_config_field_desc, # specify 0023 + # update_cogtype_splocalecontaineritem, # specify 0007 + # update_systemcogtypes_picklist, # specify 0007 + # update_cogtype_type_splocalecontaineritem, # specify 0007 + update_relative_age_fields, # specify 0008 + add_cojo_to_schema_config, # specify 0012 + update_cog_schema_config, # specify 0013 + update_age_schema_config, # specify 0015 + # schemaconfig_fixes, # specify 0017 + # add_cot_catnum_to_schema, # specify 0018 + add_tectonicunit_to_pc_in_schema_config, # specify 0020 + # fix_hidden_geo_prop, # specify 0021 + # update_schema_config_field_desc, # specify 0023 # BUG: We can't reliably run this function at startup, as there is no # easy way to differentiate Schema Config tables/fields that should or # should not be updated for already existing Disciplines. - # usc.update_hidden_prop, # specify 0023 - usc.update_storage_unique_id_fields, # specify 0024 - # usc.update_co_children_fields, # specify 0027 - # usc.remove_collectionobject_parentco, # specify 0029 - # usc.add_quantities_gift, # specify 0032 - # usc.update_paleo_desc, # specify 0033 - # usc.update_accession_date_fields, # specify 0034 - usc.update_loan_and_gift_agent_fields, # specify 0039 - usc.remove_componentparent_item, # specify 0040 - usc.create_table_schema_config_with_defaults, # specify 0040 - usc.create_discipline_type_picklist, # specify 0042 - # usc.update_discipline_type_splocalecontaineritem, # specify 0042 + # update_hidden_prop, # specify 0023 + update_storage_unique_id_fields, # specify 0024 + # update_co_children_fields, # specify 0027 + # remove_collectionobject_parentco, # specify 0029 + # add_quantities_gift, # specify 0032 + # update_paleo_desc, # specify 0033 + # update_accession_date_fields, # specify 0034 + update_loan_and_gift_agent_fields, # specify 0039 + remove_componentparent_item, # specify 0040 + create_table_schema_config_with_defaults, # specify 0040 + create_discipline_type_picklist, # specify 0042 + # update_discipline_type_splocalecontaineritem, # specify 0042 apply_schema_overrides_for_all_disciplines, deduplicate_schema_config_orm, ] From 14b6b4ea0edd95b004b2d7c4d287b01903564af2 Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Tue, 16 Jun 2026 15:30:36 +0200 Subject: [PATCH 081/113] Test: Test new python path for github Ci --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8565522320d..0a89dbf6d1b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -159,7 +159,7 @@ jobs: # mysql -h 127.0.0.1 -P $PORT -u MasterUser -p'MasterPassword' -e 'DROP DATABASE IF EXISTS test_SpecifyDB;'; # mysql -h 127.0.0.1 -P $PORT -u MasterUser -p'MasterPassword' -e 'SHOW DATABASES;' - name: Run test suite - run: ./ve/bin/python manage.py test --verbosity=3 --keepdb + run: PYTHONPATH=$PYTHONPATH:$GITHUB_WORKSPACE ./ve/bin/python manage.py test --verbosity=3 --keepdb # run: ./ve/bin/python manage.py test --verbosity=3 --noinput test-front-end: From 0c05cef70827c7be17ef6f2403e14d4b6f63f418 Mon Sep 17 00:00:00 2001 From: melton-jason Date: Tue, 16 Jun 2026 08:56:53 -0500 Subject: [PATCH 082/113] fix: consider changes to DisciplineType schema item in reverse migration --- .../specify/migration_utils/update_schema_config.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/specifyweb/specify/migration_utils/update_schema_config.py b/specifyweb/specify/migration_utils/update_schema_config.py index 75591205613..20729b10a97 100644 --- a/specifyweb/specify/migration_utils/update_schema_config.py +++ b/specifyweb/specify/migration_utils/update_schema_config.py @@ -2169,13 +2169,19 @@ def update_discipline_type_splocalecontaineritem(apps): container__name="discipline", container__schematype=0, name="type", - ).update(picklistname=DISCIPLINE_TYPE_PICKLIST_NAME, isrequired=True) + ).update( + picklistname=DISCIPLINE_TYPE_PICKLIST_NAME, + isrequired=True + ) def revert_discipline_type_splocalecontaineritem(apps): Splocalecontaineritem = apps.get_model("specify", "Splocalecontaineritem") Splocalecontaineritem.objects.filter( container__name="discipline", + picklistname=DISCIPLINE_TYPE_PICKLIST_NAME, container__schematype=0, name="type", - ).update(picklistname=None, isrequired=None) + ).update( + picklistname=None + ) From 948873c0c0add0188261ea34544283a228a4b5b9 Mon Sep 17 00:00:00 2001 From: melton-jason Date: Tue, 16 Jun 2026 11:40:35 -0500 Subject: [PATCH 083/113] refactor: optimize DisciplineType Picklist creation for scale --- .../migration_utils/update_schema_config.py | 97 +++++++++++++------ 1 file changed, 66 insertions(+), 31 deletions(-) diff --git a/specifyweb/specify/migration_utils/update_schema_config.py b/specifyweb/specify/migration_utils/update_schema_config.py index 20729b10a97..de0b493dba7 100644 --- a/specifyweb/specify/migration_utils/update_schema_config.py +++ b/specifyweb/specify/migration_utils/update_schema_config.py @@ -1,26 +1,25 @@ import re import json -from typing import NamedTuple, Tuple, TypedDict, NotRequired +from typing import NamedTuple, Tuple, TypedDict, NotRequired, Iterable import logging from collections import defaultdict from functools import lru_cache +from itertools import islice from pathlib import Path from django.db.models import Q, Count, Window, F, Exists, OuterRef from django.conf import settings from django.apps import apps as global_apps -from django.core.exceptions import MultipleObjectsReturned from django.db import connection, transaction from django.db.models.functions import RowNumber -from specifyweb.specify.models_utils.load_datamodel import FieldDoesNotExistError, TableDoesNotExistError +from specifyweb.specify.models_utils.load_datamodel import FieldDoesNotExistError -from specifyweb.specify.models_utils.load_datamodel import Table, FieldDoesNotExistError, TableDoesNotExistError +from specifyweb.specify.models_utils.load_datamodel import FieldDoesNotExistError from specifyweb.specify.models_utils.model_extras import GEOLOGY_DISCIPLINES, PALEO_DISCIPLINES from specifyweb.specify.models import ( - Discipline, datamodel, ) from specifyweb.specify.migration_utils.sp7_schemaconfig import ( @@ -2128,34 +2127,70 @@ def create_discipline_type_picklist(apps): Picklist = apps.get_model('specify', 'Picklist') Picklistitem = apps.get_model('specify', 'Picklistitem') - # Create a discipline type picklist for each collection - for collection in Collection.objects.all(): - picklist, created = Picklist.objects.get_or_create( - name=DISCIPLINE_TYPE_PICKLIST_NAME, - type=0, - collection=collection, - defaults={ - "issystem": True, - "readonly": True, - "sizelimit": -1, - "sorttype": 1, - } + def batch_iterable[T](iterable: Iterable[T], batch_size: int): + """ + A generator that takes any Iterable and yields tuples containing up to + batch_size elements until the iterable is exhausted. + + This is useful when you want to perform some operation over all + elements in the iterable, but the operation is memory intensive and can + be batched. + + Example: + ```py + example = [1, 2, 3] + for batched in batch_iterable(example, 2): + print(batched) + # prints (1, 2) then (3,) + ``` + """ + iterator = iter(iterable) + while batch := tuple(islice(iterator, batch_size)): + yield batch + + collections_missing_picklist = Collection.objects.annotate( + has_existing_picklist=Exists( + Picklist.objects.filter( + collection=OuterRef("pk"), + name=DISCIPLINE_TYPE_PICKLIST_NAME, + type=0 + ) ) - # If the picklist doesn't exist, create a new one - if created: - ordinal = 1 - items = [] - for value, title in DISCIPLINE_NAMES.items(): - items.append( - Picklistitem( - picklist=picklist, - ordinal=ordinal, - value=value, - title=title, - ) + ).filter( + has_existing_picklist=False + ).values_list("pk", flat=True).iterator(chunk_size=1000) + + COLLECTION_BATCH_SIZE=200 + + for collection_ids in batch_iterable(collections_missing_picklist, COLLECTION_BATCH_SIZE): + created_picklists = Picklist.objects.bulk_create( + [ + Picklist( + collection_id=collection_id, + name=DISCIPLINE_TYPE_PICKLIST_NAME, + type=0, + issystem=True, + readonly=True, + sizelimit=-1, + sorttype=1 ) - ordinal += 1 - Picklistitem.objects.bulk_create(items) + for collection_id in collection_ids + ], + batch_size=COLLECTION_BATCH_SIZE + ) + + Picklistitem.objects.bulk_create( + [ + Picklistitem( + picklist=picklist, + value=value, + title=title, + ordinal=ordinal + ) + for ordinal, (value, title) in enumerate(DISCIPLINE_NAMES.items(), start=1) + for picklist in created_picklists + ] + ) def revert_discipline_type_picklist(apps): Picklist = apps.get_model('specify', 'Picklist') From c40f93d673ad1f172f8857b2e7e68bc7bd400a18 Mon Sep 17 00:00:00 2001 From: melton-jason Date: Tue, 16 Jun 2026 12:16:19 -0500 Subject: [PATCH 084/113] fix: use DisciplineType picklist for newly created Disciplines --- config/common/schema_localization_en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/common/schema_localization_en.json b/config/common/schema_localization_en.json index 70cda3bf86b..0e86a2ffb09 100644 --- a/config/common/schema_localization_en.json +++ b/config/common/schema_localization_en.json @@ -2497,7 +2497,7 @@ "taxontreedef": {"name": "Taxon Tree Def", "desc": "Taxon Tree Def", "format": null, "ishidden": true, "isuiformatter": false, "picklistname": null, "type": null, "isrequired": false, "weblinkname": null}, "timestampcreated": {"name": "Timestamp Created", "desc": "Timestamp Created", "format": null, "ishidden": true, "isuiformatter": false, "picklistname": null, "type": null, "isrequired": false, "weblinkname": null}, "timestampmodified": {"name": "Timestamp Modified", "desc": "Timestamp Modified", "format": null, "ishidden": true, "isuiformatter": false, "picklistname": null, "type": null, "isrequired": false, "weblinkname": null}, - "type": {"name": "Type", "desc": "Type", "format": null, "ishidden": false, "isuiformatter": false, "picklistname": null, "type": null, "isrequired": false, "weblinkname": null}, + "type": {"name": "Type", "desc": "Type", "format": null, "ishidden": false, "isuiformatter": false, "picklistname": "DisciplineType", "type": null, "isrequired": false, "weblinkname": null}, "usergroups": {"name": "User Groups", "desc": "User Groups", "format": null, "ishidden": true, "isuiformatter": false, "picklistname": null, "type": null, "isrequired": false, "weblinkname": null}, "version": {"name": "Version", "desc": "Version", "format": null, "ishidden": true, "isuiformatter": false, "picklistname": null, "type": null, "isrequired": false, "weblinkname": null} }, From 91589eaa13a72c86cd7e4504ad85d3aa20bca399 Mon Sep 17 00:00:00 2001 From: melton-jason Date: Tue, 16 Jun 2026 12:31:28 -0500 Subject: [PATCH 085/113] fix: create DisciplineType PickList when creating Collection --- config/common/global_picklists.json | 79 ++++++++++++++++++++++++++ specifyweb/backend/setup_tool/utils.py | 8 +-- 2 files changed, 82 insertions(+), 5 deletions(-) diff --git a/config/common/global_picklists.json b/config/common/global_picklists.json index 94cff40530a..69448e8e707 100644 --- a/config/common/global_picklists.json +++ b/config/common/global_picklists.json @@ -448,6 +448,85 @@ { "title": "Fossil record", "value": "Fossil record" }, { "title": "Radiometric (adjacent)", "value": "Radiometric (adjacent)" } ] + }, + { + "name": "DisciplineType", + "formatter": null, + "issystem": true, + "readonly": true, + "sizelimit": -1, + "sorttype": 1, + "tablename": null, + "type": 0, + "version": 0, + "items": [ + { + "ordinal": 1, + "title": "Ichthyology", + "value": "fish", + "version": 0 + }, + { + "ordinal": 2, + "title": "Herpetology", + "value": "herpetology", + "version": 0 + }, + { + "ordinal": 3, + "title": "Paleobotany", + "value": "paleobotany", + "version": 0 + }, + { + "ordinal": 4, + "title": "Invertebrate Paleontology", + "value": "invertpaleo", + "version": 0 + }, + { + "ordinal": 5, + "title": "Vertebrate Paleontology", + "value": "vertpaleo", + "version": 0 + }, + { + "ordinal": 6, + "title": "Ornithology", + "value": "bird", + "version": 0 + }, + { + "ordinal": 7, + "title": "Mammalogy", + "value": "mammal", + "version": 0 + }, + { + "ordinal": 8, + "title": "Entomology", + "value": "insect", + "version": 0 + }, + { + "ordinal": 9, + "title": "Botany", + "value": "botany", + "version": 0 + }, + { + "ordinal": 10, + "title": "Invertebrate Zoology", + "value": "invertebrate", + "version": 0 + }, + { + "ordinal": 11, + "title": "Geology", + "value": "geology", + "version": 0 + } + ] } ] } \ No newline at end of file diff --git a/specifyweb/backend/setup_tool/utils.py b/specifyweb/backend/setup_tool/utils.py index cbae8a07c4a..034ba84fc70 100644 --- a/specifyweb/backend/setup_tool/utils.py +++ b/specifyweb/backend/setup_tool/utils.py @@ -1,14 +1,12 @@ +import logging import json from pathlib import Path -from django.db.models import Model as DjangoModel from typing import Optional, Type -from specifyweb.specify.api_utils import strict_uri_to_model -import logging +from django.db.models import Model as DjangoModel -from specifyweb.backend.context.app_resource import DISCIPLINE_NAMES +from specifyweb.specify.api_utils import strict_uri_to_model -from specifyweb.specify.models import Picklist, Picklistitem, Splocalecontaineritem logger = logging.getLogger(__name__) def resolve_uri_or_fallback(uri: Optional[str], id: Optional[int], table: Type[DjangoModel]) -> Optional[DjangoModel]: From 0ad7489dee4f376c758f019abe23b87b25cd9021 Mon Sep 17 00:00:00 2001 From: melton-jason Date: Tue, 16 Jun 2026 13:29:14 -0500 Subject: [PATCH 086/113] chore: remove temp_models file --- .../specify/models_utils/temp_models.py | 5951 ----------------- 1 file changed, 5951 deletions(-) delete mode 100644 specifyweb/specify/models_utils/temp_models.py diff --git a/specifyweb/specify/models_utils/temp_models.py b/specifyweb/specify/models_utils/temp_models.py deleted file mode 100644 index d8240c31e1e..00000000000 --- a/specifyweb/specify/models_utils/temp_models.py +++ /dev/null @@ -1,5951 +0,0 @@ -# This is an auto-generated Django model module. -# You'll have to do the following manually to clean this up: -# * Rearrange models' order -# * Make sure each model has one field with primary_key=True -# * Make sure each ForeignKey and OneToOneField has `on_delete` set to the desired behavior -# * Remove `managed = False` lines if you wish to allow Django to create, modify, and delete the table -# Feel free to rename the models, but don't rename db_table values or field names. -from django.db import models - - -class Accession(models.Model): - accessionid = models.AutoField(db_column='AccessionID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - accessioncondition = models.CharField(db_column='AccessionCondition', max_length=255, blank=True, null=True) # Field name made lowercase. - accessionnumber = models.CharField(db_column='AccessionNumber', max_length=60) # Field name made lowercase. - dateaccessioned = models.DateField(db_column='DateAccessioned', blank=True, null=True) # Field name made lowercase. - dateacknowledged = models.DateField(db_column='DateAcknowledged', blank=True, null=True) # Field name made lowercase. - datereceived = models.DateField(db_column='DateReceived', blank=True, null=True) # Field name made lowercase. - number1 = models.DecimalField(db_column='Number1', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number2 = models.DecimalField(db_column='Number2', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - status = models.CharField(db_column='Status', max_length=32, blank=True, null=True) # Field name made lowercase. - text1 = models.TextField(db_column='Text1', blank=True, null=True) # Field name made lowercase. - text2 = models.TextField(db_column='Text2', blank=True, null=True) # Field name made lowercase. - text3 = models.TextField(db_column='Text3', blank=True, null=True) # Field name made lowercase. - totalvalue = models.DecimalField(db_column='TotalValue', max_digits=12, decimal_places=2, blank=True, null=True) # Field name made lowercase. - type = models.CharField(db_column='Type', max_length=32, blank=True, null=True) # Field name made lowercase. - verbatimdate = models.CharField(db_column='VerbatimDate', max_length=50, blank=True, null=True) # Field name made lowercase. - yesno1 = models.BooleanField(db_column='YesNo1', blank=True, null=True) # Field name made lowercase. - yesno2 = models.BooleanField(db_column='YesNo2', blank=True, null=True) # Field name made lowercase. - divisionid = models.ForeignKey('Division', models.DO_NOTHING, db_column='DivisionID') # Field name made lowercase. - repositoryagreementid = models.ForeignKey('Repositoryagreement', models.DO_NOTHING, db_column='RepositoryAgreementID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey('Agent', models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey('Agent', models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - addressofrecordid = models.ForeignKey('Addressofrecord', models.DO_NOTHING, db_column='AddressOfRecordID', blank=True, null=True) # Field name made lowercase. - integer1 = models.IntegerField(db_column='Integer1', blank=True, null=True) # Field name made lowercase. - integer2 = models.IntegerField(db_column='Integer2', blank=True, null=True) # Field name made lowercase. - integer3 = models.IntegerField(db_column='Integer3', blank=True, null=True) # Field name made lowercase. - text4 = models.TextField(db_column='Text4', blank=True, null=True) # Field name made lowercase. - text5 = models.TextField(db_column='Text5', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'accession' - - -class Accessionagent(models.Model): - accessionagentid = models.AutoField(db_column='AccessionAgentID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - role = models.CharField(db_column='Role', max_length=50) # Field name made lowercase. - agentid = models.ForeignKey('Agent', models.DO_NOTHING, db_column='AgentID') # Field name made lowercase. - accessionid = models.ForeignKey(Accession, models.DO_NOTHING, db_column='AccessionID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey('Agent', models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey('Agent', models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - repositoryagreementid = models.ForeignKey('Repositoryagreement', models.DO_NOTHING, db_column='RepositoryAgreementID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'accessionagent' - unique_together = (('role', 'agentid', 'accessionid'),) - - -class Accessionattachment(models.Model): - accessionattachmentid = models.AutoField(db_column='AccessionAttachmentID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - ordinal = models.IntegerField(db_column='Ordinal') # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey('Agent', models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - accessionid = models.ForeignKey(Accession, models.DO_NOTHING, db_column='AccessionID') # Field name made lowercase. - attachmentid = models.ForeignKey('Attachment', models.DO_NOTHING, db_column='AttachmentID') # Field name made lowercase. - createdbyagentid = models.ForeignKey('Agent', models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'accessionattachment' - - -class Accessionauthorization(models.Model): - accessionauthorizationid = models.AutoField(db_column='AccessionAuthorizationID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - accessionid = models.ForeignKey(Accession, models.DO_NOTHING, db_column='AccessionID', blank=True, null=True) # Field name made lowercase. - repositoryagreementid = models.ForeignKey('Repositoryagreement', models.DO_NOTHING, db_column='RepositoryAgreementID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey('Agent', models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey('Agent', models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - permitid = models.ForeignKey('Permit', models.DO_NOTHING, db_column='PermitID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'accessionauthorization' - - -class Accessioncitation(models.Model): - accessioncitationid = models.AutoField(db_column='AccessionCitationID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - figurenumber = models.CharField(db_column='FigureNumber', max_length=50, blank=True, null=True) # Field name made lowercase. - isfigured = models.BooleanField(db_column='IsFigured', blank=True, null=True) # Field name made lowercase. - pagenumber = models.CharField(db_column='PageNumber', max_length=50, blank=True, null=True) # Field name made lowercase. - platenumber = models.CharField(db_column='PlateNumber', max_length=50, blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey('Agent', models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - referenceworkid = models.ForeignKey('Referencework', models.DO_NOTHING, db_column='ReferenceWorkID') # Field name made lowercase. - modifiedbyagentid = models.ForeignKey('Agent', models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - accessionid = models.ForeignKey(Accession, models.DO_NOTHING, db_column='AccessionID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'accessioncitation' - - -class Address(models.Model): - addressid = models.AutoField(db_column='AddressID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - address = models.CharField(db_column='Address', max_length=255, blank=True, null=True) # Field name made lowercase. - address2 = models.CharField(db_column='Address2', max_length=255, blank=True, null=True) # Field name made lowercase. - address3 = models.CharField(db_column='Address3', max_length=400, blank=True, null=True) # Field name made lowercase. - address4 = models.CharField(db_column='Address4', max_length=400, blank=True, null=True) # Field name made lowercase. - address5 = models.CharField(db_column='Address5', max_length=400, blank=True, null=True) # Field name made lowercase. - city = models.CharField(db_column='City', max_length=64, blank=True, null=True) # Field name made lowercase. - country = models.CharField(db_column='Country', max_length=64, blank=True, null=True) # Field name made lowercase. - enddate = models.DateField(db_column='EndDate', blank=True, null=True) # Field name made lowercase. - fax = models.CharField(db_column='Fax', max_length=50, blank=True, null=True) # Field name made lowercase. - iscurrent = models.BooleanField(db_column='IsCurrent', blank=True, null=True) # Field name made lowercase. - isprimary = models.BooleanField(db_column='IsPrimary', blank=True, null=True) # Field name made lowercase. - isshipping = models.BooleanField(db_column='IsShipping', blank=True, null=True) # Field name made lowercase. - ordinal = models.IntegerField(db_column='Ordinal', blank=True, null=True) # Field name made lowercase. - phone1 = models.CharField(db_column='Phone1', max_length=50, blank=True, null=True) # Field name made lowercase. - phone2 = models.CharField(db_column='Phone2', max_length=50, blank=True, null=True) # Field name made lowercase. - positionheld = models.CharField(db_column='PositionHeld', max_length=32, blank=True, null=True) # Field name made lowercase. - postalcode = models.CharField(db_column='PostalCode', max_length=32, blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - roomorbuilding = models.CharField(db_column='RoomOrBuilding', max_length=50, blank=True, null=True) # Field name made lowercase. - startdate = models.DateField(db_column='StartDate', blank=True, null=True) # Field name made lowercase. - state = models.CharField(db_column='State', max_length=64, blank=True, null=True) # Field name made lowercase. - typeofaddr = models.CharField(db_column='TypeOfAddr', max_length=32, blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey('Agent', models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - agentid = models.ForeignKey('Agent', models.DO_NOTHING, db_column='AgentID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey('Agent', models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'address' - - -class Addressofrecord(models.Model): - addressofrecordid = models.AutoField(db_column='AddressOfRecordID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - address = models.CharField(db_column='Address', max_length=255, blank=True, null=True) # Field name made lowercase. - address2 = models.CharField(db_column='Address2', max_length=255, blank=True, null=True) # Field name made lowercase. - city = models.CharField(db_column='City', max_length=64, blank=True, null=True) # Field name made lowercase. - country = models.CharField(db_column='Country', max_length=64, blank=True, null=True) # Field name made lowercase. - postalcode = models.CharField(db_column='PostalCode', max_length=32, blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - state = models.CharField(db_column='State', max_length=64, blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey('Agent', models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - agentid = models.ForeignKey('Agent', models.DO_NOTHING, db_column='AgentID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey('Agent', models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'addressofrecord' - - -class Agent(models.Model): - agentid = models.AutoField(db_column='AgentID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - abbreviation = models.CharField(db_column='Abbreviation', max_length=50, blank=True, null=True) # Field name made lowercase. - agenttype = models.IntegerField(db_column='AgentType') # Field name made lowercase. - dateofbirth = models.DateField(db_column='DateOfBirth', blank=True, null=True) # Field name made lowercase. - dateofbirthprecision = models.IntegerField(db_column='DateOfBirthPrecision', blank=True, null=True) # Field name made lowercase. - dateofdeath = models.DateField(db_column='DateOfDeath', blank=True, null=True) # Field name made lowercase. - dateofdeathprecision = models.IntegerField(db_column='DateOfDeathPrecision', blank=True, null=True) # Field name made lowercase. - datetype = models.IntegerField(db_column='DateType', blank=True, null=True) # Field name made lowercase. - email = models.CharField(db_column='Email', max_length=50, blank=True, null=True) # Field name made lowercase. - firstname = models.CharField(db_column='FirstName', max_length=50, blank=True, null=True) # Field name made lowercase. - guid = models.CharField(db_column='GUID', max_length=128, blank=True, null=True) # Field name made lowercase. - initials = models.CharField(db_column='Initials', max_length=8, blank=True, null=True) # Field name made lowercase. - interests = models.CharField(db_column='Interests', max_length=255, blank=True, null=True) # Field name made lowercase. - jobtitle = models.CharField(db_column='JobTitle', max_length=50, blank=True, null=True) # Field name made lowercase. - lastname = models.CharField(db_column='LastName', max_length=256, blank=True, null=True) # Field name made lowercase. - middleinitial = models.CharField(db_column='MiddleInitial', max_length=50, blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - title = models.CharField(db_column='Title', max_length=50, blank=True, null=True) # Field name made lowercase. - url = models.TextField(db_column='URL', blank=True, null=True) # Field name made lowercase. - parentorganizationid = models.ForeignKey('self', models.DO_NOTHING, db_column='ParentOrganizationID', blank=True, null=True) # Field name made lowercase. - divisionid = models.ForeignKey('Division', models.DO_NOTHING, db_column='DivisionID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey('self', models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - institutionccid = models.ForeignKey('Institution', models.DO_NOTHING, db_column='InstitutionCCID', blank=True, null=True) # Field name made lowercase. - institutiontcid = models.ForeignKey('Institution', models.DO_NOTHING, db_column='InstitutionTCID', blank=True, null=True) # Field name made lowercase. - collectionccid = models.ForeignKey('Collection', models.DO_NOTHING, db_column='CollectionCCID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey('self', models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - specifyuserid = models.ForeignKey('Specifyuser', models.DO_NOTHING, db_column='SpecifyUserID', blank=True, null=True) # Field name made lowercase. - collectiontcid = models.ForeignKey('Collection', models.DO_NOTHING, db_column='CollectionTCID', blank=True, null=True) # Field name made lowercase. - suffix = models.CharField(db_column='Suffix', max_length=50, blank=True, null=True) # Field name made lowercase. - date1 = models.DateField(db_column='Date1', blank=True, null=True) # Field name made lowercase. - date1precision = models.IntegerField(db_column='Date1Precision', blank=True, null=True) # Field name made lowercase. - date2 = models.DateField(db_column='Date2', blank=True, null=True) # Field name made lowercase. - date2precision = models.IntegerField(db_column='Date2Precision', blank=True, null=True) # Field name made lowercase. - integer1 = models.IntegerField(db_column='Integer1', blank=True, null=True) # Field name made lowercase. - integer2 = models.IntegerField(db_column='Integer2', blank=True, null=True) # Field name made lowercase. - text1 = models.TextField(db_column='Text1', blank=True, null=True) # Field name made lowercase. - text2 = models.TextField(db_column='Text2', blank=True, null=True) # Field name made lowercase. - verbatimdate1 = models.CharField(db_column='VerbatimDate1', max_length=128, blank=True, null=True) # Field name made lowercase. - verbatimdate2 = models.CharField(db_column='VerbatimDate2', max_length=128, blank=True, null=True) # Field name made lowercase. - text3 = models.TextField(db_column='Text3', blank=True, null=True) # Field name made lowercase. - text4 = models.TextField(db_column='Text4', blank=True, null=True) # Field name made lowercase. - text5 = models.TextField(db_column='Text5', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'agent' - - -class Agentattachment(models.Model): - agentattachmentid = models.AutoField(db_column='AgentAttachmentID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - ordinal = models.IntegerField(db_column='Ordinal') # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - attachmentid = models.ForeignKey('Attachment', models.DO_NOTHING, db_column='AttachmentID') # Field name made lowercase. - agentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='AgentID') # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'agentattachment' - - -class Agentgeography(models.Model): - agentgeographyid = models.AutoField(db_column='AgentGeographyID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - role = models.CharField(db_column='Role', max_length=64, blank=True, null=True) # Field name made lowercase. - geographyid = models.ForeignKey('Geography', models.DO_NOTHING, db_column='GeographyID') # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - agentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='AgentID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'agentgeography' - - -class Agentidentifier(models.Model): - agentidentifierid = models.AutoField(db_column='AgentIdentifierID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - date1 = models.DateField(db_column='Date1', blank=True, null=True) # Field name made lowercase. - date1precision = models.IntegerField(db_column='Date1Precision', blank=True, null=True) # Field name made lowercase. - date2 = models.DateField(db_column='Date2', blank=True, null=True) # Field name made lowercase. - date2precision = models.IntegerField(db_column='Date2Precision', blank=True, null=True) # Field name made lowercase. - identifier = models.CharField(db_column='Identifier', max_length=2048) # Field name made lowercase. - identifiertype = models.CharField(db_column='IdentifierType', max_length=256, blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - text1 = models.TextField(db_column='Text1', blank=True, null=True) # Field name made lowercase. - text2 = models.TextField(db_column='Text2', blank=True, null=True) # Field name made lowercase. - text3 = models.TextField(db_column='Text3', blank=True, null=True) # Field name made lowercase. - text4 = models.TextField(db_column='Text4', blank=True, null=True) # Field name made lowercase. - text5 = models.TextField(db_column='Text5', blank=True, null=True) # Field name made lowercase. - yesno1 = models.BooleanField(db_column='YesNo1', blank=True, null=True) # Field name made lowercase. - yesno2 = models.BooleanField(db_column='YesNo2', blank=True, null=True) # Field name made lowercase. - yesno3 = models.BooleanField(db_column='YesNo3', blank=True, null=True) # Field name made lowercase. - yesno4 = models.BooleanField(db_column='YesNo4', blank=True, null=True) # Field name made lowercase. - yesno5 = models.BooleanField(db_column='YesNo5', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - agentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='AgentID') # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'agentidentifier' - - -class Agentspecialty(models.Model): - agentspecialtyid = models.AutoField(db_column='AgentSpecialtyID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - ordernumber = models.IntegerField(db_column='OrderNumber') # Field name made lowercase. - specialtyname = models.CharField(db_column='SpecialtyName', max_length=64) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - agentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='AgentID') # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'agentspecialty' - unique_together = (('agentid', 'ordernumber'),) - - -class Agentvariant(models.Model): - agentvariantid = models.AutoField(db_column='AgentVariantID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - country = models.CharField(db_column='Country', max_length=2, blank=True, null=True) # Field name made lowercase. - language = models.CharField(db_column='Language', max_length=2, blank=True, null=True) # Field name made lowercase. - name = models.CharField(db_column='Name', max_length=255, blank=True, null=True) # Field name made lowercase. - vartype = models.IntegerField(db_column='VarType') # Field name made lowercase. - variant = models.CharField(db_column='Variant', max_length=2, blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - agentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='AgentID') # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'agentvariant' - - -class Appraisal(models.Model): - appraisalid = models.AutoField(db_column='AppraisalID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - appraisaldate = models.DateField(db_column='AppraisalDate') # Field name made lowercase. - appraisalnumber = models.CharField(db_column='AppraisalNumber', unique=True, max_length=64) # Field name made lowercase. - appraisalvalue = models.DecimalField(db_column='AppraisalValue', max_digits=12, decimal_places=2, blank=True, null=True) # Field name made lowercase. - monetaryunittype = models.CharField(db_column='MonetaryUnitType', max_length=8, blank=True, null=True) # Field name made lowercase. - notes = models.TextField(db_column='Notes', blank=True, null=True) # Field name made lowercase. - agentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='AgentID') # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - accessionid = models.ForeignKey(Accession, models.DO_NOTHING, db_column='AccessionID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'appraisal' - - -class Attachment(models.Model): - attachmentid = models.AutoField(db_column='AttachmentID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - attachmentlocation = models.CharField(db_column='AttachmentLocation', max_length=128, blank=True, null=True) # Field name made lowercase. - copyrightdate = models.CharField(db_column='CopyrightDate', max_length=64, blank=True, null=True) # Field name made lowercase. - copyrightholder = models.CharField(db_column='CopyrightHolder', max_length=64, blank=True, null=True) # Field name made lowercase. - credit = models.CharField(db_column='Credit', max_length=64, blank=True, null=True) # Field name made lowercase. - dateimaged = models.CharField(db_column='DateImaged', max_length=64, blank=True, null=True) # Field name made lowercase. - filecreateddate = models.DateField(db_column='FileCreatedDate', blank=True, null=True) # Field name made lowercase. - license = models.CharField(db_column='License', max_length=64, blank=True, null=True) # Field name made lowercase. - mimetype = models.CharField(db_column='MimeType', max_length=1024, blank=True, null=True) # Field name made lowercase. - origfilename = models.TextField(db_column='origFilename') # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - title = models.CharField(max_length=255, blank=True, null=True) - tableid = models.SmallIntegerField(db_column='TableID', blank=True, null=True) # Field name made lowercase. - scopeid = models.IntegerField(db_column='ScopeID', blank=True, null=True) # Field name made lowercase. - scopetype = models.IntegerField(db_column='ScopeType', blank=True, null=True) # Field name made lowercase. - guid = models.CharField(db_column='GUID', max_length=128, blank=True, null=True) # Field name made lowercase. - visibility = models.IntegerField(db_column='Visibility', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - visibilitysetbyid = models.ForeignKey('Specifyuser', models.DO_NOTHING, db_column='VisibilitySetByID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - attachmentimageattributeid = models.ForeignKey('Attachmentimageattribute', models.DO_NOTHING, db_column='AttachmentImageAttributeID', blank=True, null=True) # Field name made lowercase. - ispublic = models.BooleanField(db_column='IsPublic') # Field name made lowercase. - creatorid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatorID', blank=True, null=True) # Field name made lowercase. - capturedevice = models.CharField(db_column='CaptureDevice', max_length=128, blank=True, null=True) # Field name made lowercase. - licenselogourl = models.CharField(db_column='LicenseLogoUrl', max_length=256, blank=True, null=True) # Field name made lowercase. - metadatatext = models.CharField(db_column='MetadataText', max_length=256, blank=True, null=True) # Field name made lowercase. - subjectorientation = models.CharField(db_column='SubjectOrientation', max_length=64, blank=True, null=True) # Field name made lowercase. - subtype = models.CharField(db_column='Subtype', max_length=64, blank=True, null=True) # Field name made lowercase. - type = models.CharField(db_column='Type', max_length=64, blank=True, null=True) # Field name made lowercase. - attachmentstorageconfig = models.TextField(db_column='AttachmentStorageConfig', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'attachment' - - -class Attachmentdataset(models.Model): - name = models.CharField(max_length=256) - remarks = models.TextField(blank=True, null=True) - importedfilename = models.TextField(blank=True, null=True) - uploaderstatus = models.JSONField(blank=True, null=True) - uploadplan = models.TextField(blank=True, null=True) - uploadresult = models.JSONField(blank=True, null=True) - data = models.JSONField() - timestampcreated = models.DateTimeField() - timestampmodified = models.DateTimeField() - collection = models.ForeignKey('Collection', models.DO_NOTHING) - createdbyagent = models.ForeignKey(Agent, models.DO_NOTHING, blank=True, null=True) - modifiedbyagent = models.ForeignKey(Agent, models.DO_NOTHING, blank=True, null=True) - specifyuser = models.ForeignKey('Specifyuser', models.DO_NOTHING) - - class Meta: - managed = False - db_table = 'attachmentdataset' - - -class Attachmentimageattribute(models.Model): - attachmentimageattributeid = models.AutoField(db_column='AttachmentImageAttributeID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - creativecommons = models.TextField(db_column='CreativeCommons', blank=True, null=True) # Field name made lowercase. - height = models.IntegerField(db_column='Height', blank=True, null=True) # Field name made lowercase. - imagetype = models.CharField(db_column='ImageType', max_length=80, blank=True, null=True) # Field name made lowercase. - magnification = models.FloatField(db_column='Magnification', blank=True, null=True) # Field name made lowercase. - mbimageid = models.IntegerField(db_column='MBImageID', blank=True, null=True) # Field name made lowercase. - number1 = models.DecimalField(db_column='Number1', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number2 = models.DecimalField(db_column='Number2', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - resolution = models.FloatField(db_column='Resolution', blank=True, null=True) # Field name made lowercase. - text1 = models.CharField(db_column='Text1', max_length=200, blank=True, null=True) # Field name made lowercase. - text2 = models.CharField(db_column='Text2', max_length=200, blank=True, null=True) # Field name made lowercase. - timestamplastsend = models.DateTimeField(db_column='TimestampLastSend', blank=True, null=True) # Field name made lowercase. - timestamplastupdatecheck = models.DateTimeField(db_column='TimestampLastUpdateCheck', blank=True, null=True) # Field name made lowercase. - viewdescription = models.CharField(db_column='ViewDescription', max_length=80, blank=True, null=True) # Field name made lowercase. - width = models.IntegerField(db_column='Width', blank=True, null=True) # Field name made lowercase. - yesno1 = models.BooleanField(db_column='YesNo1', blank=True, null=True) # Field name made lowercase. - yesno2 = models.BooleanField(db_column='YesNo2', blank=True, null=True) # Field name made lowercase. - morphbankviewid = models.ForeignKey('Morphbankview', models.DO_NOTHING, db_column='MorphBankViewID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'attachmentimageattribute' - - -class Attachmentmetadata(models.Model): - attachmentmetadataid = models.AutoField(db_column='AttachmentMetadataID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - name = models.CharField(db_column='Name', max_length=64) # Field name made lowercase. - value = models.CharField(db_column='Value', max_length=128) # Field name made lowercase. - attachmentid = models.ForeignKey(Attachment, models.DO_NOTHING, db_column='AttachmentID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'attachmentmetadata' - - -class Attachmenttag(models.Model): - attachmenttagid = models.AutoField(db_column='AttachmentTagID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - tag = models.CharField(db_column='Tag', max_length=64) # Field name made lowercase. - attachmentid = models.ForeignKey(Attachment, models.DO_NOTHING, db_column='AttachmentID') # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'attachmenttag' - - -class Attributedef(models.Model): - attributedefid = models.AutoField(db_column='AttributeDefID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - datatype = models.SmallIntegerField(db_column='DataType', blank=True, null=True) # Field name made lowercase. - fieldname = models.CharField(db_column='FieldName', max_length=32, blank=True, null=True) # Field name made lowercase. - tabletype = models.SmallIntegerField(db_column='TableType', blank=True, null=True) # Field name made lowercase. - disciplineid = models.ForeignKey('Discipline', models.DO_NOTHING, db_column='DisciplineID') # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - preptypeid = models.ForeignKey('Preptype', models.DO_NOTHING, db_column='PrepTypeID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'attributedef' - - -class AuthGroup(models.Model): - name = models.CharField(unique=True, max_length=150) - - class Meta: - managed = False - db_table = 'auth_group' - - -class AuthGroupPermissions(models.Model): - group = models.ForeignKey(AuthGroup, models.DO_NOTHING) - permission = models.ForeignKey('AuthPermission', models.DO_NOTHING) - - class Meta: - managed = False - db_table = 'auth_group_permissions' - unique_together = (('group', 'permission'),) - - -class AuthPermission(models.Model): - name = models.CharField(max_length=255) - content_type = models.ForeignKey('DjangoContentType', models.DO_NOTHING) - codename = models.CharField(max_length=100) - - class Meta: - managed = False - db_table = 'auth_permission' - unique_together = (('content_type', 'codename'),) - - -class Author(models.Model): - authorid = models.AutoField(db_column='AuthorID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - ordernumber = models.SmallIntegerField(db_column='OrderNumber') # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - referenceworkid = models.ForeignKey('Referencework', models.DO_NOTHING, db_column='ReferenceWorkID') # Field name made lowercase. - agentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='AgentID') # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'author' - unique_together = (('referenceworkid', 'agentid'),) - - -class Autonumberingscheme(models.Model): - autonumberingschemeid = models.AutoField(db_column='AutoNumberingSchemeID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - formatname = models.CharField(db_column='FormatName', max_length=64, blank=True, null=True) # Field name made lowercase. - isnumericonly = models.BooleanField(db_column='IsNumericOnly') # Field name made lowercase. - schemeclassname = models.CharField(db_column='SchemeClassName', max_length=64, blank=True, null=True) # Field name made lowercase. - schemename = models.CharField(db_column='SchemeName', max_length=64, blank=True, null=True) # Field name made lowercase. - tablenumber = models.IntegerField(db_column='TableNumber') # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'autonumberingscheme' - - -class AutonumschColl(models.Model): - collectionid = models.OneToOneField('Collection', models.DO_NOTHING, db_column='CollectionID', primary_key=True) # Field name made lowercase. - autonumberingschemeid = models.ForeignKey(Autonumberingscheme, models.DO_NOTHING, db_column='AutoNumberingSchemeID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'autonumsch_coll' - unique_together = (('collectionid', 'autonumberingschemeid'),) - - -class AutonumschDiv(models.Model): - divisionid = models.OneToOneField('Division', models.DO_NOTHING, db_column='DivisionID', primary_key=True) # Field name made lowercase. - autonumberingschemeid = models.ForeignKey(Autonumberingscheme, models.DO_NOTHING, db_column='AutoNumberingSchemeID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'autonumsch_div' - unique_together = (('divisionid', 'autonumberingschemeid'),) - - -class AutonumschDsp(models.Model): - disciplineid = models.OneToOneField('Discipline', models.DO_NOTHING, db_column='DisciplineID', primary_key=True) # Field name made lowercase. - autonumberingschemeid = models.ForeignKey(Autonumberingscheme, models.DO_NOTHING, db_column='AutoNumberingSchemeID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'autonumsch_dsp' - unique_together = (('disciplineid', 'autonumberingschemeid'),) - - -class Borrow(models.Model): - borrowid = models.AutoField(db_column='BorrowID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - collectionmemberid = models.IntegerField(db_column='CollectionMemberID') # Field name made lowercase. - currentduedate = models.DateField(db_column='CurrentDueDate', blank=True, null=True) # Field name made lowercase. - dateclosed = models.DateField(db_column='DateClosed', blank=True, null=True) # Field name made lowercase. - invoicenumber = models.CharField(db_column='InvoiceNumber', max_length=50) # Field name made lowercase. - isclosed = models.BooleanField(db_column='IsClosed', blank=True, null=True) # Field name made lowercase. - isfinancialresponsibility = models.BooleanField(db_column='IsFinancialResponsibility', blank=True, null=True) # Field name made lowercase. - number1 = models.DecimalField(db_column='Number1', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number2 = models.DecimalField(db_column='Number2', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - originalduedate = models.DateField(db_column='OriginalDueDate', blank=True, null=True) # Field name made lowercase. - receiveddate = models.DateField(db_column='ReceivedDate', blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - text1 = models.TextField(db_column='Text1', blank=True, null=True) # Field name made lowercase. - text2 = models.TextField(db_column='Text2', blank=True, null=True) # Field name made lowercase. - yesno1 = models.BooleanField(db_column='YesNo1', blank=True, null=True) # Field name made lowercase. - yesno2 = models.BooleanField(db_column='YesNo2', blank=True, null=True) # Field name made lowercase. - addressofrecordid = models.ForeignKey(Addressofrecord, models.DO_NOTHING, db_column='AddressOfRecordID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - borrowdate = models.DateField(db_column='BorrowDate', blank=True, null=True) # Field name made lowercase. - borrowdateprecision = models.IntegerField(db_column='BorrowDatePrecision', blank=True, null=True) # Field name made lowercase. - numberofitemsborrowed = models.IntegerField(db_column='NumberOfItemsBorrowed', blank=True, null=True) # Field name made lowercase. - status = models.CharField(db_column='Status', max_length=64, blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'borrow' - - -class Borrowagent(models.Model): - borrowagentid = models.AutoField(db_column='BorrowAgentID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - collectionmemberid = models.IntegerField(db_column='CollectionMemberID') # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - role = models.CharField(db_column='Role', max_length=32) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - borrowid = models.ForeignKey(Borrow, models.DO_NOTHING, db_column='BorrowID') # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - agentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='AgentID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'borrowagent' - unique_together = (('role', 'agentid', 'borrowid'),) - - -class Borrowattachment(models.Model): - borrowattachmentid = models.AutoField(db_column='BorrowAttachmentID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - ordinal = models.IntegerField(db_column='Ordinal') # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - borrowid = models.ForeignKey(Borrow, models.DO_NOTHING, db_column='BorrowID') # Field name made lowercase. - attachmentid = models.ForeignKey(Attachment, models.DO_NOTHING, db_column='AttachmentID') # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'borrowattachment' - - -class Borrowmaterial(models.Model): - borrowmaterialid = models.AutoField(db_column='BorrowMaterialID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - collectionmemberid = models.IntegerField(db_column='CollectionMemberID') # Field name made lowercase. - description = models.CharField(db_column='Description', max_length=250, blank=True, null=True) # Field name made lowercase. - incomments = models.TextField(db_column='InComments', blank=True, null=True) # Field name made lowercase. - materialnumber = models.CharField(db_column='MaterialNumber', max_length=50) # Field name made lowercase. - outcomments = models.TextField(db_column='OutComments', blank=True, null=True) # Field name made lowercase. - quantity = models.SmallIntegerField(db_column='Quantity', blank=True, null=True) # Field name made lowercase. - quantityresolved = models.SmallIntegerField(db_column='QuantityResolved', blank=True, null=True) # Field name made lowercase. - quantityreturned = models.SmallIntegerField(db_column='QuantityReturned', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - borrowid = models.ForeignKey(Borrow, models.DO_NOTHING, db_column='BorrowID') # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - text1 = models.TextField(db_column='Text1', blank=True, null=True) # Field name made lowercase. - text2 = models.TextField(db_column='Text2', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'borrowmaterial' - - -class Borrowreturnmaterial(models.Model): - borrowreturnmaterialid = models.AutoField(db_column='BorrowReturnMaterialID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - collectionmemberid = models.IntegerField(db_column='CollectionMemberID') # Field name made lowercase. - quantity = models.SmallIntegerField(db_column='Quantity', blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - returneddate = models.DateField(db_column='ReturnedDate', blank=True, null=True) # Field name made lowercase. - borrowmaterialid = models.ForeignKey(Borrowmaterial, models.DO_NOTHING, db_column='BorrowMaterialID') # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - returnedbyid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ReturnedByID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'borrowreturnmaterial' - - -class Collectingevent(models.Model): - collectingeventid = models.AutoField(db_column='CollectingEventID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - enddate = models.DateField(db_column='EndDate', blank=True, null=True) # Field name made lowercase. - enddateprecision = models.IntegerField(db_column='EndDatePrecision', blank=True, null=True) # Field name made lowercase. - enddateverbatim = models.CharField(db_column='EndDateVerbatim', max_length=50, blank=True, null=True) # Field name made lowercase. - endtime = models.SmallIntegerField(db_column='EndTime', blank=True, null=True) # Field name made lowercase. - method = models.CharField(db_column='Method', max_length=50, blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - sgrstatus = models.IntegerField(db_column='SGRStatus', blank=True, null=True) # Field name made lowercase. - guid = models.CharField(db_column='GUID', max_length=128, blank=True, null=True) # Field name made lowercase. - startdate = models.DateField(db_column='StartDate', blank=True, null=True) # Field name made lowercase. - startdateprecision = models.IntegerField(db_column='StartDatePrecision', blank=True, null=True) # Field name made lowercase. - startdateverbatim = models.CharField(db_column='StartDateVerbatim', max_length=50, blank=True, null=True) # Field name made lowercase. - starttime = models.SmallIntegerField(db_column='StartTime', blank=True, null=True) # Field name made lowercase. - stationfieldnumber = models.CharField(db_column='StationFieldNumber', max_length=50, blank=True, null=True) # Field name made lowercase. - verbatimdate = models.CharField(db_column='VerbatimDate', max_length=50, blank=True, null=True) # Field name made lowercase. - verbatimlocality = models.TextField(db_column='VerbatimLocality', blank=True, null=True) # Field name made lowercase. - visibility = models.IntegerField(db_column='Visibility', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - collectingtripid = models.ForeignKey('Collectingtrip', models.DO_NOTHING, db_column='CollectingTripID', blank=True, null=True) # Field name made lowercase. - collectingeventattributeid = models.ForeignKey('Collectingeventattribute', models.DO_NOTHING, db_column='CollectingEventAttributeID', blank=True, null=True) # Field name made lowercase. - visibilitysetbyid = models.ForeignKey('Specifyuser', models.DO_NOTHING, db_column='VisibilitySetByID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - disciplineid = models.ForeignKey('Discipline', models.DO_NOTHING, db_column='DisciplineID') # Field name made lowercase. - localityid = models.ForeignKey('Locality', models.DO_NOTHING, db_column='LocalityID', blank=True, null=True) # Field name made lowercase. - integer1 = models.IntegerField(db_column='Integer1', blank=True, null=True) # Field name made lowercase. - integer2 = models.IntegerField(db_column='Integer2', blank=True, null=True) # Field name made lowercase. - reservedinteger3 = models.IntegerField(db_column='ReservedInteger3', blank=True, null=True) # Field name made lowercase. - reservedinteger4 = models.IntegerField(db_column='ReservedInteger4', blank=True, null=True) # Field name made lowercase. - reservedtext1 = models.CharField(db_column='ReservedText1', max_length=128, blank=True, null=True) # Field name made lowercase. - reservedtext2 = models.CharField(db_column='ReservedText2', max_length=128, blank=True, null=True) # Field name made lowercase. - text1 = models.TextField(db_column='Text1', blank=True, null=True) # Field name made lowercase. - text2 = models.TextField(db_column='Text2', blank=True, null=True) # Field name made lowercase. - paleocontextid = models.ForeignKey('Paleocontext', models.DO_NOTHING, db_column='PaleoContextID', blank=True, null=True) # Field name made lowercase. - stationfieldnumbermodifier1 = models.CharField(db_column='StationFieldNumberModifier1', max_length=50, blank=True, null=True) # Field name made lowercase. - stationfieldnumbermodifier2 = models.CharField(db_column='StationFieldNumberModifier2', max_length=50, blank=True, null=True) # Field name made lowercase. - stationfieldnumbermodifier3 = models.CharField(db_column='StationFieldNumberModifier3', max_length=50, blank=True, null=True) # Field name made lowercase. - text3 = models.TextField(db_column='Text3', blank=True, null=True) # Field name made lowercase. - text4 = models.TextField(db_column='Text4', blank=True, null=True) # Field name made lowercase. - text5 = models.TextField(db_column='Text5', blank=True, null=True) # Field name made lowercase. - text6 = models.TextField(db_column='Text6', blank=True, null=True) # Field name made lowercase. - text7 = models.TextField(db_column='Text7', blank=True, null=True) # Field name made lowercase. - text8 = models.TextField(db_column='Text8', blank=True, null=True) # Field name made lowercase. - uniqueidentifier = models.CharField(db_column='UniqueIdentifier', max_length=128, blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'collectingevent' - unique_together = (('disciplineid', 'uniqueidentifier'),) - - -class Collectingeventattachment(models.Model): - collectingeventattachmentid = models.AutoField(db_column='CollectingEventAttachmentID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - collectionmemberid = models.IntegerField(db_column='CollectionMemberID') # Field name made lowercase. - ordinal = models.IntegerField(db_column='Ordinal') # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - collectingeventid = models.ForeignKey(Collectingevent, models.DO_NOTHING, db_column='CollectingEventID') # Field name made lowercase. - attachmentid = models.ForeignKey(Attachment, models.DO_NOTHING, db_column='AttachmentID') # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'collectingeventattachment' - - -class Collectingeventattr(models.Model): - attrid = models.AutoField(db_column='AttrID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - collectionmemberid = models.IntegerField(db_column='CollectionMemberID') # Field name made lowercase. - doublevalue = models.FloatField(db_column='DoubleValue', blank=True, null=True) # Field name made lowercase. - strvalue = models.CharField(db_column='StrValue', max_length=255, blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - collectingeventid = models.ForeignKey(Collectingevent, models.DO_NOTHING, db_column='CollectingEventID') # Field name made lowercase. - attributedefid = models.ForeignKey(Attributedef, models.DO_NOTHING, db_column='AttributeDefID') # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'collectingeventattr' - - -class Collectingeventattribute(models.Model): - collectingeventattributeid = models.AutoField(db_column='CollectingEventAttributeID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - number1 = models.DecimalField(db_column='Number1', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number10 = models.DecimalField(db_column='Number10', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number11 = models.DecimalField(db_column='Number11', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number12 = models.DecimalField(db_column='Number12', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number13 = models.DecimalField(db_column='Number13', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number2 = models.DecimalField(db_column='Number2', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number3 = models.DecimalField(db_column='Number3', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number4 = models.DecimalField(db_column='Number4', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number5 = models.DecimalField(db_column='Number5', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number6 = models.DecimalField(db_column='Number6', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number7 = models.DecimalField(db_column='Number7', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number8 = models.DecimalField(db_column='Number8', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number9 = models.DecimalField(db_column='Number9', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - text1 = models.TextField(db_column='Text1', blank=True, null=True) # Field name made lowercase. - text10 = models.TextField(db_column='Text10', blank=True, null=True) # Field name made lowercase. - text11 = models.TextField(db_column='Text11', blank=True, null=True) # Field name made lowercase. - text12 = models.TextField(db_column='Text12', blank=True, null=True) # Field name made lowercase. - text13 = models.TextField(db_column='Text13', blank=True, null=True) # Field name made lowercase. - text14 = models.TextField(db_column='Text14', blank=True, null=True) # Field name made lowercase. - text15 = models.TextField(db_column='Text15', blank=True, null=True) # Field name made lowercase. - text16 = models.TextField(db_column='Text16', blank=True, null=True) # Field name made lowercase. - text17 = models.TextField(db_column='Text17', blank=True, null=True) # Field name made lowercase. - text2 = models.TextField(db_column='Text2', blank=True, null=True) # Field name made lowercase. - text3 = models.TextField(db_column='Text3', blank=True, null=True) # Field name made lowercase. - text4 = models.TextField(db_column='Text4', blank=True, null=True) # Field name made lowercase. - text5 = models.TextField(db_column='Text5', blank=True, null=True) # Field name made lowercase. - text6 = models.TextField(db_column='Text6', blank=True, null=True) # Field name made lowercase. - text7 = models.TextField(db_column='Text7', blank=True, null=True) # Field name made lowercase. - text8 = models.TextField(db_column='Text8', blank=True, null=True) # Field name made lowercase. - text9 = models.TextField(db_column='Text9', blank=True, null=True) # Field name made lowercase. - yesno1 = models.BooleanField(db_column='YesNo1', blank=True, null=True) # Field name made lowercase. - yesno2 = models.BooleanField(db_column='YesNo2', blank=True, null=True) # Field name made lowercase. - yesno3 = models.BooleanField(db_column='YesNo3', blank=True, null=True) # Field name made lowercase. - yesno4 = models.BooleanField(db_column='YesNo4', blank=True, null=True) # Field name made lowercase. - yesno5 = models.BooleanField(db_column='YesNo5', blank=True, null=True) # Field name made lowercase. - disciplineid = models.ForeignKey('Discipline', models.DO_NOTHING, db_column='DisciplineID') # Field name made lowercase. - hosttaxonid = models.ForeignKey('Taxon', models.DO_NOTHING, db_column='HostTaxonID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - integer1 = models.IntegerField(db_column='Integer1', blank=True, null=True) # Field name made lowercase. - integer10 = models.IntegerField(db_column='Integer10', blank=True, null=True) # Field name made lowercase. - integer2 = models.IntegerField(db_column='Integer2', blank=True, null=True) # Field name made lowercase. - integer3 = models.IntegerField(db_column='Integer3', blank=True, null=True) # Field name made lowercase. - integer4 = models.IntegerField(db_column='Integer4', blank=True, null=True) # Field name made lowercase. - integer5 = models.IntegerField(db_column='Integer5', blank=True, null=True) # Field name made lowercase. - integer6 = models.IntegerField(db_column='Integer6', blank=True, null=True) # Field name made lowercase. - integer7 = models.IntegerField(db_column='Integer7', blank=True, null=True) # Field name made lowercase. - integer8 = models.IntegerField(db_column='Integer8', blank=True, null=True) # Field name made lowercase. - integer9 = models.IntegerField(db_column='Integer9', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'collectingeventattribute' - - -class Collectingeventauthorization(models.Model): - collectingeventauthorizationid = models.AutoField(db_column='CollectingEventAuthorizationID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - permitid = models.ForeignKey('Permit', models.DO_NOTHING, db_column='PermitID') # Field name made lowercase. - collectingeventid = models.ForeignKey(Collectingevent, models.DO_NOTHING, db_column='CollectingEventID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'collectingeventauthorization' - - -class Collectingtrip(models.Model): - collectingtripid = models.AutoField(db_column='CollectingTripID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - collectingtripname = models.CharField(db_column='Collectingtripname', max_length=400, blank=True, null=True) # Field name made lowercase. - enddate = models.DateField(db_column='EndDate', blank=True, null=True) # Field name made lowercase. - enddateprecision = models.IntegerField(db_column='EndDatePrecision', blank=True, null=True) # Field name made lowercase. - enddateverbatim = models.CharField(db_column='EndDateVerbatim', max_length=50, blank=True, null=True) # Field name made lowercase. - endtime = models.SmallIntegerField(db_column='EndTime', blank=True, null=True) # Field name made lowercase. - number1 = models.IntegerField(db_column='Number1', blank=True, null=True) # Field name made lowercase. - number2 = models.IntegerField(db_column='Number2', blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - sponsor = models.CharField(db_column='Sponsor', max_length=64, blank=True, null=True) # Field name made lowercase. - startdate = models.DateField(db_column='StartDate', blank=True, null=True) # Field name made lowercase. - startdateprecision = models.IntegerField(db_column='StartDatePrecision', blank=True, null=True) # Field name made lowercase. - startdateverbatim = models.CharField(db_column='StartDateVerbatim', max_length=50, blank=True, null=True) # Field name made lowercase. - starttime = models.SmallIntegerField(db_column='StartTime', blank=True, null=True) # Field name made lowercase. - text1 = models.CharField(db_column='Text1', max_length=255, blank=True, null=True) # Field name made lowercase. - text2 = models.CharField(db_column='Text2', max_length=128, blank=True, null=True) # Field name made lowercase. - text3 = models.CharField(db_column='Text3', max_length=64, blank=True, null=True) # Field name made lowercase. - text4 = models.CharField(db_column='Text4', max_length=64, blank=True, null=True) # Field name made lowercase. - yesno1 = models.BooleanField(db_column='YesNo1', blank=True, null=True) # Field name made lowercase. - yesno2 = models.BooleanField(db_column='YesNo2', blank=True, null=True) # Field name made lowercase. - disciplineid = models.ForeignKey('Discipline', models.DO_NOTHING, db_column='DisciplineID') # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - cruise = models.CharField(db_column='Cruise', max_length=250, blank=True, null=True) # Field name made lowercase. - expedition = models.CharField(db_column='Expedition', max_length=250, blank=True, null=True) # Field name made lowercase. - vessel = models.CharField(db_column='Vessel', max_length=250, blank=True, null=True) # Field name made lowercase. - date1 = models.DateField(db_column='Date1', blank=True, null=True) # Field name made lowercase. - date1precision = models.IntegerField(db_column='Date1Precision', blank=True, null=True) # Field name made lowercase. - date2 = models.DateField(db_column='Date2', blank=True, null=True) # Field name made lowercase. - date2precision = models.IntegerField(db_column='Date2Precision', blank=True, null=True) # Field name made lowercase. - text5 = models.TextField(db_column='Text5', blank=True, null=True) # Field name made lowercase. - text6 = models.TextField(db_column='Text6', blank=True, null=True) # Field name made lowercase. - text7 = models.TextField(db_column='Text7', blank=True, null=True) # Field name made lowercase. - text8 = models.TextField(db_column='Text8', blank=True, null=True) # Field name made lowercase. - text9 = models.TextField(db_column='Text9', blank=True, null=True) # Field name made lowercase. - agent2id = models.ForeignKey(Agent, models.DO_NOTHING, db_column='Agent2ID', blank=True, null=True) # Field name made lowercase. - collectingtripattributeid = models.ForeignKey('Collectingtripattribute', models.DO_NOTHING, db_column='CollectingTripAttributeID', blank=True, null=True) # Field name made lowercase. - agent1id = models.ForeignKey(Agent, models.DO_NOTHING, db_column='Agent1ID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'collectingtrip' - - -class Collectingtripattachment(models.Model): - collectingtripattachmentid = models.AutoField(db_column='CollectingTripAttachmentID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - collectionmemberid = models.IntegerField(db_column='CollectionMemberID') # Field name made lowercase. - ordinal = models.IntegerField(db_column='Ordinal') # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - collectingtripid = models.ForeignKey(Collectingtrip, models.DO_NOTHING, db_column='CollectingTripID') # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - attachmentid = models.ForeignKey(Attachment, models.DO_NOTHING, db_column='AttachmentID') # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'collectingtripattachment' - - -class Collectingtripattribute(models.Model): - collectingtripattributeid = models.AutoField(db_column='CollectingTripAttributeID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - integer1 = models.IntegerField(db_column='Integer1', blank=True, null=True) # Field name made lowercase. - integer10 = models.IntegerField(db_column='Integer10', blank=True, null=True) # Field name made lowercase. - integer2 = models.IntegerField(db_column='Integer2', blank=True, null=True) # Field name made lowercase. - integer3 = models.IntegerField(db_column='Integer3', blank=True, null=True) # Field name made lowercase. - integer4 = models.IntegerField(db_column='Integer4', blank=True, null=True) # Field name made lowercase. - integer5 = models.IntegerField(db_column='Integer5', blank=True, null=True) # Field name made lowercase. - integer6 = models.IntegerField(db_column='Integer6', blank=True, null=True) # Field name made lowercase. - integer7 = models.IntegerField(db_column='Integer7', blank=True, null=True) # Field name made lowercase. - integer8 = models.IntegerField(db_column='Integer8', blank=True, null=True) # Field name made lowercase. - integer9 = models.IntegerField(db_column='Integer9', blank=True, null=True) # Field name made lowercase. - number1 = models.DecimalField(db_column='Number1', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number10 = models.DecimalField(db_column='Number10', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number11 = models.DecimalField(db_column='Number11', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number12 = models.DecimalField(db_column='Number12', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number13 = models.DecimalField(db_column='Number13', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number2 = models.DecimalField(db_column='Number2', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number3 = models.DecimalField(db_column='Number3', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number4 = models.DecimalField(db_column='Number4', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number5 = models.DecimalField(db_column='Number5', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number6 = models.DecimalField(db_column='Number6', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number7 = models.DecimalField(db_column='Number7', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number8 = models.DecimalField(db_column='Number8', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number9 = models.DecimalField(db_column='Number9', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - text1 = models.TextField(db_column='Text1', blank=True, null=True) # Field name made lowercase. - text10 = models.CharField(db_column='Text10', max_length=50, blank=True, null=True) # Field name made lowercase. - text11 = models.CharField(db_column='Text11', max_length=50, blank=True, null=True) # Field name made lowercase. - text12 = models.CharField(db_column='Text12', max_length=50, blank=True, null=True) # Field name made lowercase. - text13 = models.CharField(db_column='Text13', max_length=50, blank=True, null=True) # Field name made lowercase. - text14 = models.CharField(db_column='Text14', max_length=50, blank=True, null=True) # Field name made lowercase. - text15 = models.CharField(db_column='Text15', max_length=50, blank=True, null=True) # Field name made lowercase. - text16 = models.CharField(db_column='Text16', max_length=50, blank=True, null=True) # Field name made lowercase. - text17 = models.CharField(db_column='Text17', max_length=50, blank=True, null=True) # Field name made lowercase. - text2 = models.TextField(db_column='Text2', blank=True, null=True) # Field name made lowercase. - text3 = models.TextField(db_column='Text3', blank=True, null=True) # Field name made lowercase. - text4 = models.CharField(db_column='Text4', max_length=100, blank=True, null=True) # Field name made lowercase. - text5 = models.CharField(db_column='Text5', max_length=100, blank=True, null=True) # Field name made lowercase. - text6 = models.CharField(db_column='Text6', max_length=50, blank=True, null=True) # Field name made lowercase. - text7 = models.CharField(db_column='Text7', max_length=50, blank=True, null=True) # Field name made lowercase. - text8 = models.CharField(db_column='Text8', max_length=50, blank=True, null=True) # Field name made lowercase. - text9 = models.CharField(db_column='Text9', max_length=50, blank=True, null=True) # Field name made lowercase. - yesno1 = models.BooleanField(db_column='YesNo1', blank=True, null=True) # Field name made lowercase. - yesno2 = models.BooleanField(db_column='YesNo2', blank=True, null=True) # Field name made lowercase. - yesno3 = models.BooleanField(db_column='YesNo3', blank=True, null=True) # Field name made lowercase. - yesno4 = models.BooleanField(db_column='YesNo4', blank=True, null=True) # Field name made lowercase. - yesno5 = models.BooleanField(db_column='YesNo5', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - disciplineid = models.ForeignKey('Discipline', models.DO_NOTHING, db_column='DisciplineID') # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'collectingtripattribute' - - -class Collectingtripauthorization(models.Model): - collectingtripauthorizationid = models.AutoField(db_column='CollectingTripAuthorizationID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - collectingtripid = models.ForeignKey(Collectingtrip, models.DO_NOTHING, db_column='CollectingTripID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - permitid = models.ForeignKey('Permit', models.DO_NOTHING, db_column='PermitID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'collectingtripauthorization' - - -class Collection(models.Model): - usergroupscopeid = models.IntegerField(db_column='UserGroupScopeId', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - catalogformatnumname = models.CharField(db_column='CatalogFormatNumName', max_length=64) # Field name made lowercase. - code = models.CharField(db_column='Code', max_length=50, blank=True, null=True) # Field name made lowercase. - collectionid = models.IntegerField(db_column='collectionId', blank=True, null=True) # Field name made lowercase. - collectionname = models.CharField(db_column='CollectionName', max_length=50, blank=True, null=True) # Field name made lowercase. - collectiontype = models.CharField(db_column='CollectionType', max_length=32, blank=True, null=True) # Field name made lowercase. - dbcontentversion = models.CharField(db_column='DbContentVersion', max_length=32, blank=True, null=True) # Field name made lowercase. - description = models.TextField(db_column='Description', blank=True, null=True) # Field name made lowercase. - developmentstatus = models.CharField(db_column='DevelopmentStatus', max_length=32, blank=True, null=True) # Field name made lowercase. - estimatedsize = models.IntegerField(db_column='EstimatedSize', blank=True, null=True) # Field name made lowercase. - guid = models.CharField(db_column='GUID', max_length=128, blank=True, null=True) # Field name made lowercase. - institutiontype = models.CharField(db_column='InstitutionType', max_length=32, blank=True, null=True) # Field name made lowercase. - isembeddedcollectingevent = models.BooleanField(db_column='IsEmbeddedCollectingEvent') # Field name made lowercase. - isanumber = models.CharField(db_column='IsaNumber', max_length=24, blank=True, null=True) # Field name made lowercase. - kingdomcoverage = models.CharField(db_column='KingdomCoverage', max_length=32, blank=True, null=True) # Field name made lowercase. - preservationmethodtype = models.CharField(db_column='PreservationMethodType', max_length=32, blank=True, null=True) # Field name made lowercase. - primaryfocus = models.CharField(db_column='PrimaryFocus', max_length=32, blank=True, null=True) # Field name made lowercase. - primarypurpose = models.CharField(db_column='PrimaryPurpose', max_length=32, blank=True, null=True) # Field name made lowercase. - regnumber = models.CharField(db_column='RegNumber', max_length=24, blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - scope = models.TextField(db_column='Scope', blank=True, null=True) # Field name made lowercase. - webportaluri = models.CharField(db_column='WebPortalURI', max_length=255, blank=True, null=True) # Field name made lowercase. - websiteuri = models.CharField(db_column='WebSiteURI', max_length=255, blank=True, null=True) # Field name made lowercase. - institutionnetworkid = models.ForeignKey('Institution', models.DO_NOTHING, db_column='InstitutionNetworkID', blank=True, null=True) # Field name made lowercase. - disciplineid = models.ForeignKey('Discipline', models.DO_NOTHING, db_column='DisciplineID') # Field name made lowercase. - admincontactid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='AdminContactID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'collection' - - -class Collectionobject(models.Model): - collectionobjectid = models.AutoField(db_column='CollectionObjectID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - collectionmemberid = models.IntegerField(db_column='CollectionMemberID') # Field name made lowercase. - altcatalognumber = models.CharField(db_column='AltCatalogNumber', max_length=64, blank=True, null=True) # Field name made lowercase. - availability = models.CharField(db_column='Availability', max_length=32, blank=True, null=True) # Field name made lowercase. - catalognumber = models.CharField(db_column='CatalogNumber', max_length=32, blank=True, null=True) # Field name made lowercase. - catalogeddate = models.DateField(db_column='CatalogedDate', blank=True, null=True) # Field name made lowercase. - catalogeddateprecision = models.IntegerField(db_column='CatalogedDatePrecision', blank=True, null=True) # Field name made lowercase. - catalogeddateverbatim = models.CharField(db_column='CatalogedDateVerbatim', max_length=32, blank=True, null=True) # Field name made lowercase. - countamt = models.IntegerField(db_column='CountAmt', blank=True, null=True) # Field name made lowercase. - deaccessioned = models.BooleanField(db_column='Deaccessioned', blank=True, null=True) # Field name made lowercase. - description = models.TextField(db_column='Description', blank=True, null=True) # Field name made lowercase. - fieldnumber = models.CharField(db_column='FieldNumber', max_length=50, blank=True, null=True) # Field name made lowercase. - guid = models.CharField(db_column='GUID', max_length=128, blank=True, null=True) # Field name made lowercase. - inventorydate = models.DateField(db_column='InventoryDate', blank=True, null=True) # Field name made lowercase. - modifier = models.CharField(db_column='Modifier', max_length=50, blank=True, null=True) # Field name made lowercase. - name = models.CharField(db_column='Name', max_length=64, blank=True, null=True) # Field name made lowercase. - notifications = models.CharField(db_column='Notifications', max_length=32, blank=True, null=True) # Field name made lowercase. - number1 = models.DecimalField(db_column='Number1', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number2 = models.DecimalField(db_column='Number2', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - objectcondition = models.CharField(db_column='ObjectCondition', max_length=64, blank=True, null=True) # Field name made lowercase. - ocr = models.TextField(db_column='OCR', blank=True, null=True) # Field name made lowercase. - projectnumber = models.CharField(db_column='ProjectNumber', max_length=64, blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - restrictions = models.CharField(db_column='Restrictions', max_length=32, blank=True, null=True) # Field name made lowercase. - sgrstatus = models.IntegerField(db_column='SGRStatus', blank=True, null=True) # Field name made lowercase. - text1 = models.TextField(db_column='Text1', blank=True, null=True) # Field name made lowercase. - text2 = models.TextField(db_column='Text2', blank=True, null=True) # Field name made lowercase. - totalvalue = models.DecimalField(db_column='TotalValue', max_digits=12, decimal_places=2, blank=True, null=True) # Field name made lowercase. - visibility = models.IntegerField(db_column='Visibility', blank=True, null=True) # Field name made lowercase. - yesno1 = models.BooleanField(db_column='YesNo1', blank=True, null=True) # Field name made lowercase. - yesno2 = models.BooleanField(db_column='YesNo2', blank=True, null=True) # Field name made lowercase. - yesno3 = models.BooleanField(db_column='YesNo3', blank=True, null=True) # Field name made lowercase. - yesno4 = models.BooleanField(db_column='YesNo4', blank=True, null=True) # Field name made lowercase. - yesno5 = models.BooleanField(db_column='YesNo5', blank=True, null=True) # Field name made lowercase. - yesno6 = models.BooleanField(db_column='YesNo6', blank=True, null=True) # Field name made lowercase. - collectionid = models.ForeignKey(Collection, models.DO_NOTHING, db_column='CollectionID') # Field name made lowercase. - appraisalid = models.ForeignKey(Appraisal, models.DO_NOTHING, db_column='AppraisalID', blank=True, null=True) # Field name made lowercase. - collectingeventid = models.ForeignKey(Collectingevent, models.DO_NOTHING, db_column='CollectingEventID', blank=True, null=True) # Field name made lowercase. - containerid = models.ForeignKey('Container', models.DO_NOTHING, db_column='ContainerID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - containerownerid = models.ForeignKey('Container', models.DO_NOTHING, db_column='ContainerOwnerID', blank=True, null=True) # Field name made lowercase. - fieldnotebookpageid = models.ForeignKey('Fieldnotebookpage', models.DO_NOTHING, db_column='FieldNotebookPageID', blank=True, null=True) # Field name made lowercase. - accessionid = models.ForeignKey(Accession, models.DO_NOTHING, db_column='AccessionID', blank=True, null=True) # Field name made lowercase. - paleocontextid = models.ForeignKey('Paleocontext', models.DO_NOTHING, db_column='PaleoContextID', blank=True, null=True) # Field name made lowercase. - visibilitysetbyid = models.ForeignKey('Specifyuser', models.DO_NOTHING, db_column='VisibilitySetByID', blank=True, null=True) # Field name made lowercase. - catalogerid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CatalogerID', blank=True, null=True) # Field name made lowercase. - collectionobjectattributeid = models.ForeignKey('Collectionobjectattribute', models.DO_NOTHING, db_column='CollectionObjectAttributeID', blank=True, null=True) # Field name made lowercase. - reservedtext = models.CharField(db_column='ReservedText', max_length=128, blank=True, null=True) # Field name made lowercase. - text3 = models.TextField(db_column='Text3', blank=True, null=True) # Field name made lowercase. - integer1 = models.IntegerField(db_column='Integer1', blank=True, null=True) # Field name made lowercase. - integer2 = models.IntegerField(db_column='Integer2', blank=True, null=True) # Field name made lowercase. - reservedinteger3 = models.IntegerField(db_column='ReservedInteger3', blank=True, null=True) # Field name made lowercase. - reservedinteger4 = models.IntegerField(db_column='ReservedInteger4', blank=True, null=True) # Field name made lowercase. - reservedtext2 = models.CharField(db_column='ReservedText2', max_length=128, blank=True, null=True) # Field name made lowercase. - reservedtext3 = models.CharField(db_column='ReservedText3', max_length=128, blank=True, null=True) # Field name made lowercase. - inventorizedbyid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='InventorizedByID', blank=True, null=True) # Field name made lowercase. - date1 = models.DateField(db_column='Date1', blank=True, null=True) # Field name made lowercase. - date1precision = models.IntegerField(db_column='Date1Precision', blank=True, null=True) # Field name made lowercase. - inventorydateprecision = models.IntegerField(db_column='InventoryDatePrecision', blank=True, null=True) # Field name made lowercase. - agent1id = models.ForeignKey(Agent, models.DO_NOTHING, db_column='Agent1ID', blank=True, null=True) # Field name made lowercase. - numberofduplicates = models.IntegerField(db_column='NumberOfDuplicates', blank=True, null=True) # Field name made lowercase. - embargoreason = models.TextField(db_column='EmbargoReason', blank=True, null=True) # Field name made lowercase. - embargoreleasedate = models.DateField(db_column='EmbargoReleaseDate', blank=True, null=True) # Field name made lowercase. - embargoreleasedateprecision = models.IntegerField(db_column='EmbargoReleaseDatePrecision', blank=True, null=True) # Field name made lowercase. - embargostartdate = models.DateField(db_column='EmbargoStartDate', blank=True, null=True) # Field name made lowercase. - embargostartdateprecision = models.IntegerField(db_column='EmbargoStartDatePrecision', blank=True, null=True) # Field name made lowercase. - text4 = models.TextField(db_column='Text4', blank=True, null=True) # Field name made lowercase. - text5 = models.TextField(db_column='Text5', blank=True, null=True) # Field name made lowercase. - text6 = models.TextField(db_column='Text6', blank=True, null=True) # Field name made lowercase. - text7 = models.TextField(db_column='Text7', blank=True, null=True) # Field name made lowercase. - text8 = models.TextField(db_column='Text8', blank=True, null=True) # Field name made lowercase. - uniqueidentifier = models.CharField(db_column='UniqueIdentifier', max_length=128, blank=True, null=True) # Field name made lowercase. - embargoauthorityid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='EmbargoAuthorityID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'collectionobject' - unique_together = (('collectionid', 'catalognumber'), ('collectionid', 'uniqueidentifier'),) - - -class Collectionobjectattachment(models.Model): - collectionobjectattachmentid = models.AutoField(db_column='CollectionObjectAttachmentID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - collectionmemberid = models.IntegerField(db_column='CollectionMemberID') # Field name made lowercase. - ordinal = models.IntegerField(db_column='Ordinal') # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - collectionobjectid = models.ForeignKey(Collectionobject, models.DO_NOTHING, db_column='CollectionObjectID') # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - attachmentid = models.ForeignKey(Attachment, models.DO_NOTHING, db_column='AttachmentID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'collectionobjectattachment' - - -class Collectionobjectattr(models.Model): - attrid = models.AutoField(db_column='AttrID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - collectionmemberid = models.IntegerField(db_column='CollectionMemberID') # Field name made lowercase. - doublevalue = models.FloatField(db_column='DoubleValue', blank=True, null=True) # Field name made lowercase. - strvalue = models.CharField(db_column='StrValue', max_length=255, blank=True, null=True) # Field name made lowercase. - attributedefid = models.ForeignKey(Attributedef, models.DO_NOTHING, db_column='AttributeDefID') # Field name made lowercase. - collectionobjectid = models.ForeignKey(Collectionobject, models.DO_NOTHING, db_column='CollectionObjectID') # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'collectionobjectattr' - - -class Collectionobjectattribute(models.Model): - collectionobjectattributeid = models.AutoField(db_column='CollectionObjectAttributeID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - collectionmemberid = models.IntegerField(db_column='CollectionMemberID') # Field name made lowercase. - number1 = models.DecimalField(db_column='Number1', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number10 = models.DecimalField(db_column='Number10', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number11 = models.DecimalField(db_column='Number11', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number12 = models.DecimalField(db_column='Number12', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number13 = models.DecimalField(db_column='Number13', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number14 = models.DecimalField(db_column='Number14', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number15 = models.DecimalField(db_column='Number15', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number16 = models.DecimalField(db_column='Number16', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number17 = models.DecimalField(db_column='Number17', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number18 = models.DecimalField(db_column='Number18', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number19 = models.DecimalField(db_column='Number19', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number2 = models.DecimalField(db_column='Number2', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number20 = models.DecimalField(db_column='Number20', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number21 = models.DecimalField(db_column='Number21', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number22 = models.DecimalField(db_column='Number22', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number23 = models.DecimalField(db_column='Number23', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number24 = models.DecimalField(db_column='Number24', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number25 = models.DecimalField(db_column='Number25', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number26 = models.DecimalField(db_column='Number26', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number27 = models.DecimalField(db_column='Number27', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number28 = models.DecimalField(db_column='Number28', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number29 = models.DecimalField(db_column='Number29', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number3 = models.DecimalField(db_column='Number3', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number30 = models.IntegerField(blank=True, null=True) - number31 = models.DecimalField(db_column='Number31', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number32 = models.DecimalField(db_column='Number32', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number33 = models.DecimalField(db_column='Number33', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number34 = models.DecimalField(db_column='Number34', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number35 = models.DecimalField(db_column='Number35', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number36 = models.DecimalField(db_column='Number36', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number37 = models.DecimalField(db_column='Number37', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number38 = models.DecimalField(db_column='Number38', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number39 = models.DecimalField(db_column='Number39', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number4 = models.DecimalField(db_column='Number4', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number40 = models.DecimalField(db_column='Number40', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number41 = models.DecimalField(db_column='Number41', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number42 = models.DecimalField(db_column='Number42', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number5 = models.DecimalField(db_column='Number5', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number6 = models.DecimalField(db_column='Number6', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number7 = models.DecimalField(db_column='Number7', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number8 = models.IntegerField(blank=True, null=True) - number9 = models.DecimalField(db_column='Number9', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - text1 = models.TextField(db_column='Text1', blank=True, null=True) # Field name made lowercase. - text10 = models.CharField(db_column='Text10', max_length=50, blank=True, null=True) # Field name made lowercase. - text11 = models.CharField(db_column='Text11', max_length=50, blank=True, null=True) # Field name made lowercase. - text12 = models.CharField(db_column='Text12', max_length=50, blank=True, null=True) # Field name made lowercase. - text13 = models.CharField(db_column='Text13', max_length=50, blank=True, null=True) # Field name made lowercase. - text14 = models.CharField(db_column='Text14', max_length=50, blank=True, null=True) # Field name made lowercase. - text15 = models.CharField(db_column='Text15', max_length=64, blank=True, null=True) # Field name made lowercase. - text2 = models.TextField(db_column='Text2', blank=True, null=True) # Field name made lowercase. - text3 = models.TextField(db_column='Text3', blank=True, null=True) # Field name made lowercase. - text4 = models.CharField(db_column='Text4', max_length=50, blank=True, null=True) # Field name made lowercase. - text5 = models.CharField(db_column='Text5', max_length=50, blank=True, null=True) # Field name made lowercase. - text6 = models.CharField(db_column='Text6', max_length=100, blank=True, null=True) # Field name made lowercase. - text7 = models.CharField(db_column='Text7', max_length=100, blank=True, null=True) # Field name made lowercase. - text8 = models.CharField(db_column='Text8', max_length=50, blank=True, null=True) # Field name made lowercase. - text9 = models.CharField(db_column='Text9', max_length=50, blank=True, null=True) # Field name made lowercase. - yesno1 = models.BooleanField(db_column='YesNo1', blank=True, null=True) # Field name made lowercase. - yesno2 = models.BooleanField(db_column='YesNo2', blank=True, null=True) # Field name made lowercase. - yesno3 = models.BooleanField(db_column='YesNo3', blank=True, null=True) # Field name made lowercase. - yesno4 = models.BooleanField(db_column='YesNo4', blank=True, null=True) # Field name made lowercase. - yesno5 = models.BooleanField(db_column='YesNo5', blank=True, null=True) # Field name made lowercase. - yesno6 = models.BooleanField(db_column='YesNo6', blank=True, null=True) # Field name made lowercase. - yesno7 = models.BooleanField(db_column='YesNo7', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - bottomdistance = models.DecimalField(db_column='BottomDistance', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - direction = models.CharField(db_column='Direction', max_length=32, blank=True, null=True) # Field name made lowercase. - distanceunits = models.CharField(db_column='DistanceUnits', max_length=16, blank=True, null=True) # Field name made lowercase. - positionstate = models.CharField(db_column='PositionState', max_length=32, blank=True, null=True) # Field name made lowercase. - topdistance = models.DecimalField(db_column='TopDistance', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - text16 = models.TextField(db_column='Text16', blank=True, null=True) # Field name made lowercase. - text17 = models.TextField(db_column='Text17', blank=True, null=True) # Field name made lowercase. - text18 = models.TextField(db_column='Text18', blank=True, null=True) # Field name made lowercase. - integer1 = models.IntegerField(db_column='Integer1', blank=True, null=True) # Field name made lowercase. - integer10 = models.IntegerField(db_column='Integer10', blank=True, null=True) # Field name made lowercase. - integer2 = models.IntegerField(db_column='Integer2', blank=True, null=True) # Field name made lowercase. - integer3 = models.IntegerField(db_column='Integer3', blank=True, null=True) # Field name made lowercase. - integer4 = models.IntegerField(db_column='Integer4', blank=True, null=True) # Field name made lowercase. - integer5 = models.IntegerField(db_column='Integer5', blank=True, null=True) # Field name made lowercase. - integer6 = models.IntegerField(db_column='Integer6', blank=True, null=True) # Field name made lowercase. - integer7 = models.IntegerField(db_column='Integer7', blank=True, null=True) # Field name made lowercase. - integer8 = models.IntegerField(db_column='Integer8', blank=True, null=True) # Field name made lowercase. - integer9 = models.IntegerField(db_column='Integer9', blank=True, null=True) # Field name made lowercase. - text19 = models.TextField(db_column='Text19', blank=True, null=True) # Field name made lowercase. - text20 = models.TextField(db_column='Text20', blank=True, null=True) # Field name made lowercase. - text21 = models.TextField(db_column='Text21', blank=True, null=True) # Field name made lowercase. - text22 = models.TextField(db_column='Text22', blank=True, null=True) # Field name made lowercase. - text23 = models.TextField(db_column='Text23', blank=True, null=True) # Field name made lowercase. - text24 = models.TextField(db_column='Text24', blank=True, null=True) # Field name made lowercase. - text25 = models.TextField(db_column='Text25', blank=True, null=True) # Field name made lowercase. - text26 = models.TextField(db_column='Text26', blank=True, null=True) # Field name made lowercase. - text27 = models.TextField(db_column='Text27', blank=True, null=True) # Field name made lowercase. - text28 = models.TextField(db_column='Text28', blank=True, null=True) # Field name made lowercase. - text29 = models.TextField(db_column='Text29', blank=True, null=True) # Field name made lowercase. - text30 = models.TextField(db_column='Text30', blank=True, null=True) # Field name made lowercase. - yesno10 = models.BooleanField(db_column='YesNo10', blank=True, null=True) # Field name made lowercase. - yesno11 = models.BooleanField(db_column='YesNo11', blank=True, null=True) # Field name made lowercase. - yesno12 = models.BooleanField(db_column='YesNo12', blank=True, null=True) # Field name made lowercase. - yesno13 = models.BooleanField(db_column='YesNo13', blank=True, null=True) # Field name made lowercase. - yesno14 = models.BooleanField(db_column='YesNo14', blank=True, null=True) # Field name made lowercase. - yesno15 = models.BooleanField(db_column='YesNo15', blank=True, null=True) # Field name made lowercase. - yesno16 = models.BooleanField(db_column='YesNo16', blank=True, null=True) # Field name made lowercase. - yesno17 = models.BooleanField(db_column='YesNo17', blank=True, null=True) # Field name made lowercase. - yesno18 = models.BooleanField(db_column='YesNo18', blank=True, null=True) # Field name made lowercase. - yesno19 = models.BooleanField(db_column='YesNo19', blank=True, null=True) # Field name made lowercase. - yesno20 = models.BooleanField(db_column='YesNo20', blank=True, null=True) # Field name made lowercase. - yesno8 = models.BooleanField(db_column='YesNo8', blank=True, null=True) # Field name made lowercase. - yesno9 = models.BooleanField(db_column='YesNo9', blank=True, null=True) # Field name made lowercase. - date1 = models.DateField(db_column='Date1', blank=True, null=True) # Field name made lowercase. - date1precision = models.IntegerField(db_column='Date1Precision', blank=True, null=True) # Field name made lowercase. - agent1id = models.ForeignKey(Agent, models.DO_NOTHING, db_column='Agent1ID', blank=True, null=True) # Field name made lowercase. - text31 = models.TextField(db_column='Text31', blank=True, null=True) # Field name made lowercase. - text32 = models.TextField(db_column='Text32', blank=True, null=True) # Field name made lowercase. - text33 = models.TextField(db_column='Text33', blank=True, null=True) # Field name made lowercase. - text34 = models.TextField(db_column='Text34', blank=True, null=True) # Field name made lowercase. - text35 = models.TextField(db_column='Text35', blank=True, null=True) # Field name made lowercase. - text36 = models.TextField(db_column='Text36', blank=True, null=True) # Field name made lowercase. - text37 = models.TextField(db_column='Text37', blank=True, null=True) # Field name made lowercase. - text38 = models.TextField(db_column='Text38', blank=True, null=True) # Field name made lowercase. - text39 = models.TextField(db_column='Text39', blank=True, null=True) # Field name made lowercase. - text40 = models.TextField(db_column='Text40', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'collectionobjectattribute' - - -class Collectionobjectcitation(models.Model): - collectionobjectcitationid = models.AutoField(db_column='CollectionObjectCitationID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - collectionmemberid = models.IntegerField(db_column='CollectionMemberID') # Field name made lowercase. - isfigured = models.BooleanField(db_column='IsFigured', blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - referenceworkid = models.ForeignKey('Referencework', models.DO_NOTHING, db_column='ReferenceWorkID') # Field name made lowercase. - collectionobjectid = models.ForeignKey(Collectionobject, models.DO_NOTHING, db_column='CollectionObjectID') # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - figurenumber = models.CharField(db_column='FigureNumber', max_length=50, blank=True, null=True) # Field name made lowercase. - pagenumber = models.CharField(db_column='PageNumber', max_length=50, blank=True, null=True) # Field name made lowercase. - platenumber = models.CharField(db_column='PlateNumber', max_length=50, blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'collectionobjectcitation' - - -class Collectionobjectproperty(models.Model): - collectionobjectpropertyid = models.AutoField(db_column='CollectionObjectPropertyID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - collectionmemberid = models.IntegerField(db_column='CollectionMemberID') # Field name made lowercase. - date1 = models.DateField(db_column='Date1', blank=True, null=True) # Field name made lowercase. - date10 = models.DateField(db_column='Date10', blank=True, null=True) # Field name made lowercase. - date11 = models.DateField(db_column='Date11', blank=True, null=True) # Field name made lowercase. - date12 = models.DateField(db_column='Date12', blank=True, null=True) # Field name made lowercase. - date13 = models.DateField(db_column='Date13', blank=True, null=True) # Field name made lowercase. - date14 = models.DateField(db_column='Date14', blank=True, null=True) # Field name made lowercase. - date15 = models.DateField(db_column='Date15', blank=True, null=True) # Field name made lowercase. - date16 = models.DateField(db_column='Date16', blank=True, null=True) # Field name made lowercase. - date17 = models.DateField(db_column='Date17', blank=True, null=True) # Field name made lowercase. - date18 = models.DateField(db_column='Date18', blank=True, null=True) # Field name made lowercase. - date19 = models.DateField(db_column='Date19', blank=True, null=True) # Field name made lowercase. - date2 = models.DateField(db_column='Date2', blank=True, null=True) # Field name made lowercase. - date20 = models.DateField(db_column='Date20', blank=True, null=True) # Field name made lowercase. - date3 = models.DateField(db_column='Date3', blank=True, null=True) # Field name made lowercase. - date4 = models.DateField(db_column='Date4', blank=True, null=True) # Field name made lowercase. - date5 = models.DateField(db_column='Date5', blank=True, null=True) # Field name made lowercase. - date6 = models.DateField(db_column='Date6', blank=True, null=True) # Field name made lowercase. - date7 = models.DateField(db_column='Date7', blank=True, null=True) # Field name made lowercase. - date8 = models.DateField(db_column='Date8', blank=True, null=True) # Field name made lowercase. - date9 = models.DateField(db_column='Date9', blank=True, null=True) # Field name made lowercase. - guid = models.CharField(db_column='GUID', max_length=128, blank=True, null=True) # Field name made lowercase. - integer1 = models.SmallIntegerField(db_column='Integer1', blank=True, null=True) # Field name made lowercase. - integer10 = models.SmallIntegerField(db_column='Integer10', blank=True, null=True) # Field name made lowercase. - integer11 = models.SmallIntegerField(db_column='Integer11', blank=True, null=True) # Field name made lowercase. - integer12 = models.SmallIntegerField(db_column='Integer12', blank=True, null=True) # Field name made lowercase. - integer13 = models.SmallIntegerField(db_column='Integer13', blank=True, null=True) # Field name made lowercase. - integer14 = models.SmallIntegerField(db_column='Integer14', blank=True, null=True) # Field name made lowercase. - integer15 = models.SmallIntegerField(db_column='Integer15', blank=True, null=True) # Field name made lowercase. - integer16 = models.SmallIntegerField(db_column='Integer16', blank=True, null=True) # Field name made lowercase. - integer17 = models.SmallIntegerField(db_column='Integer17', blank=True, null=True) # Field name made lowercase. - integer18 = models.SmallIntegerField(db_column='Integer18', blank=True, null=True) # Field name made lowercase. - integer19 = models.SmallIntegerField(db_column='Integer19', blank=True, null=True) # Field name made lowercase. - integer2 = models.SmallIntegerField(db_column='Integer2', blank=True, null=True) # Field name made lowercase. - integer20 = models.SmallIntegerField(db_column='Integer20', blank=True, null=True) # Field name made lowercase. - integer21 = models.IntegerField(db_column='Integer21', blank=True, null=True) # Field name made lowercase. - integer22 = models.IntegerField(db_column='Integer22', blank=True, null=True) # Field name made lowercase. - integer23 = models.IntegerField(db_column='Integer23', blank=True, null=True) # Field name made lowercase. - integer24 = models.IntegerField(db_column='Integer24', blank=True, null=True) # Field name made lowercase. - integer25 = models.IntegerField(db_column='Integer25', blank=True, null=True) # Field name made lowercase. - integer26 = models.IntegerField(db_column='Integer26', blank=True, null=True) # Field name made lowercase. - integer27 = models.IntegerField(db_column='Integer27', blank=True, null=True) # Field name made lowercase. - integer28 = models.IntegerField(db_column='Integer28', blank=True, null=True) # Field name made lowercase. - integer29 = models.IntegerField(db_column='Integer29', blank=True, null=True) # Field name made lowercase. - integer3 = models.SmallIntegerField(db_column='Integer3', blank=True, null=True) # Field name made lowercase. - integer30 = models.IntegerField(db_column='Integer30', blank=True, null=True) # Field name made lowercase. - integer4 = models.SmallIntegerField(db_column='Integer4', blank=True, null=True) # Field name made lowercase. - integer5 = models.SmallIntegerField(db_column='Integer5', blank=True, null=True) # Field name made lowercase. - integer6 = models.SmallIntegerField(db_column='Integer6', blank=True, null=True) # Field name made lowercase. - integer7 = models.SmallIntegerField(db_column='Integer7', blank=True, null=True) # Field name made lowercase. - integer8 = models.SmallIntegerField(db_column='Integer8', blank=True, null=True) # Field name made lowercase. - integer9 = models.SmallIntegerField(db_column='Integer9', blank=True, null=True) # Field name made lowercase. - number1 = models.DecimalField(db_column='Number1', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number10 = models.DecimalField(db_column='Number10', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number11 = models.DecimalField(db_column='Number11', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number12 = models.DecimalField(db_column='Number12', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number13 = models.DecimalField(db_column='Number13', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number14 = models.DecimalField(db_column='Number14', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number15 = models.DecimalField(db_column='Number15', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number16 = models.DecimalField(db_column='Number16', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number17 = models.DecimalField(db_column='Number17', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number18 = models.DecimalField(db_column='Number18', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number19 = models.DecimalField(db_column='Number19', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number2 = models.DecimalField(db_column='Number2', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number20 = models.DecimalField(db_column='Number20', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number21 = models.DecimalField(db_column='Number21', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number22 = models.DecimalField(db_column='Number22', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number23 = models.DecimalField(db_column='Number23', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number24 = models.DecimalField(db_column='Number24', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number25 = models.DecimalField(db_column='Number25', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number26 = models.DecimalField(db_column='Number26', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number27 = models.DecimalField(db_column='Number27', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number28 = models.DecimalField(db_column='Number28', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number29 = models.DecimalField(db_column='Number29', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number3 = models.DecimalField(db_column='Number3', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number30 = models.DecimalField(db_column='Number30', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number4 = models.DecimalField(db_column='Number4', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number5 = models.DecimalField(db_column='Number5', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number6 = models.DecimalField(db_column='Number6', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number7 = models.DecimalField(db_column='Number7', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number8 = models.DecimalField(db_column='Number8', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number9 = models.DecimalField(db_column='Number9', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - text1 = models.CharField(db_column='Text1', max_length=50, blank=True, null=True) # Field name made lowercase. - text10 = models.CharField(db_column='Text10', max_length=50, blank=True, null=True) # Field name made lowercase. - text11 = models.CharField(db_column='Text11', max_length=50, blank=True, null=True) # Field name made lowercase. - text12 = models.CharField(db_column='Text12', max_length=50, blank=True, null=True) # Field name made lowercase. - text13 = models.CharField(db_column='Text13', max_length=50, blank=True, null=True) # Field name made lowercase. - text14 = models.CharField(db_column='Text14', max_length=50, blank=True, null=True) # Field name made lowercase. - text15 = models.CharField(db_column='Text15', max_length=50, blank=True, null=True) # Field name made lowercase. - text16 = models.CharField(db_column='Text16', max_length=100, blank=True, null=True) # Field name made lowercase. - text17 = models.CharField(db_column='Text17', max_length=100, blank=True, null=True) # Field name made lowercase. - text18 = models.CharField(db_column='Text18', max_length=100, blank=True, null=True) # Field name made lowercase. - text19 = models.CharField(db_column='Text19', max_length=100, blank=True, null=True) # Field name made lowercase. - text2 = models.CharField(db_column='Text2', max_length=50, blank=True, null=True) # Field name made lowercase. - text20 = models.CharField(db_column='Text20', max_length=100, blank=True, null=True) # Field name made lowercase. - text21 = models.CharField(db_column='Text21', max_length=100, blank=True, null=True) # Field name made lowercase. - text22 = models.CharField(db_column='Text22', max_length=100, blank=True, null=True) # Field name made lowercase. - text23 = models.CharField(db_column='Text23', max_length=100, blank=True, null=True) # Field name made lowercase. - text24 = models.CharField(db_column='Text24', max_length=100, blank=True, null=True) # Field name made lowercase. - text25 = models.CharField(db_column='Text25', max_length=100, blank=True, null=True) # Field name made lowercase. - text26 = models.CharField(db_column='Text26', max_length=100, blank=True, null=True) # Field name made lowercase. - text27 = models.CharField(db_column='Text27', max_length=100, blank=True, null=True) # Field name made lowercase. - text28 = models.CharField(db_column='Text28', max_length=100, blank=True, null=True) # Field name made lowercase. - text29 = models.CharField(db_column='Text29', max_length=100, blank=True, null=True) # Field name made lowercase. - text3 = models.CharField(db_column='Text3', max_length=50, blank=True, null=True) # Field name made lowercase. - text30 = models.CharField(db_column='Text30', max_length=100, blank=True, null=True) # Field name made lowercase. - text31 = models.TextField(db_column='Text31', blank=True, null=True) # Field name made lowercase. - text32 = models.TextField(db_column='Text32', blank=True, null=True) # Field name made lowercase. - text33 = models.TextField(db_column='Text33', blank=True, null=True) # Field name made lowercase. - text34 = models.TextField(db_column='Text34', blank=True, null=True) # Field name made lowercase. - text35 = models.TextField(db_column='Text35', blank=True, null=True) # Field name made lowercase. - text36 = models.TextField(db_column='Text36', blank=True, null=True) # Field name made lowercase. - text37 = models.TextField(db_column='Text37', blank=True, null=True) # Field name made lowercase. - text38 = models.TextField(db_column='Text38', blank=True, null=True) # Field name made lowercase. - text39 = models.TextField(db_column='Text39', blank=True, null=True) # Field name made lowercase. - text4 = models.CharField(db_column='Text4', max_length=50, blank=True, null=True) # Field name made lowercase. - text40 = models.TextField(db_column='Text40', blank=True, null=True) # Field name made lowercase. - text5 = models.CharField(db_column='Text5', max_length=50, blank=True, null=True) # Field name made lowercase. - text6 = models.CharField(db_column='Text6', max_length=50, blank=True, null=True) # Field name made lowercase. - text7 = models.CharField(db_column='Text7', max_length=50, blank=True, null=True) # Field name made lowercase. - text8 = models.CharField(db_column='Text8', max_length=50, blank=True, null=True) # Field name made lowercase. - text9 = models.CharField(db_column='Text9', max_length=50, blank=True, null=True) # Field name made lowercase. - yesno1 = models.BooleanField(db_column='YesNo1', blank=True, null=True) # Field name made lowercase. - yesno10 = models.BooleanField(db_column='YesNo10', blank=True, null=True) # Field name made lowercase. - yesno11 = models.BooleanField(db_column='YesNo11', blank=True, null=True) # Field name made lowercase. - yesno12 = models.BooleanField(db_column='YesNo12', blank=True, null=True) # Field name made lowercase. - yesno13 = models.BooleanField(db_column='YesNo13', blank=True, null=True) # Field name made lowercase. - yesno14 = models.BooleanField(db_column='YesNo14', blank=True, null=True) # Field name made lowercase. - yesno15 = models.BooleanField(db_column='YesNo15', blank=True, null=True) # Field name made lowercase. - yesno16 = models.BooleanField(db_column='YesNo16', blank=True, null=True) # Field name made lowercase. - yesno17 = models.BooleanField(db_column='YesNo17', blank=True, null=True) # Field name made lowercase. - yesno18 = models.BooleanField(db_column='YesNo18', blank=True, null=True) # Field name made lowercase. - yesno19 = models.BooleanField(db_column='YesNo19', blank=True, null=True) # Field name made lowercase. - yesno2 = models.BooleanField(db_column='YesNo2', blank=True, null=True) # Field name made lowercase. - yesno20 = models.BooleanField(db_column='YesNo20', blank=True, null=True) # Field name made lowercase. - yesno3 = models.BooleanField(db_column='YesNo3', blank=True, null=True) # Field name made lowercase. - yesno4 = models.BooleanField(db_column='YesNo4', blank=True, null=True) # Field name made lowercase. - yesno5 = models.BooleanField(db_column='YesNo5', blank=True, null=True) # Field name made lowercase. - yesno6 = models.BooleanField(db_column='YesNo6', blank=True, null=True) # Field name made lowercase. - yesno7 = models.BooleanField(db_column='YesNo7', blank=True, null=True) # Field name made lowercase. - yesno8 = models.BooleanField(db_column='YesNo8', blank=True, null=True) # Field name made lowercase. - yesno9 = models.BooleanField(db_column='YesNo9', blank=True, null=True) # Field name made lowercase. - agent2id = models.ForeignKey(Agent, models.DO_NOTHING, db_column='Agent2ID', blank=True, null=True) # Field name made lowercase. - agent15id = models.ForeignKey(Agent, models.DO_NOTHING, db_column='Agent15ID', blank=True, null=True) # Field name made lowercase. - agent19id = models.ForeignKey(Agent, models.DO_NOTHING, db_column='Agent19ID', blank=True, null=True) # Field name made lowercase. - agent4id = models.ForeignKey(Agent, models.DO_NOTHING, db_column='Agent4ID', blank=True, null=True) # Field name made lowercase. - agent3id = models.ForeignKey(Agent, models.DO_NOTHING, db_column='Agent3ID', blank=True, null=True) # Field name made lowercase. - agent8d = models.ForeignKey(Agent, models.DO_NOTHING, db_column='Agent8D', blank=True, null=True) # Field name made lowercase. - agent12id = models.ForeignKey(Agent, models.DO_NOTHING, db_column='Agent12ID', blank=True, null=True) # Field name made lowercase. - agent13id = models.ForeignKey(Agent, models.DO_NOTHING, db_column='Agent13ID', blank=True, null=True) # Field name made lowercase. - agent18id = models.ForeignKey(Agent, models.DO_NOTHING, db_column='Agent18ID', blank=True, null=True) # Field name made lowercase. - agent17id = models.ForeignKey(Agent, models.DO_NOTHING, db_column='Agent17ID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - agent10id = models.ForeignKey(Agent, models.DO_NOTHING, db_column='Agent10ID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - collectionobjectid = models.ForeignKey(Collectionobject, models.DO_NOTHING, db_column='CollectionObjectID') # Field name made lowercase. - agent1id = models.ForeignKey(Agent, models.DO_NOTHING, db_column='Agent1ID', blank=True, null=True) # Field name made lowercase. - agent9id = models.ForeignKey(Agent, models.DO_NOTHING, db_column='Agent9ID', blank=True, null=True) # Field name made lowercase. - agent16id = models.ForeignKey(Agent, models.DO_NOTHING, db_column='Agent16ID', blank=True, null=True) # Field name made lowercase. - agent14id = models.ForeignKey(Agent, models.DO_NOTHING, db_column='Agent14ID', blank=True, null=True) # Field name made lowercase. - agent5id = models.ForeignKey(Agent, models.DO_NOTHING, db_column='Agent5ID', blank=True, null=True) # Field name made lowercase. - agent7id = models.ForeignKey(Agent, models.DO_NOTHING, db_column='Agent7ID', blank=True, null=True) # Field name made lowercase. - agent20id = models.ForeignKey(Agent, models.DO_NOTHING, db_column='Agent20ID', blank=True, null=True) # Field name made lowercase. - agent6id = models.ForeignKey(Agent, models.DO_NOTHING, db_column='Agent6ID', blank=True, null=True) # Field name made lowercase. - agent11id = models.ForeignKey(Agent, models.DO_NOTHING, db_column='Agent11ID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'collectionobjectproperty' - - -class Collectionrelationship(models.Model): - collectionrelationshipid = models.AutoField(db_column='CollectionRelationshipID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - text1 = models.CharField(db_column='Text1', max_length=32, blank=True, null=True) # Field name made lowercase. - text2 = models.CharField(db_column='Text2', max_length=32, blank=True, null=True) # Field name made lowercase. - collectionreltypeid = models.ForeignKey('Collectionreltype', models.DO_NOTHING, db_column='CollectionRelTypeID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - rightsidecollectionid = models.ForeignKey(Collectionobject, models.DO_NOTHING, db_column='RightSideCollectionID') # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - leftsidecollectionid = models.ForeignKey(Collectionobject, models.DO_NOTHING, db_column='LeftSideCollectionID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'collectionrelationship' - - -class Collectionreltype(models.Model): - collectionreltypeid = models.AutoField(db_column='CollectionRelTypeID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - name = models.CharField(db_column='Name', max_length=32, blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - leftsidecollectionid = models.ForeignKey(Collection, models.DO_NOTHING, db_column='LeftSideCollectionID', blank=True, null=True) # Field name made lowercase. - rightsidecollectionid = models.ForeignKey(Collection, models.DO_NOTHING, db_column='RightSideCollectionID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'collectionreltype' - - -class Collector(models.Model): - collectorid = models.AutoField(db_column='CollectorID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - isprimary = models.BooleanField(db_column='IsPrimary') # Field name made lowercase. - ordernumber = models.IntegerField(db_column='OrderNumber') # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - divisionid = models.ForeignKey('Division', models.DO_NOTHING, db_column='DivisionID', blank=True, null=True) # Field name made lowercase. - collectingeventid = models.ForeignKey(Collectingevent, models.DO_NOTHING, db_column='CollectingEventID') # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - agentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='AgentID') # Field name made lowercase. - text1 = models.TextField(db_column='Text1', blank=True, null=True) # Field name made lowercase. - text2 = models.TextField(db_column='Text2', blank=True, null=True) # Field name made lowercase. - yesno1 = models.BooleanField(db_column='YesNo1', blank=True, null=True) # Field name made lowercase. - yesno2 = models.BooleanField(db_column='YesNo2', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'collector' - unique_together = (('agentid', 'collectingeventid'),) - - -class Commonnametx(models.Model): - commonnametxid = models.AutoField(db_column='CommonNameTxID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - author = models.CharField(db_column='Author', max_length=128, blank=True, null=True) # Field name made lowercase. - country = models.CharField(db_column='Country', max_length=2, blank=True, null=True) # Field name made lowercase. - language = models.CharField(db_column='Language', max_length=2, blank=True, null=True) # Field name made lowercase. - name = models.CharField(db_column='Name', max_length=255, blank=True, null=True) # Field name made lowercase. - variant = models.CharField(db_column='Variant', max_length=2, blank=True, null=True) # Field name made lowercase. - taxonid = models.ForeignKey('Taxon', models.DO_NOTHING, db_column='TaxonID') # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'commonnametx' - - -class Commonnametxcitation(models.Model): - commonnametxcitationid = models.AutoField(db_column='CommonNameTxCitationID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - number1 = models.DecimalField(db_column='Number1', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number2 = models.DecimalField(db_column='Number2', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - text1 = models.TextField(db_column='Text1', blank=True, null=True) # Field name made lowercase. - text2 = models.TextField(db_column='Text2', blank=True, null=True) # Field name made lowercase. - yesno1 = models.BooleanField(db_column='YesNo1', blank=True, null=True) # Field name made lowercase. - yesno2 = models.BooleanField(db_column='YesNo2', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - referenceworkid = models.ForeignKey('Referencework', models.DO_NOTHING, db_column='ReferenceWorkID') # Field name made lowercase. - commonnametxid = models.ForeignKey(Commonnametx, models.DO_NOTHING, db_column='CommonNameTxID') # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - figurenumber = models.CharField(db_column='FigureNumber', max_length=50, blank=True, null=True) # Field name made lowercase. - isfigured = models.BooleanField(db_column='IsFigured', blank=True, null=True) # Field name made lowercase. - pagenumber = models.CharField(db_column='PageNumber', max_length=50, blank=True, null=True) # Field name made lowercase. - platenumber = models.CharField(db_column='PlateNumber', max_length=50, blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'commonnametxcitation' - - -class Conservdescription(models.Model): - conservdescriptionid = models.AutoField(db_column='ConservDescriptionID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - backgroundinfo = models.TextField(db_column='BackgroundInfo', blank=True, null=True) # Field name made lowercase. - composition = models.TextField(db_column='Composition', blank=True, null=True) # Field name made lowercase. - description = models.TextField(db_column='Description', blank=True, null=True) # Field name made lowercase. - displayrecommendations = models.TextField(db_column='DisplayRecommendations', blank=True, null=True) # Field name made lowercase. - height = models.DecimalField(db_column='Height', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - lightrecommendations = models.TextField(db_column='LightRecommendations', blank=True, null=True) # Field name made lowercase. - objlength = models.DecimalField(db_column='ObjLength', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - otherrecommendations = models.TextField(db_column='OtherRecommendations', blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - shortdesc = models.CharField(db_column='ShortDesc', max_length=128, blank=True, null=True) # Field name made lowercase. - source = models.TextField(db_column='Source', blank=True, null=True) # Field name made lowercase. - units = models.CharField(db_column='Units', max_length=16, blank=True, null=True) # Field name made lowercase. - width = models.DecimalField(db_column='Width', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - divisionid = models.ForeignKey('Division', models.DO_NOTHING, db_column='DivisionID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - collectionobjectid = models.ForeignKey(Collectionobject, models.DO_NOTHING, db_column='CollectionObjectID', blank=True, null=True) # Field name made lowercase. - catalogeddate = models.DateField(db_column='CatalogedDate', blank=True, null=True) # Field name made lowercase. - determineddateprecision = models.IntegerField(db_column='determinedDatePrecision', blank=True, null=True) # Field name made lowercase. - preparationid = models.ForeignKey('Preparation', models.DO_NOTHING, db_column='PreparationID', blank=True, null=True) # Field name made lowercase. - date1 = models.DateField(db_column='Date1', blank=True, null=True) # Field name made lowercase. - date1precision = models.IntegerField(db_column='Date1Precision', blank=True, null=True) # Field name made lowercase. - date2 = models.DateField(db_column='Date2', blank=True, null=True) # Field name made lowercase. - date2precision = models.IntegerField(db_column='Date2Precision', blank=True, null=True) # Field name made lowercase. - date3 = models.DateField(db_column='Date3', blank=True, null=True) # Field name made lowercase. - date3precision = models.IntegerField(db_column='Date3Precision', blank=True, null=True) # Field name made lowercase. - date4 = models.DateField(db_column='Date4', blank=True, null=True) # Field name made lowercase. - date4precision = models.IntegerField(db_column='Date4Precision', blank=True, null=True) # Field name made lowercase. - date5 = models.DateField(db_column='Date5', blank=True, null=True) # Field name made lowercase. - date5precision = models.IntegerField(db_column='Date5Precision', blank=True, null=True) # Field name made lowercase. - integer1 = models.IntegerField(db_column='Integer1', blank=True, null=True) # Field name made lowercase. - integer2 = models.IntegerField(db_column='Integer2', blank=True, null=True) # Field name made lowercase. - integer3 = models.IntegerField(db_column='Integer3', blank=True, null=True) # Field name made lowercase. - integer4 = models.IntegerField(db_column='Integer4', blank=True, null=True) # Field name made lowercase. - integer5 = models.IntegerField(db_column='Integer5', blank=True, null=True) # Field name made lowercase. - number1 = models.DecimalField(db_column='Number1', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number2 = models.DecimalField(db_column='Number2', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number3 = models.DecimalField(db_column='Number3', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number4 = models.DecimalField(db_column='Number4', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number5 = models.DecimalField(db_column='Number5', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - text1 = models.TextField(db_column='Text1', blank=True, null=True) # Field name made lowercase. - text2 = models.TextField(db_column='Text2', blank=True, null=True) # Field name made lowercase. - text3 = models.TextField(db_column='Text3', blank=True, null=True) # Field name made lowercase. - text4 = models.TextField(db_column='Text4', blank=True, null=True) # Field name made lowercase. - text5 = models.TextField(db_column='Text5', blank=True, null=True) # Field name made lowercase. - yesno1 = models.BooleanField(db_column='YesNo1', blank=True, null=True) # Field name made lowercase. - yesno2 = models.BooleanField(db_column='YesNo2', blank=True, null=True) # Field name made lowercase. - yesno3 = models.BooleanField(db_column='YesNo3', blank=True, null=True) # Field name made lowercase. - yesno4 = models.BooleanField(db_column='YesNo4', blank=True, null=True) # Field name made lowercase. - yesno5 = models.BooleanField(db_column='YesNo5', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'conservdescription' - - -class Conservdescriptionattachment(models.Model): - conservdescriptionattachmentid = models.AutoField(db_column='ConservDescriptionAttachmentID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - ordinal = models.IntegerField(db_column='Ordinal') # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - conservdescriptionid = models.ForeignKey(Conservdescription, models.DO_NOTHING, db_column='ConservDescriptionID') # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - attachmentid = models.ForeignKey(Attachment, models.DO_NOTHING, db_column='AttachmentID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'conservdescriptionattachment' - - -class Conservevent(models.Model): - conserveventid = models.AutoField(db_column='ConservEventID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - advtestingexam = models.TextField(db_column='AdvTestingExam', blank=True, null=True) # Field name made lowercase. - advtestingexamresults = models.TextField(db_column='AdvTestingExamResults', blank=True, null=True) # Field name made lowercase. - completedcomments = models.TextField(db_column='CompletedComments', blank=True, null=True) # Field name made lowercase. - completeddate = models.DateField(db_column='CompletedDate', blank=True, null=True) # Field name made lowercase. - conditionreport = models.TextField(db_column='ConditionReport', blank=True, null=True) # Field name made lowercase. - curatorapprovaldate = models.DateField(db_column='CuratorApprovalDate', blank=True, null=True) # Field name made lowercase. - examdate = models.DateField(db_column='ExamDate', blank=True, null=True) # Field name made lowercase. - number1 = models.IntegerField(db_column='Number1', blank=True, null=True) # Field name made lowercase. - number2 = models.IntegerField(db_column='Number2', blank=True, null=True) # Field name made lowercase. - photodocs = models.TextField(db_column='PhotoDocs', blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - text1 = models.CharField(db_column='Text1', max_length=64, blank=True, null=True) # Field name made lowercase. - text2 = models.CharField(db_column='Text2', max_length=64, blank=True, null=True) # Field name made lowercase. - treatmentcompdate = models.DateField(db_column='TreatmentCompDate', blank=True, null=True) # Field name made lowercase. - treatmentreport = models.TextField(db_column='TreatmentReport', blank=True, null=True) # Field name made lowercase. - yesno1 = models.BooleanField(db_column='YesNo1', blank=True, null=True) # Field name made lowercase. - yesno2 = models.BooleanField(db_column='YesNo2', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - treatedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='TreatedByAgentID', blank=True, null=True) # Field name made lowercase. - conservdescriptionid = models.ForeignKey(Conservdescription, models.DO_NOTHING, db_column='ConservDescriptionID') # Field name made lowercase. - curatorid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CuratorID', blank=True, null=True) # Field name made lowercase. - examinedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ExaminedByAgentID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - completeddateprecision = models.IntegerField(db_column='CompletedDatePrecision', blank=True, null=True) # Field name made lowercase. - curatorapprovaldateprecision = models.IntegerField(db_column='CuratorApprovalDatePrecision', blank=True, null=True) # Field name made lowercase. - examdateprecision = models.IntegerField(db_column='ExamDatePrecision', blank=True, null=True) # Field name made lowercase. - treatmentcompdateprecision = models.IntegerField(db_column='TreatmentCompDatePrecision', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'conservevent' - - -class Conserveventattachment(models.Model): - conserveventattachmentid = models.AutoField(db_column='ConservEventAttachmentID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - ordinal = models.IntegerField(db_column='Ordinal') # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - attachmentid = models.ForeignKey(Attachment, models.DO_NOTHING, db_column='AttachmentID') # Field name made lowercase. - conserveventid = models.ForeignKey(Conservevent, models.DO_NOTHING, db_column='ConservEventID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'conserveventattachment' - - -class Container(models.Model): - containerid = models.AutoField(db_column='ContainerID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - collectionmemberid = models.IntegerField(db_column='CollectionMemberID') # Field name made lowercase. - description = models.TextField(db_column='Description', blank=True, null=True) # Field name made lowercase. - name = models.CharField(db_column='Name', max_length=1024, blank=True, null=True) # Field name made lowercase. - number = models.IntegerField(db_column='Number', blank=True, null=True) # Field name made lowercase. - type = models.SmallIntegerField(db_column='Type', blank=True, null=True) # Field name made lowercase. - storageid = models.ForeignKey('Storage', models.DO_NOTHING, db_column='StorageID', blank=True, null=True) # Field name made lowercase. - parentid = models.ForeignKey('self', models.DO_NOTHING, db_column='ParentID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'container' - - -class Continentcodes(models.Model): - code = models.CharField(max_length=2, blank=True, null=True) - name = models.CharField(max_length=20, blank=True, null=True) - geonameid = models.IntegerField(db_column='geonameId', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'continentcodes' - - -class Countryinfo(models.Model): - iso_alpha2 = models.CharField(max_length=2, blank=True, null=True) - iso_alpha3 = models.CharField(max_length=3, blank=True, null=True) - iso_numeric = models.IntegerField(blank=True, null=True) - fips_code = models.CharField(max_length=3, blank=True, null=True) - name = models.CharField(primary_key=True, max_length=255) - capital = models.CharField(max_length=255, blank=True, null=True) - areainsqkm = models.CharField(max_length=16, blank=True, null=True) - population = models.CharField(max_length=16, blank=True, null=True) - continent = models.CharField(max_length=2, blank=True, null=True) - tld = models.CharField(max_length=32, blank=True, null=True) - currencycode = models.CharField(max_length=3, blank=True, null=True) - currencyname = models.CharField(max_length=32, blank=True, null=True) - phone = models.CharField(max_length=32, blank=True, null=True) - postalformat = models.CharField(max_length=128, blank=True, null=True) - postalregex = models.TextField(blank=True, null=True) - languages = models.CharField(max_length=255, blank=True, null=True) - geonameid = models.IntegerField(db_column='geonameId', blank=True, null=True) # Field name made lowercase. - neighbors = models.CharField(max_length=255, blank=True, null=True) - - class Meta: - managed = False - db_table = 'countryinfo' - - -class Datatype(models.Model): - datatypeid = models.AutoField(db_column='DataTypeID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - name = models.CharField(db_column='Name', max_length=50, blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'datatype' - - -class Deaccession(models.Model): - deaccessionid = models.AutoField(db_column='DeaccessionID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - date1 = models.DateField(db_column='Date1', blank=True, null=True) # Field name made lowercase. - date2 = models.DateField(db_column='Date2', blank=True, null=True) # Field name made lowercase. - deaccessiondate = models.DateField(db_column='DeaccessionDate', blank=True, null=True) # Field name made lowercase. - deaccessionnumber = models.CharField(db_column='DeaccessionNumber', max_length=50) # Field name made lowercase. - integer1 = models.IntegerField(db_column='Integer1', blank=True, null=True) # Field name made lowercase. - integer2 = models.IntegerField(db_column='Integer2', blank=True, null=True) # Field name made lowercase. - integer3 = models.IntegerField(db_column='Integer3', blank=True, null=True) # Field name made lowercase. - integer4 = models.IntegerField(db_column='Integer4', blank=True, null=True) # Field name made lowercase. - integer5 = models.IntegerField(db_column='Integer5', blank=True, null=True) # Field name made lowercase. - number1 = models.DecimalField(db_column='Number1', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number2 = models.DecimalField(db_column='Number2', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number3 = models.DecimalField(db_column='Number3', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number4 = models.DecimalField(db_column='Number4', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number5 = models.DecimalField(db_column='Number5', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - status = models.CharField(db_column='Status', max_length=64, blank=True, null=True) # Field name made lowercase. - text1 = models.TextField(db_column='Text1', blank=True, null=True) # Field name made lowercase. - text2 = models.TextField(db_column='Text2', blank=True, null=True) # Field name made lowercase. - text3 = models.TextField(db_column='Text3', blank=True, null=True) # Field name made lowercase. - text4 = models.TextField(db_column='Text4', blank=True, null=True) # Field name made lowercase. - text5 = models.TextField(db_column='Text5', blank=True, null=True) # Field name made lowercase. - type = models.CharField(db_column='Type', max_length=64, blank=True, null=True) # Field name made lowercase. - yesno1 = models.BooleanField(db_column='YesNo1', blank=True, null=True) # Field name made lowercase. - yesno2 = models.BooleanField(db_column='YesNo2', blank=True, null=True) # Field name made lowercase. - yesno3 = models.BooleanField(db_column='YesNo3', blank=True, null=True) # Field name made lowercase. - yesno4 = models.BooleanField(db_column='YesNo4', blank=True, null=True) # Field name made lowercase. - yesno5 = models.BooleanField(db_column='YesNo5', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - agent1id = models.ForeignKey(Agent, models.DO_NOTHING, db_column='Agent1ID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - agent2id = models.ForeignKey(Agent, models.DO_NOTHING, db_column='Agent2ID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'deaccession' - - -class Deaccessionagent(models.Model): - deaccessionagentid = models.AutoField(db_column='DeaccessionAgentID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - role = models.CharField(db_column='Role', max_length=50) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - agentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='AgentID') # Field name made lowercase. - deaccessionid = models.ForeignKey(Deaccession, models.DO_NOTHING, db_column='DeaccessionID') # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'deaccessionagent' - unique_together = (('role', 'agentid', 'deaccessionid'),) - - -class Deaccessionattachment(models.Model): - deaccessionattachmentid = models.AutoField(db_column='DeaccessionAttachmentID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - ordinal = models.IntegerField(db_column='Ordinal') # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - deaccessionid = models.ForeignKey(Deaccession, models.DO_NOTHING, db_column='DeaccessionID') # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - attachmentid = models.ForeignKey(Attachment, models.DO_NOTHING, db_column='AttachmentID') # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'deaccessionattachment' - - -class Determination(models.Model): - determinationid = models.AutoField(db_column='DeterminationID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - collectionmemberid = models.IntegerField(db_column='CollectionMemberID') # Field name made lowercase. - addendum = models.CharField(db_column='Addendum', max_length=16, blank=True, null=True) # Field name made lowercase. - alternatename = models.CharField(db_column='AlternateName', max_length=128, blank=True, null=True) # Field name made lowercase. - confidence = models.CharField(db_column='Confidence', max_length=50, blank=True, null=True) # Field name made lowercase. - determineddate = models.DateField(db_column='DeterminedDate', blank=True, null=True) # Field name made lowercase. - determineddateprecision = models.IntegerField(db_column='DeterminedDatePrecision', blank=True, null=True) # Field name made lowercase. - featureorbasis = models.CharField(db_column='FeatureOrBasis', max_length=250, blank=True, null=True) # Field name made lowercase. - iscurrent = models.BooleanField(db_column='IsCurrent') # Field name made lowercase. - method = models.CharField(db_column='Method', max_length=50, blank=True, null=True) # Field name made lowercase. - nameusage = models.CharField(db_column='NameUsage', max_length=64, blank=True, null=True) # Field name made lowercase. - number1 = models.DecimalField(db_column='Number1', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number2 = models.DecimalField(db_column='Number2', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - qualifier = models.CharField(db_column='Qualifier', max_length=16, blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - subspqualifier = models.CharField(db_column='SubSpQualifier', max_length=16, blank=True, null=True) # Field name made lowercase. - text1 = models.TextField(db_column='Text1', blank=True, null=True) # Field name made lowercase. - text2 = models.TextField(db_column='Text2', blank=True, null=True) # Field name made lowercase. - typestatusname = models.CharField(db_column='TypeStatusName', max_length=50, blank=True, null=True) # Field name made lowercase. - varqualifier = models.CharField(db_column='VarQualifier', max_length=16, blank=True, null=True) # Field name made lowercase. - yesno1 = models.BooleanField(db_column='YesNo1', blank=True, null=True) # Field name made lowercase. - yesno2 = models.BooleanField(db_column='YesNo2', blank=True, null=True) # Field name made lowercase. - guid = models.CharField(db_column='GUID', max_length=128, blank=True, null=True) # Field name made lowercase. - taxonid = models.ForeignKey('Taxon', models.DO_NOTHING, db_column='TaxonID', blank=True, null=True) # Field name made lowercase. - collectionobjectid = models.ForeignKey(Collectionobject, models.DO_NOTHING, db_column='CollectionObjectID') # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - determinerid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='DeterminerID', blank=True, null=True) # Field name made lowercase. - preferredtaxonid = models.ForeignKey('Taxon', models.DO_NOTHING, db_column='PreferredTaxonID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - integer1 = models.IntegerField(db_column='Integer1', blank=True, null=True) # Field name made lowercase. - integer2 = models.IntegerField(db_column='Integer2', blank=True, null=True) # Field name made lowercase. - integer3 = models.IntegerField(db_column='Integer3', blank=True, null=True) # Field name made lowercase. - integer4 = models.IntegerField(db_column='Integer4', blank=True, null=True) # Field name made lowercase. - integer5 = models.IntegerField(db_column='Integer5', blank=True, null=True) # Field name made lowercase. - number3 = models.DecimalField(db_column='Number3', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number4 = models.DecimalField(db_column='Number4', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number5 = models.DecimalField(db_column='Number5', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - text3 = models.TextField(db_column='Text3', blank=True, null=True) # Field name made lowercase. - text4 = models.CharField(db_column='Text4', max_length=128, blank=True, null=True) # Field name made lowercase. - text5 = models.CharField(db_column='Text5', max_length=128, blank=True, null=True) # Field name made lowercase. - text6 = models.CharField(db_column='Text6', max_length=128, blank=True, null=True) # Field name made lowercase. - text7 = models.CharField(db_column='Text7', max_length=128, blank=True, null=True) # Field name made lowercase. - text8 = models.CharField(db_column='Text8', max_length=128, blank=True, null=True) # Field name made lowercase. - yesno3 = models.BooleanField(db_column='YesNo3', blank=True, null=True) # Field name made lowercase. - yesno4 = models.BooleanField(db_column='YesNo4', blank=True, null=True) # Field name made lowercase. - yesno5 = models.BooleanField(db_column='YesNo5', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'determination' - - -class Determinationcitation(models.Model): - determinationcitationid = models.AutoField(db_column='DeterminationCitationID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - collectionmemberid = models.IntegerField(db_column='CollectionMemberID') # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - referenceworkid = models.ForeignKey('Referencework', models.DO_NOTHING, db_column='ReferenceWorkID') # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - determinationid = models.ForeignKey(Determination, models.DO_NOTHING, db_column='DeterminationID') # Field name made lowercase. - figurenumber = models.CharField(db_column='FigureNumber', max_length=50, blank=True, null=True) # Field name made lowercase. - isfigured = models.BooleanField(db_column='IsFigured', blank=True, null=True) # Field name made lowercase. - pagenumber = models.CharField(db_column='PageNumber', max_length=50, blank=True, null=True) # Field name made lowercase. - platenumber = models.CharField(db_column='PlateNumber', max_length=50, blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'determinationcitation' - unique_together = (('referenceworkid', 'determinationid'),) - - -class Determiner(models.Model): - determinerid = models.AutoField(db_column='DeterminerID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - isprimary = models.BooleanField(db_column='IsPrimary') # Field name made lowercase. - ordernumber = models.IntegerField(db_column='OrderNumber') # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - text1 = models.TextField(db_column='Text1', blank=True, null=True) # Field name made lowercase. - text2 = models.TextField(db_column='Text2', blank=True, null=True) # Field name made lowercase. - yesno1 = models.BooleanField(db_column='YesNo1', blank=True, null=True) # Field name made lowercase. - yesno2 = models.BooleanField(db_column='YesNo2', blank=True, null=True) # Field name made lowercase. - agentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='AgentID') # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - determinationid = models.ForeignKey(Determination, models.DO_NOTHING, db_column='DeterminationID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'determiner' - unique_together = (('agentid', 'determinationid'),) - - -class Discipline(models.Model): - usergroupscopeid = models.IntegerField(db_column='UserGroupScopeId', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - disciplineid = models.IntegerField(db_column='disciplineId', blank=True, null=True) # Field name made lowercase. - name = models.CharField(db_column='Name', max_length=64, blank=True, null=True) # Field name made lowercase. - regnumber = models.CharField(db_column='RegNumber', max_length=24, blank=True, null=True) # Field name made lowercase. - type = models.CharField(db_column='Type', max_length=64, blank=True, null=True) # Field name made lowercase. - taxontreedefid = models.ForeignKey('Taxontreedef', models.DO_NOTHING, db_column='TaxonTreeDefID', blank=True, null=True) # Field name made lowercase. - divisionid = models.ForeignKey('Division', models.DO_NOTHING, db_column='DivisionID') # Field name made lowercase. - geologictimeperiodtreedefid = models.ForeignKey('Geologictimeperiodtreedef', models.DO_NOTHING, db_column='GeologicTimePeriodTreeDefID') # Field name made lowercase. - lithostrattreedefid = models.ForeignKey('Lithostrattreedef', models.DO_NOTHING, db_column='LithoStratTreeDefID', blank=True, null=True) # Field name made lowercase. - geographytreedefid = models.ForeignKey('Geographytreedef', models.DO_NOTHING, db_column='GeographyTreeDefID') # Field name made lowercase. - datatypeid = models.ForeignKey(Datatype, models.DO_NOTHING, db_column='DataTypeID') # Field name made lowercase. - ispaleocontextembedded = models.BooleanField(db_column='IsPaleoContextEmbedded', blank=True, null=True) # Field name made lowercase. - paleocontextchildtable = models.CharField(db_column='PaleoContextChildTable', max_length=50, blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'discipline' - - -class Disposal(models.Model): - disposalid = models.AutoField(db_column='DisposalID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - disposaldate = models.DateField(db_column='DisposalDate', blank=True, null=True) # Field name made lowercase. - disposalnumber = models.CharField(db_column='DisposalNumber', max_length=50) # Field name made lowercase. - donotexport = models.BooleanField(db_column='doNotExport', blank=True, null=True) # Field name made lowercase. - number1 = models.DecimalField(db_column='Number1', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number2 = models.DecimalField(db_column='Number2', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - text1 = models.TextField(db_column='Text1', blank=True, null=True) # Field name made lowercase. - text2 = models.TextField(db_column='Text2', blank=True, null=True) # Field name made lowercase. - type = models.CharField(db_column='Type', max_length=64, blank=True, null=True) # Field name made lowercase. - yesno1 = models.BooleanField(db_column='YesNo1', blank=True, null=True) # Field name made lowercase. - yesno2 = models.BooleanField(db_column='YesNo2', blank=True, null=True) # Field name made lowercase. - deaccessionid = models.ForeignKey(Deaccession, models.DO_NOTHING, db_column='DeaccessionID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'disposal' - - -class Disposalagent(models.Model): - disposalagentid = models.AutoField(db_column='DisposalAgentID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - role = models.CharField(db_column='Role', max_length=50) # Field name made lowercase. - disposalid = models.ForeignKey(Disposal, models.DO_NOTHING, db_column='DisposalID') # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - agentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='AgentID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'disposalagent' - unique_together = (('role', 'agentid', 'disposalid'),) - - -class Disposalattachment(models.Model): - disposalattachmentid = models.AutoField(db_column='DisposalAttachmentID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - ordinal = models.IntegerField(db_column='Ordinal') # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - disposalid = models.ForeignKey(Disposal, models.DO_NOTHING, db_column='DisposalID') # Field name made lowercase. - attachmentid = models.ForeignKey(Attachment, models.DO_NOTHING, db_column='AttachmentID') # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'disposalattachment' - - -class Disposalpreparation(models.Model): - disposalpreparationid = models.AutoField(db_column='DisposalPreparationID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - quantity = models.IntegerField(db_column='Quantity', blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - disposalid = models.ForeignKey(Disposal, models.DO_NOTHING, db_column='DisposalID') # Field name made lowercase. - loanreturnpreparationid = models.ForeignKey('Loanreturnpreparation', models.DO_NOTHING, db_column='LoanReturnPreparationID', blank=True, null=True) # Field name made lowercase. - preparationid = models.ForeignKey('Preparation', models.DO_NOTHING, db_column='PreparationID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'disposalpreparation' - - -class Division(models.Model): - usergroupscopeid = models.IntegerField(db_column='UserGroupScopeId', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - abbrev = models.CharField(db_column='Abbrev', max_length=64, blank=True, null=True) # Field name made lowercase. - altname = models.CharField(db_column='AltName', max_length=128, blank=True, null=True) # Field name made lowercase. - description = models.TextField(db_column='Description', blank=True, null=True) # Field name made lowercase. - disciplinetype = models.CharField(db_column='DisciplineType', max_length=64, blank=True, null=True) # Field name made lowercase. - divisionid = models.IntegerField(db_column='divisionId', blank=True, null=True) # Field name made lowercase. - iconuri = models.CharField(db_column='IconURI', max_length=255, blank=True, null=True) # Field name made lowercase. - name = models.CharField(db_column='Name', max_length=255, blank=True, null=True) # Field name made lowercase. - regnumber = models.CharField(db_column='RegNumber', max_length=24, blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - uri = models.CharField(db_column='Uri', max_length=255, blank=True, null=True) # Field name made lowercase. - addressid = models.ForeignKey(Address, models.DO_NOTHING, db_column='AddressID', blank=True, null=True) # Field name made lowercase. - institutionid = models.ForeignKey('Institution', models.DO_NOTHING, db_column='InstitutionID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'division' - - -class DjangoContentType(models.Model): - app_label = models.CharField(max_length=100) - model = models.CharField(max_length=100) - - class Meta: - managed = False - db_table = 'django_content_type' - unique_together = (('app_label', 'model'),) - - -class DjangoMigrations(models.Model): - app = models.CharField(max_length=255) - name = models.CharField(max_length=255) - applied = models.DateTimeField() - - class Meta: - managed = False - db_table = 'django_migrations' - - -class DjangoSession(models.Model): - session_key = models.CharField(primary_key=True, max_length=40) - session_data = models.TextField() - expire_date = models.DateTimeField() - - class Meta: - managed = False - db_table = 'django_session' - - -class Dnaprimer(models.Model): - dnaprimerid = models.AutoField(db_column='DNAPrimerID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - integer1 = models.IntegerField(db_column='Integer1', blank=True, null=True) # Field name made lowercase. - integer2 = models.IntegerField(db_column='Integer2', blank=True, null=True) # Field name made lowercase. - number1 = models.DecimalField(db_column='Number1', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number2 = models.DecimalField(db_column='Number2', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - primerdesignator = models.CharField(db_column='PrimerDesignator', max_length=64, blank=True, null=True) # Field name made lowercase. - primernameforward = models.CharField(db_column='PrimerNameForward', max_length=64, blank=True, null=True) # Field name made lowercase. - primernamereverse = models.CharField(db_column='PrimerNameReverse', max_length=64, blank=True, null=True) # Field name made lowercase. - primerreferencecitationforward = models.CharField(db_column='PrimerReferenceCitationForward', max_length=300, blank=True, null=True) # Field name made lowercase. - primerreferencecitationreverse = models.CharField(db_column='PrimerReferenceCitationReverse', max_length=300, blank=True, null=True) # Field name made lowercase. - primerreferencelinkforward = models.CharField(db_column='PrimerReferenceLinkForward', max_length=300, blank=True, null=True) # Field name made lowercase. - primerreferencelinkreverse = models.CharField(db_column='PrimerReferenceLinkReverse', max_length=300, blank=True, null=True) # Field name made lowercase. - primersequenceforward = models.CharField(db_column='PrimerSequenceForward', max_length=128, blank=True, null=True) # Field name made lowercase. - primersequencereverse = models.CharField(db_column='PrimerSequenceReverse', max_length=128, blank=True, null=True) # Field name made lowercase. - purificationmethod = models.CharField(db_column='purificationMethod', max_length=255, blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - reservedinteger3 = models.IntegerField(db_column='ReservedInteger3', blank=True, null=True) # Field name made lowercase. - reservedinteger4 = models.IntegerField(db_column='ReservedInteger4', blank=True, null=True) # Field name made lowercase. - reservednumber3 = models.DecimalField(db_column='ReservedNumber3', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - reservednumber4 = models.DecimalField(db_column='ReservedNumber4', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - reservedtext3 = models.TextField(db_column='ReservedText3', blank=True, null=True) # Field name made lowercase. - reservedtext4 = models.TextField(db_column='ReservedText4', blank=True, null=True) # Field name made lowercase. - text1 = models.TextField(db_column='Text1', blank=True, null=True) # Field name made lowercase. - text2 = models.TextField(db_column='Text2', blank=True, null=True) # Field name made lowercase. - yesno1 = models.BooleanField(db_column='YesNo1', blank=True, null=True) # Field name made lowercase. - yesno2 = models.BooleanField(db_column='YesNo2', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'dnaprimer' - - -class Dnasequence(models.Model): - dnasequenceid = models.AutoField(db_column='DnaSequenceID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - collectionmemberid = models.IntegerField(db_column='CollectionMemberID') # Field name made lowercase. - ambiguousresidues = models.IntegerField(db_column='AmbiguousResidues', blank=True, null=True) # Field name made lowercase. - boldbarcodeid = models.CharField(db_column='BOLDBarcodeID', max_length=32, blank=True, null=True) # Field name made lowercase. - boldlastupdatedate = models.DateField(db_column='BOLDLastUpdateDate', blank=True, null=True) # Field name made lowercase. - boldsampleid = models.CharField(db_column='BOLDSampleID', max_length=32, blank=True, null=True) # Field name made lowercase. - boldtranslationmatrix = models.CharField(db_column='BOLDTranslationMatrix', max_length=64, blank=True, null=True) # Field name made lowercase. - compa = models.IntegerField(db_column='CompA', blank=True, null=True) # Field name made lowercase. - compc = models.IntegerField(db_column='CompC', blank=True, null=True) # Field name made lowercase. - compg = models.IntegerField(db_column='CompG', blank=True, null=True) # Field name made lowercase. - compt = models.IntegerField(db_column='compT', blank=True, null=True) # Field name made lowercase. - genbankaccessionnumber = models.CharField(db_column='GenBankAccessionNumber', max_length=32, blank=True, null=True) # Field name made lowercase. - genesequence = models.TextField(db_column='GeneSequence', blank=True, null=True) # Field name made lowercase. - moleculetype = models.CharField(db_column='MoleculeType', max_length=32, blank=True, null=True) # Field name made lowercase. - number1 = models.DecimalField(db_column='Number1', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number2 = models.DecimalField(db_column='Number2', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number3 = models.DecimalField(db_column='Number3', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - targetmarker = models.CharField(db_column='TargetMarker', max_length=32, blank=True, null=True) # Field name made lowercase. - text1 = models.CharField(db_column='Text1', max_length=32, blank=True, null=True) # Field name made lowercase. - text2 = models.CharField(db_column='Text2', max_length=32, blank=True, null=True) # Field name made lowercase. - text3 = models.CharField(db_column='Text3', max_length=64, blank=True, null=True) # Field name made lowercase. - totalresidues = models.IntegerField(db_column='TotalResidues', blank=True, null=True) # Field name made lowercase. - yesno1 = models.BooleanField(db_column='YesNo1', blank=True, null=True) # Field name made lowercase. - yesno2 = models.BooleanField(db_column='YesNo2', blank=True, null=True) # Field name made lowercase. - yesno3 = models.BooleanField(db_column='YesNo3', blank=True, null=True) # Field name made lowercase. - collectionobjectid = models.ForeignKey(Collectionobject, models.DO_NOTHING, db_column='CollectionObjectID', blank=True, null=True) # Field name made lowercase. - agentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='AgentID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - materialsampleid = models.ForeignKey('Materialsample', models.DO_NOTHING, db_column='MaterialSampleID', blank=True, null=True) # Field name made lowercase. - extractiondate = models.DateField(db_column='ExtractionDate', blank=True, null=True) # Field name made lowercase. - extractiondateprecision = models.IntegerField(db_column='ExtractionDatePrecision', blank=True, null=True) # Field name made lowercase. - sequencedate = models.DateField(db_column='SequenceDate', blank=True, null=True) # Field name made lowercase. - sequencedateprecision = models.IntegerField(db_column='SequenceDatePrecision', blank=True, null=True) # Field name made lowercase. - extractorid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ExtractorID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'dnasequence' - - -class Dnasequenceattachment(models.Model): - dnasequenceattachmentid = models.AutoField(db_column='DnaSequenceAttachmentId', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - ordinal = models.IntegerField(db_column='Ordinal') # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - attachmentid = models.ForeignKey(Attachment, models.DO_NOTHING, db_column='AttachmentID') # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - dnasequenceid = models.ForeignKey(Dnasequence, models.DO_NOTHING, db_column='DnaSequenceID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'dnasequenceattachment' - - -class Dnasequencerunattachment(models.Model): - dnasequencingrunattachmentid = models.AutoField(db_column='DnaSequencingRunAttachmentId', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - ordinal = models.IntegerField(db_column='Ordinal') # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - dnasequencingrunid = models.ForeignKey('Dnasequencingrun', models.DO_NOTHING, db_column='DnaSequencingRunID') # Field name made lowercase. - attachmentid = models.ForeignKey(Attachment, models.DO_NOTHING, db_column='AttachmentID') # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'dnasequencerunattachment' - - -class Dnasequencingrun(models.Model): - dnasequencingrunid = models.AutoField(db_column='DNASequencingRunID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - collectionmemberid = models.IntegerField(db_column='CollectionMemberID') # Field name made lowercase. - genesequence = models.TextField(db_column='GeneSequence', blank=True, null=True) # Field name made lowercase. - number1 = models.DecimalField(db_column='Number1', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number2 = models.DecimalField(db_column='Number2', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number3 = models.DecimalField(db_column='Number3', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - ordinal = models.IntegerField(db_column='Ordinal', blank=True, null=True) # Field name made lowercase. - pcrcocktailprimer = models.BooleanField(db_column='PCRCocktailPrimer', blank=True, null=True) # Field name made lowercase. - pcrforwardprimercode = models.CharField(db_column='PCRForwardPrimerCode', max_length=32, blank=True, null=True) # Field name made lowercase. - pcrprimername = models.CharField(db_column='PCRPrimerName', max_length=32, blank=True, null=True) # Field name made lowercase. - pcrprimersequence5_3 = models.CharField(db_column='PCRPrimerSequence5_3', max_length=64, blank=True, null=True) # Field name made lowercase. - pcrreverseprimercode = models.CharField(db_column='PCRReversePrimerCode', max_length=32, blank=True, null=True) # Field name made lowercase. - readdirection = models.CharField(db_column='ReadDirection', max_length=16, blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - rundate = models.DateField(db_column='RunDate', blank=True, null=True) # Field name made lowercase. - scorefilename = models.CharField(db_column='ScoreFileName', max_length=32, blank=True, null=True) # Field name made lowercase. - sequencecocktailprimer = models.BooleanField(db_column='SequenceCocktailPrimer', blank=True, null=True) # Field name made lowercase. - sequenceprimercode = models.CharField(db_column='SequencePrimerCode', max_length=32, blank=True, null=True) # Field name made lowercase. - sequenceprimername = models.CharField(db_column='SequencePrimerName', max_length=32, blank=True, null=True) # Field name made lowercase. - sequenceprimersequence5_3 = models.CharField(db_column='SequencePrimerSequence5_3', max_length=64, blank=True, null=True) # Field name made lowercase. - text1 = models.CharField(db_column='Text1', max_length=32, blank=True, null=True) # Field name made lowercase. - text2 = models.CharField(db_column='Text2', max_length=32, blank=True, null=True) # Field name made lowercase. - text3 = models.CharField(db_column='Text3', max_length=64, blank=True, null=True) # Field name made lowercase. - tracefilename = models.CharField(db_column='TraceFileName', max_length=32, blank=True, null=True) # Field name made lowercase. - yesno1 = models.BooleanField(db_column='YesNo1', blank=True, null=True) # Field name made lowercase. - yesno2 = models.BooleanField(db_column='YesNo2', blank=True, null=True) # Field name made lowercase. - yesno3 = models.BooleanField(db_column='YesNo3', blank=True, null=True) # Field name made lowercase. - runbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='RunByAgentID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - preparedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='PreparedByAgentID', blank=True, null=True) # Field name made lowercase. - dnasequenceid = models.ForeignKey(Dnasequence, models.DO_NOTHING, db_column='DNASequenceID') # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - dryaddoi = models.CharField(db_column='DryadDOI', max_length=256, blank=True, null=True) # Field name made lowercase. - sraexperimentid = models.CharField(db_column='SRAExperimentID', max_length=64, blank=True, null=True) # Field name made lowercase. - srarunid = models.CharField(db_column='SRARunID', max_length=64, blank=True, null=True) # Field name made lowercase. - srasubmissionid = models.CharField(db_column='SRASubmissionID', max_length=64, blank=True, null=True) # Field name made lowercase. - dnaprimerid = models.ForeignKey(Dnaprimer, models.DO_NOTHING, db_column='DNAPrimerID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'dnasequencingrun' - - -class Dnasequencingruncitation(models.Model): - dnasequencingruncitationid = models.AutoField(db_column='DNASequencingRunCitationID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - number1 = models.DecimalField(db_column='Number1', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number2 = models.DecimalField(db_column='Number2', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - text1 = models.TextField(db_column='Text1', blank=True, null=True) # Field name made lowercase. - text2 = models.TextField(db_column='Text2', blank=True, null=True) # Field name made lowercase. - yesno1 = models.BooleanField(db_column='YesNo1', blank=True, null=True) # Field name made lowercase. - yesno2 = models.BooleanField(db_column='YesNo2', blank=True, null=True) # Field name made lowercase. - dnasequencingrunid = models.ForeignKey(Dnasequencingrun, models.DO_NOTHING, db_column='DNASequencingRunID') # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - referenceworkid = models.ForeignKey('Referencework', models.DO_NOTHING, db_column='ReferenceWorkID') # Field name made lowercase. - figurenumber = models.CharField(db_column='FigureNumber', max_length=50, blank=True, null=True) # Field name made lowercase. - isfigured = models.BooleanField(db_column='IsFigured', blank=True, null=True) # Field name made lowercase. - pagenumber = models.CharField(db_column='PageNumber', max_length=50, blank=True, null=True) # Field name made lowercase. - platenumber = models.CharField(db_column='PlateNumber', max_length=50, blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'dnasequencingruncitation' - - -class Dwc(models.Model): - dwcid = models.IntegerField(db_column='dwcId', primary_key=True) # Field name made lowercase. - catalognumber = models.CharField(db_column='catalogNumber', max_length=32, blank=True, null=True) # Field name made lowercase. - class_field = models.CharField(db_column='class', max_length=500, blank=True, null=True) # Field renamed because it was a Python reserved word. - continent = models.CharField(max_length=500, blank=True, null=True) - country = models.CharField(max_length=500, blank=True, null=True) - county = models.CharField(max_length=500, blank=True, null=True) - decimallatitude = models.CharField(db_column='decimalLatitude', max_length=20, blank=True, null=True) # Field name made lowercase. - decimallongitude = models.CharField(db_column='decimalLongitude', max_length=20, blank=True, null=True) # Field name made lowercase. - eventdate = models.DateField(db_column='eventDate', blank=True, null=True) # Field name made lowercase. - eventremarks = models.TextField(db_column='eventRemarks', blank=True, null=True) # Field name made lowercase. - genus = models.CharField(max_length=500, blank=True, null=True) - family = models.CharField(max_length=500, blank=True, null=True) - geodeticdatum = models.CharField(db_column='geodeticDatum', max_length=50, blank=True, null=True) # Field name made lowercase. - georeferenceddate = models.DateField(db_column='georeferencedDate', blank=True, null=True) # Field name made lowercase. - infraspecificepithet = models.CharField(db_column='infraspecificEpithet', max_length=500, blank=True, null=True) # Field name made lowercase. - kingdom = models.CharField(max_length=500, blank=True, null=True) - lifestage = models.CharField(db_column='lifeStage', max_length=50, blank=True, null=True) # Field name made lowercase. - locality = models.CharField(max_length=255, blank=True, null=True) - modified = models.DateTimeField(blank=True, null=True) - order = models.CharField(max_length=500, blank=True, null=True) - othercatalognumbers = models.CharField(db_column='otherCatalogNumbers', max_length=32, blank=True, null=True) # Field name made lowercase. - phylum = models.CharField(max_length=500, blank=True, null=True) - preparations = models.TextField(blank=True, null=True) - recordedby = models.TextField(db_column='recordedBy', blank=True, null=True) # Field name made lowercase. - scientificname = models.CharField(db_column='scientificName', max_length=255, blank=True, null=True) # Field name made lowercase. - sex = models.TextField(blank=True, null=True) - specificepithet = models.CharField(db_column='specificEpithet', max_length=500, blank=True, null=True) # Field name made lowercase. - stateprovince = models.CharField(db_column='stateProvince', max_length=500, blank=True, null=True) # Field name made lowercase. - typestatus = models.CharField(db_column='typeStatus', max_length=50, blank=True, null=True) # Field name made lowercase. - collectioncode = models.CharField(db_column='collectionCode', max_length=50, blank=True, null=True) # Field name made lowercase. - basisofrecord = models.CharField(db_column='basisOfRecord', max_length=32, blank=True, null=True) # Field name made lowercase. - datasetname = models.TextField(db_column='datasetName', blank=True, null=True) # Field name made lowercase. - institutionid = models.CharField(db_column='institutionID', max_length=128, blank=True, null=True) # Field name made lowercase. - institutioncode = models.CharField(db_column='institutionCode', max_length=64, blank=True, null=True) # Field name made lowercase. - rights = models.TextField(blank=True, null=True) - accessrights = models.TextField(db_column='accessRights', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'dwc' - - -class Exchangein(models.Model): - exchangeinid = models.AutoField(db_column='ExchangeInID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - descriptionofmaterial = models.CharField(db_column='DescriptionOfMaterial', max_length=120, blank=True, null=True) # Field name made lowercase. - exchangedate = models.DateField(db_column='ExchangeDate', blank=True, null=True) # Field name made lowercase. - number1 = models.DecimalField(db_column='Number1', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number2 = models.DecimalField(db_column='Number2', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - quantityexchanged = models.SmallIntegerField(db_column='QuantityExchanged', blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - srcgeography = models.CharField(db_column='SrcGeography', max_length=32, blank=True, null=True) # Field name made lowercase. - srctaxonomy = models.CharField(db_column='SrcTaxonomy', max_length=32, blank=True, null=True) # Field name made lowercase. - text1 = models.TextField(db_column='Text1', blank=True, null=True) # Field name made lowercase. - text2 = models.TextField(db_column='Text2', blank=True, null=True) # Field name made lowercase. - yesno1 = models.BooleanField(db_column='YesNo1', blank=True, null=True) # Field name made lowercase. - yesno2 = models.BooleanField(db_column='YesNo2', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - catalogedbyid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CatalogedByID') # Field name made lowercase. - divisionid = models.ForeignKey(Division, models.DO_NOTHING, db_column='DivisionID') # Field name made lowercase. - addressofrecordid = models.ForeignKey(Addressofrecord, models.DO_NOTHING, db_column='AddressOfRecordID', blank=True, null=True) # Field name made lowercase. - receivedfromorganizationid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ReceivedFromOrganizationID') # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - contents = models.TextField(db_column='Contents', blank=True, null=True) # Field name made lowercase. - exchangeinnumber = models.CharField(db_column='ExchangeInNumber', max_length=50, blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'exchangein' - - -class Exchangeinattachment(models.Model): - exchangeinattachmentid = models.AutoField(db_column='ExchangeInAttachmentID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - ordinal = models.IntegerField(db_column='Ordinal') # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - exchangeinid = models.ForeignKey(Exchangein, models.DO_NOTHING, db_column='ExchangeInID') # Field name made lowercase. - attachmentid = models.ForeignKey(Attachment, models.DO_NOTHING, db_column='AttachmentID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'exchangeinattachment' - - -class Exchangeinprep(models.Model): - exchangeinprepid = models.AutoField(db_column='ExchangeInPrepID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - comments = models.TextField(db_column='Comments', blank=True, null=True) # Field name made lowercase. - descriptionofmaterial = models.CharField(db_column='DescriptionOfMaterial', max_length=255, blank=True, null=True) # Field name made lowercase. - number1 = models.IntegerField(db_column='Number1', blank=True, null=True) # Field name made lowercase. - quantity = models.IntegerField(db_column='Quantity', blank=True, null=True) # Field name made lowercase. - text1 = models.TextField(db_column='Text1', blank=True, null=True) # Field name made lowercase. - text2 = models.TextField(db_column='Text2', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - exchangeinid = models.ForeignKey(Exchangein, models.DO_NOTHING, db_column='ExchangeInID', blank=True, null=True) # Field name made lowercase. - disciplineid = models.ForeignKey(Discipline, models.DO_NOTHING, db_column='DisciplineID') # Field name made lowercase. - preparationid = models.ForeignKey('Preparation', models.DO_NOTHING, db_column='PreparationID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'exchangeinprep' - - -class Exchangeout(models.Model): - exchangeoutid = models.AutoField(db_column='ExchangeOutID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - descriptionofmaterial = models.CharField(db_column='DescriptionOfMaterial', max_length=120, blank=True, null=True) # Field name made lowercase. - exchangedate = models.DateField(db_column='ExchangeDate', blank=True, null=True) # Field name made lowercase. - number1 = models.DecimalField(db_column='Number1', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number2 = models.DecimalField(db_column='Number2', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - quantityexchanged = models.SmallIntegerField(db_column='QuantityExchanged', blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - srcgeography = models.CharField(db_column='SrcGeography', max_length=32, blank=True, null=True) # Field name made lowercase. - srctaxonomy = models.CharField(db_column='SrcTaxonomy', max_length=32, blank=True, null=True) # Field name made lowercase. - text1 = models.TextField(db_column='Text1', blank=True, null=True) # Field name made lowercase. - text2 = models.TextField(db_column='Text2', blank=True, null=True) # Field name made lowercase. - yesno1 = models.BooleanField(db_column='YesNo1', blank=True, null=True) # Field name made lowercase. - yesno2 = models.BooleanField(db_column='YesNo2', blank=True, null=True) # Field name made lowercase. - addressofrecordid = models.ForeignKey(Addressofrecord, models.DO_NOTHING, db_column='AddressOfRecordID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - senttoorganizationid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='SentToOrganizationID') # Field name made lowercase. - catalogedbyid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CatalogedByID') # Field name made lowercase. - divisionid = models.ForeignKey(Division, models.DO_NOTHING, db_column='DivisionID') # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - contents = models.TextField(db_column='Contents', blank=True, null=True) # Field name made lowercase. - exchangeoutnumber = models.CharField(db_column='ExchangeOutNumber', max_length=50) # Field name made lowercase. - deaccessionid = models.ForeignKey(Deaccession, models.DO_NOTHING, db_column='DeaccessionID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'exchangeout' - - -class Exchangeoutattachment(models.Model): - exchangeoutattachmentid = models.AutoField(db_column='ExchangeOutAttachmentID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - ordinal = models.IntegerField(db_column='Ordinal') # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - attachmentid = models.ForeignKey(Attachment, models.DO_NOTHING, db_column='AttachmentID') # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - exchangeoutid = models.ForeignKey(Exchangeout, models.DO_NOTHING, db_column='ExchangeOutID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'exchangeoutattachment' - - -class Exchangeoutprep(models.Model): - exchangeoutprepid = models.AutoField(db_column='ExchangeOutPrepID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - comments = models.TextField(db_column='Comments', blank=True, null=True) # Field name made lowercase. - descriptionofmaterial = models.CharField(db_column='DescriptionOfMaterial', max_length=255, blank=True, null=True) # Field name made lowercase. - number1 = models.IntegerField(db_column='Number1', blank=True, null=True) # Field name made lowercase. - quantity = models.IntegerField(db_column='Quantity', blank=True, null=True) # Field name made lowercase. - text1 = models.TextField(db_column='Text1', blank=True, null=True) # Field name made lowercase. - text2 = models.TextField(db_column='Text2', blank=True, null=True) # Field name made lowercase. - exchangeoutid = models.ForeignKey(Exchangeout, models.DO_NOTHING, db_column='ExchangeOutID', blank=True, null=True) # Field name made lowercase. - preparationid = models.ForeignKey('Preparation', models.DO_NOTHING, db_column='PreparationID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - disciplineid = models.ForeignKey(Discipline, models.DO_NOTHING, db_column='DisciplineID') # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'exchangeoutprep' - - -class Exsiccata(models.Model): - exsiccataid = models.AutoField(db_column='ExsiccataID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - title = models.CharField(db_column='Title', max_length=255) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - referenceworkid = models.ForeignKey('Referencework', models.DO_NOTHING, db_column='ReferenceWorkID') # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - schedae = models.CharField(db_column='Schedae', max_length=255, blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'exsiccata' - - -class Exsiccataitem(models.Model): - exsiccataitemid = models.AutoField(db_column='ExsiccataItemID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - fascicle = models.CharField(db_column='Fascicle', max_length=16, blank=True, null=True) # Field name made lowercase. - number = models.CharField(db_column='Number', max_length=16, blank=True, null=True) # Field name made lowercase. - exsiccataid = models.ForeignKey(Exsiccata, models.DO_NOTHING, db_column='ExsiccataID') # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - collectionobjectid = models.ForeignKey(Collectionobject, models.DO_NOTHING, db_column='CollectionObjectID') # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'exsiccataitem' - - -class Extractor(models.Model): - extractorid = models.AutoField(db_column='ExtractorID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - ordernumber = models.IntegerField(db_column='OrderNumber') # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - text1 = models.TextField(db_column='Text1', blank=True, null=True) # Field name made lowercase. - text2 = models.TextField(db_column='Text2', blank=True, null=True) # Field name made lowercase. - yesno1 = models.BooleanField(db_column='YesNo1', blank=True, null=True) # Field name made lowercase. - yesno2 = models.BooleanField(db_column='YesNo2', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - agentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='AgentID') # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - dnasequenceid = models.ForeignKey(Dnasequence, models.DO_NOTHING, db_column='DNASequenceID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'extractor' - unique_together = (('agentid', 'dnasequenceid'),) - - -class Fieldnotebook(models.Model): - fieldnotebookid = models.AutoField(db_column='FieldNotebookID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - description = models.TextField(db_column='Description', blank=True, null=True) # Field name made lowercase. - enddate = models.DateField(db_column='EndDate', blank=True, null=True) # Field name made lowercase. - storage = models.CharField(db_column='Storage', max_length=64, blank=True, null=True) # Field name made lowercase. - name = models.CharField(db_column='Name', max_length=32, blank=True, null=True) # Field name made lowercase. - startdate = models.DateField(db_column='StartDate', blank=True, null=True) # Field name made lowercase. - collectionid = models.ForeignKey(Collection, models.DO_NOTHING, db_column='CollectionID') # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - disciplineid = models.ForeignKey(Discipline, models.DO_NOTHING, db_column='DisciplineID') # Field name made lowercase. - agentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='AgentID') # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'fieldnotebook' - - -class Fieldnotebookattachment(models.Model): - fieldnotebookattachmentid = models.AutoField(db_column='FieldNotebookAttachmentId', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - ordinal = models.IntegerField(db_column='Ordinal') # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - fieldnotebookid = models.ForeignKey(Fieldnotebook, models.DO_NOTHING, db_column='FieldNotebookID') # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - attachmentid = models.ForeignKey(Attachment, models.DO_NOTHING, db_column='AttachmentID') # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'fieldnotebookattachment' - - -class Fieldnotebookpage(models.Model): - fieldnotebookpageid = models.AutoField(db_column='FieldNotebookPageID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - description = models.CharField(db_column='Description', max_length=128, blank=True, null=True) # Field name made lowercase. - pagenumber = models.CharField(db_column='PageNumber', max_length=32) # Field name made lowercase. - scandate = models.DateField(db_column='ScanDate', blank=True, null=True) # Field name made lowercase. - fieldnotebookpagesetid = models.ForeignKey('Fieldnotebookpageset', models.DO_NOTHING, db_column='FieldNotebookPageSetID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - disciplineid = models.ForeignKey(Discipline, models.DO_NOTHING, db_column='DisciplineID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'fieldnotebookpage' - - -class Fieldnotebookpageattachment(models.Model): - fieldnotebookpageattachmentid = models.AutoField(db_column='FieldNotebookPageAttachmentId', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - ordinal = models.IntegerField(db_column='Ordinal') # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - attachmentid = models.ForeignKey(Attachment, models.DO_NOTHING, db_column='AttachmentID') # Field name made lowercase. - fieldnotebookpageid = models.ForeignKey(Fieldnotebookpage, models.DO_NOTHING, db_column='FieldNotebookPageID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'fieldnotebookpageattachment' - - -class Fieldnotebookpageset(models.Model): - fieldnotebookpagesetid = models.AutoField(db_column='FieldNotebookPageSetID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - description = models.CharField(db_column='Description', max_length=128, blank=True, null=True) # Field name made lowercase. - enddate = models.DateField(db_column='EndDate', blank=True, null=True) # Field name made lowercase. - method = models.CharField(db_column='Method', max_length=64, blank=True, null=True) # Field name made lowercase. - ordernumber = models.SmallIntegerField(db_column='OrderNumber', blank=True, null=True) # Field name made lowercase. - startdate = models.DateField(db_column='StartDate', blank=True, null=True) # Field name made lowercase. - disciplineid = models.ForeignKey(Discipline, models.DO_NOTHING, db_column='DisciplineID') # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - fieldnotebookid = models.ForeignKey(Fieldnotebook, models.DO_NOTHING, db_column='FieldNotebookID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - agentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='AgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'fieldnotebookpageset' - - -class Fieldnotebookpagesetattachment(models.Model): - fieldnotebookpagesetattachmentid = models.AutoField(db_column='FieldNotebookPageSetAttachmentId', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - ordinal = models.IntegerField(db_column='Ordinal') # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - fieldnotebookpagesetid = models.ForeignKey(Fieldnotebookpageset, models.DO_NOTHING, db_column='FieldNotebookPageSetID') # Field name made lowercase. - attachmentid = models.ForeignKey(Attachment, models.DO_NOTHING, db_column='AttachmentID') # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'fieldnotebookpagesetattachment' - - -class Fundingagent(models.Model): - fundingagentid = models.AutoField(db_column='FundingAgentID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - isprimary = models.BooleanField(db_column='IsPrimary') # Field name made lowercase. - ordernumber = models.IntegerField(db_column='OrderNumber') # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - type = models.CharField(db_column='Type', max_length=32, blank=True, null=True) # Field name made lowercase. - agentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='AgentID') # Field name made lowercase. - collectingtripid = models.ForeignKey(Collectingtrip, models.DO_NOTHING, db_column='CollectingTripID') # Field name made lowercase. - divisionid = models.ForeignKey(Division, models.DO_NOTHING, db_column='DivisionID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'fundingagent' - unique_together = (('agentid', 'collectingtripid'),) - - -class Geocoorddetail(models.Model): - geocoorddetailid = models.AutoField(db_column='GeoCoordDetailID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - errorpolygon = models.TextField(db_column='ErrorPolygon', blank=True, null=True) # Field name made lowercase. - georefaccuracyunits = models.CharField(db_column='GeoRefAccuracyUnits', max_length=20, blank=True, null=True) # Field name made lowercase. - georefdetdate = models.DateTimeField(db_column='GeoRefDetDate', blank=True, null=True) # Field name made lowercase. - georefdetref = models.CharField(db_column='GeoRefDetRef', max_length=100, blank=True, null=True) # Field name made lowercase. - georefremarks = models.TextField(db_column='GeoRefRemarks', blank=True, null=True) # Field name made lowercase. - georefverificationstatus = models.CharField(db_column='GeoRefVerificationStatus', max_length=50, blank=True, null=True) # Field name made lowercase. - maxuncertaintyest = models.DecimalField(db_column='MaxUncertaintyEst', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - maxuncertaintyestunit = models.CharField(db_column='MaxUncertaintyEstUnit', max_length=8, blank=True, null=True) # Field name made lowercase. - namedplaceextent = models.DecimalField(db_column='NamedPlaceExtent', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - nogeorefbecause = models.CharField(db_column='NoGeoRefBecause', max_length=100, blank=True, null=True) # Field name made lowercase. - originalcoordsystem = models.CharField(db_column='OriginalCoordSystem', max_length=32, blank=True, null=True) # Field name made lowercase. - protocol = models.CharField(db_column='Protocol', max_length=64, blank=True, null=True) # Field name made lowercase. - source = models.CharField(db_column='Source', max_length=64, blank=True, null=True) # Field name made lowercase. - uncertaintypolygon = models.TextField(db_column='UncertaintyPolygon', blank=True, null=True) # Field name made lowercase. - validation = models.CharField(db_column='Validation', max_length=64, blank=True, null=True) # Field name made lowercase. - agentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='AgentID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - localityid = models.ForeignKey('Locality', models.DO_NOTHING, db_column='LocalityID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - georefaccuracy = models.DecimalField(db_column='GeoRefAccuracy', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - text1 = models.TextField(db_column='Text1', blank=True, null=True) # Field name made lowercase. - text2 = models.TextField(db_column='Text2', blank=True, null=True) # Field name made lowercase. - text3 = models.TextField(db_column='Text3', blank=True, null=True) # Field name made lowercase. - georefcompileddate = models.DateTimeField(db_column='GeoRefCompiledDate', blank=True, null=True) # Field name made lowercase. - compiledbyid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CompiledByID', blank=True, null=True) # Field name made lowercase. - integer1 = models.IntegerField(db_column='Integer1', blank=True, null=True) # Field name made lowercase. - integer2 = models.IntegerField(db_column='Integer2', blank=True, null=True) # Field name made lowercase. - integer3 = models.IntegerField(db_column='Integer3', blank=True, null=True) # Field name made lowercase. - integer4 = models.IntegerField(db_column='Integer4', blank=True, null=True) # Field name made lowercase. - integer5 = models.IntegerField(db_column='Integer5', blank=True, null=True) # Field name made lowercase. - number1 = models.DecimalField(db_column='Number1', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number2 = models.DecimalField(db_column='Number2', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number3 = models.DecimalField(db_column='Number3', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number4 = models.DecimalField(db_column='Number4', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number5 = models.DecimalField(db_column='Number5', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - text4 = models.TextField(db_column='Text4', blank=True, null=True) # Field name made lowercase. - text5 = models.TextField(db_column='Text5', blank=True, null=True) # Field name made lowercase. - yesno1 = models.BooleanField(db_column='YesNo1', blank=True, null=True) # Field name made lowercase. - yesno2 = models.BooleanField(db_column='YesNo2', blank=True, null=True) # Field name made lowercase. - yesno3 = models.BooleanField(db_column='YesNo3', blank=True, null=True) # Field name made lowercase. - yesno4 = models.BooleanField(db_column='YesNo4', blank=True, null=True) # Field name made lowercase. - yesno5 = models.BooleanField(db_column='YesNo5', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'geocoorddetail' - - -class Geography(models.Model): - geographyid = models.AutoField(db_column='GeographyID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - abbrev = models.CharField(db_column='Abbrev', max_length=16, blank=True, null=True) # Field name made lowercase. - centroidlat = models.DecimalField(db_column='CentroidLat', max_digits=19, decimal_places=2, blank=True, null=True) # Field name made lowercase. - centroidlon = models.DecimalField(db_column='CentroidLon', max_digits=19, decimal_places=2, blank=True, null=True) # Field name made lowercase. - commonname = models.CharField(db_column='CommonName', max_length=128, blank=True, null=True) # Field name made lowercase. - fullname = models.CharField(db_column='FullName', max_length=500, blank=True, null=True) # Field name made lowercase. - geographycode = models.CharField(db_column='GeographyCode', max_length=24, blank=True, null=True) # Field name made lowercase. - gml = models.TextField(db_column='GML', blank=True, null=True) # Field name made lowercase. - guid = models.CharField(db_column='GUID', max_length=128, blank=True, null=True) # Field name made lowercase. - highestchildnodenumber = models.IntegerField(db_column='HighestChildNodeNumber', blank=True, null=True) # Field name made lowercase. - isaccepted = models.BooleanField(db_column='IsAccepted', blank=True, null=True) # Field name made lowercase. - iscurrent = models.BooleanField(db_column='IsCurrent', blank=True, null=True) # Field name made lowercase. - name = models.CharField(db_column='Name', max_length=128, blank=True, null=True) # Field name made lowercase. - nodenumber = models.IntegerField(db_column='NodeNumber', blank=True, null=True) # Field name made lowercase. - number1 = models.IntegerField(db_column='Number1', blank=True, null=True) # Field name made lowercase. - number2 = models.IntegerField(db_column='Number2', blank=True, null=True) # Field name made lowercase. - rankid = models.IntegerField(db_column='RankID') # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - text1 = models.CharField(db_column='Text1', max_length=32, blank=True, null=True) # Field name made lowercase. - text2 = models.CharField(db_column='Text2', max_length=32, blank=True, null=True) # Field name made lowercase. - timestampversion = models.DateTimeField(db_column='TimestampVersion', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - geographytreedefid = models.ForeignKey('Geographytreedef', models.DO_NOTHING, db_column='GeographyTreeDefID') # Field name made lowercase. - acceptedid = models.ForeignKey('self', models.DO_NOTHING, db_column='AcceptedID', blank=True, null=True) # Field name made lowercase. - parentid = models.ForeignKey('self', models.DO_NOTHING, db_column='ParentID', blank=True, null=True) # Field name made lowercase. - geographytreedefitemid = models.ForeignKey('Geographytreedefitem', models.DO_NOTHING, db_column='GeographyTreeDefItemID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'geography' - - -class Geographytreedef(models.Model): - geographytreedefid = models.AutoField(db_column='GeographyTreeDefID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - fullnamedirection = models.IntegerField(db_column='FullNameDirection', blank=True, null=True) # Field name made lowercase. - name = models.CharField(db_column='Name', max_length=64) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'geographytreedef' - - -class Geographytreedefitem(models.Model): - geographytreedefitemid = models.AutoField(db_column='GeographyTreeDefItemID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - fullnameseparator = models.CharField(db_column='FullNameSeparator', max_length=32, blank=True, null=True) # Field name made lowercase. - isenforced = models.BooleanField(db_column='IsEnforced', blank=True, null=True) # Field name made lowercase. - isinfullname = models.BooleanField(db_column='IsInFullName', blank=True, null=True) # Field name made lowercase. - name = models.CharField(db_column='Name', max_length=64) # Field name made lowercase. - rankid = models.IntegerField(db_column='RankID') # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - textafter = models.CharField(db_column='TextAfter', max_length=64, blank=True, null=True) # Field name made lowercase. - textbefore = models.CharField(db_column='TextBefore', max_length=64, blank=True, null=True) # Field name made lowercase. - title = models.CharField(db_column='Title', max_length=64, blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - parentitemid = models.ForeignKey('self', models.DO_NOTHING, db_column='ParentItemID', blank=True, null=True) # Field name made lowercase. - geographytreedefid = models.ForeignKey(Geographytreedef, models.DO_NOTHING, db_column='GeographyTreeDefID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'geographytreedefitem' - - -class Geologictimeperiod(models.Model): - geologictimeperiodid = models.AutoField(db_column='GeologicTimePeriodID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - endperiod = models.DecimalField(db_column='EndPeriod', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - enduncertainty = models.DecimalField(db_column='EndUncertainty', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - fullname = models.CharField(db_column='FullName', max_length=255, blank=True, null=True) # Field name made lowercase. - guid = models.CharField(db_column='GUID', max_length=128, blank=True, null=True) # Field name made lowercase. - highestchildnodenumber = models.IntegerField(db_column='HighestChildNodeNumber', blank=True, null=True) # Field name made lowercase. - isaccepted = models.BooleanField(db_column='IsAccepted', blank=True, null=True) # Field name made lowercase. - isbiostrat = models.BooleanField(db_column='IsBioStrat', blank=True, null=True) # Field name made lowercase. - name = models.CharField(db_column='Name', max_length=64) # Field name made lowercase. - nodenumber = models.IntegerField(db_column='NodeNumber', blank=True, null=True) # Field name made lowercase. - rankid = models.IntegerField(db_column='RankID') # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - standard = models.CharField(db_column='Standard', max_length=64, blank=True, null=True) # Field name made lowercase. - startperiod = models.DecimalField(db_column='StartPeriod', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - startuncertainty = models.DecimalField(db_column='StartUncertainty', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - text1 = models.CharField(db_column='Text1', max_length=128, blank=True, null=True) # Field name made lowercase. - text2 = models.CharField(db_column='Text2', max_length=128, blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - geologictimeperiodtreedefid = models.ForeignKey('Geologictimeperiodtreedef', models.DO_NOTHING, db_column='GeologicTimePeriodTreeDefID') # Field name made lowercase. - acceptedid = models.ForeignKey('self', models.DO_NOTHING, db_column='AcceptedID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - geologictimeperiodtreedefitemid = models.ForeignKey('Geologictimeperiodtreedefitem', models.DO_NOTHING, db_column='GeologicTimePeriodTreeDefItemID') # Field name made lowercase. - parentid = models.ForeignKey('self', models.DO_NOTHING, db_column='ParentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'geologictimeperiod' - - -class Geologictimeperiodtreedef(models.Model): - geologictimeperiodtreedefid = models.AutoField(db_column='GeologicTimePeriodTreeDefID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - fullnamedirection = models.IntegerField(db_column='FullNameDirection', blank=True, null=True) # Field name made lowercase. - name = models.CharField(db_column='Name', max_length=64) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'geologictimeperiodtreedef' - - -class Geologictimeperiodtreedefitem(models.Model): - geologictimeperiodtreedefitemid = models.AutoField(db_column='GeologicTimePeriodTreeDefItemID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - fullnameseparator = models.CharField(db_column='FullNameSeparator', max_length=32, blank=True, null=True) # Field name made lowercase. - isenforced = models.BooleanField(db_column='IsEnforced', blank=True, null=True) # Field name made lowercase. - isinfullname = models.BooleanField(db_column='IsInFullName', blank=True, null=True) # Field name made lowercase. - name = models.CharField(db_column='Name', max_length=64) # Field name made lowercase. - rankid = models.IntegerField(db_column='RankID') # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - textafter = models.CharField(db_column='TextAfter', max_length=64, blank=True, null=True) # Field name made lowercase. - textbefore = models.CharField(db_column='TextBefore', max_length=64, blank=True, null=True) # Field name made lowercase. - title = models.CharField(db_column='Title', max_length=64, blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - geologictimeperiodtreedefid = models.ForeignKey(Geologictimeperiodtreedef, models.DO_NOTHING, db_column='GeologicTimePeriodTreeDefID') # Field name made lowercase. - parentitemid = models.ForeignKey('self', models.DO_NOTHING, db_column='ParentItemID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'geologictimeperiodtreedefitem' - - -class Geoname(models.Model): - geonameid = models.IntegerField(db_column='geonameId', primary_key=True) # Field name made lowercase. - name = models.CharField(max_length=255, blank=True, null=True) - asciiname = models.CharField(max_length=255, blank=True, null=True) - alternatenames = models.TextField(blank=True, null=True) - latitude = models.DecimalField(max_digits=9, decimal_places=7, blank=True, null=True) - longitude = models.DecimalField(max_digits=9, decimal_places=7, blank=True, null=True) - fclass = models.CharField(max_length=1, blank=True, null=True) - fcode = models.CharField(max_length=10, blank=True, null=True) - country = models.CharField(max_length=2, blank=True, null=True) - cc2 = models.CharField(max_length=60, blank=True, null=True) - admin1 = models.CharField(max_length=20, blank=True, null=True) - admin2 = models.CharField(max_length=80, blank=True, null=True) - admin3 = models.CharField(max_length=20, blank=True, null=True) - admin4 = models.CharField(max_length=20, blank=True, null=True) - population = models.IntegerField(blank=True, null=True) - elevation = models.IntegerField(blank=True, null=True) - gtopo30 = models.IntegerField(blank=True, null=True) - timezone = models.CharField(max_length=40, blank=True, null=True) - moddate = models.DateField(blank=True, null=True) - isocode = models.CharField(db_column='ISOCode', max_length=24, blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'geoname' - - -class Gift(models.Model): - giftid = models.AutoField(db_column='GiftID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - datereceived = models.DateField(db_column='DateReceived', blank=True, null=True) # Field name made lowercase. - giftdate = models.DateField(db_column='GiftDate', blank=True, null=True) # Field name made lowercase. - giftnumber = models.CharField(db_column='GiftNumber', max_length=50) # Field name made lowercase. - isfinancialresponsibility = models.BooleanField(db_column='IsFinancialResponsibility', blank=True, null=True) # Field name made lowercase. - number1 = models.DecimalField(db_column='Number1', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number2 = models.DecimalField(db_column='Number2', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - purposeofgift = models.CharField(db_column='PurposeOfGift', max_length=64, blank=True, null=True) # Field name made lowercase. - receivedcomments = models.CharField(db_column='ReceivedComments', max_length=255, blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - specialconditions = models.TextField(db_column='SpecialConditions', blank=True, null=True) # Field name made lowercase. - srcgeography = models.CharField(db_column='SrcGeography', max_length=500, blank=True, null=True) # Field name made lowercase. - srctaxonomy = models.CharField(db_column='SrcTaxonomy', max_length=500, blank=True, null=True) # Field name made lowercase. - text1 = models.TextField(db_column='Text1', blank=True, null=True) # Field name made lowercase. - text2 = models.TextField(db_column='Text2', blank=True, null=True) # Field name made lowercase. - yesno1 = models.BooleanField(db_column='YesNo1', blank=True, null=True) # Field name made lowercase. - yesno2 = models.BooleanField(db_column='YesNo2', blank=True, null=True) # Field name made lowercase. - addressofrecordid = models.ForeignKey(Addressofrecord, models.DO_NOTHING, db_column='AddressOfRecordID', blank=True, null=True) # Field name made lowercase. - divisionid = models.ForeignKey(Division, models.DO_NOTHING, db_column='DivisionID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - disciplineid = models.ForeignKey(Discipline, models.DO_NOTHING, db_column='DisciplineID') # Field name made lowercase. - contents = models.TextField(db_column='Contents', blank=True, null=True) # Field name made lowercase. - integer1 = models.IntegerField(db_column='Integer1', blank=True, null=True) # Field name made lowercase. - integer2 = models.IntegerField(db_column='Integer2', blank=True, null=True) # Field name made lowercase. - integer3 = models.IntegerField(db_column='Integer3', blank=True, null=True) # Field name made lowercase. - date1 = models.DateField(db_column='Date1', blank=True, null=True) # Field name made lowercase. - date1precision = models.IntegerField(db_column='Date1Precision', blank=True, null=True) # Field name made lowercase. - status = models.CharField(db_column='Status', max_length=64, blank=True, null=True) # Field name made lowercase. - text3 = models.TextField(db_column='Text3', blank=True, null=True) # Field name made lowercase. - text4 = models.TextField(db_column='Text4', blank=True, null=True) # Field name made lowercase. - text5 = models.CharField(db_column='Text5', max_length=128, blank=True, null=True) # Field name made lowercase. - deaccessionid = models.ForeignKey(Deaccession, models.DO_NOTHING, db_column='DeaccessionID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'gift' - - -class Giftagent(models.Model): - giftagentid = models.AutoField(db_column='GiftAgentID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - role = models.CharField(db_column='Role', max_length=50) # Field name made lowercase. - disciplineid = models.ForeignKey(Discipline, models.DO_NOTHING, db_column='DisciplineID') # Field name made lowercase. - giftid = models.ForeignKey(Gift, models.DO_NOTHING, db_column='GiftID') # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - agentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='AgentID') # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - date1 = models.DateField(db_column='Date1', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'giftagent' - unique_together = (('role', 'giftid', 'agentid'),) - - -class Giftattachment(models.Model): - giftattachmentid = models.AutoField(db_column='GiftAttachmentID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - ordinal = models.IntegerField(db_column='Ordinal') # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - attachmentid = models.ForeignKey(Attachment, models.DO_NOTHING, db_column='AttachmentID') # Field name made lowercase. - giftid = models.ForeignKey(Gift, models.DO_NOTHING, db_column='GiftID') # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'giftattachment' - - -class Giftpreparation(models.Model): - giftpreparationid = models.AutoField(db_column='GiftPreparationID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - descriptionofmaterial = models.CharField(db_column='DescriptionOfMaterial', max_length=255, blank=True, null=True) # Field name made lowercase. - incomments = models.TextField(db_column='InComments', blank=True, null=True) # Field name made lowercase. - outcomments = models.TextField(db_column='OutComments', blank=True, null=True) # Field name made lowercase. - quantity = models.IntegerField(db_column='Quantity', blank=True, null=True) # Field name made lowercase. - receivedcomments = models.TextField(db_column='ReceivedComments', blank=True, null=True) # Field name made lowercase. - disciplineid = models.ForeignKey(Discipline, models.DO_NOTHING, db_column='DisciplineID') # Field name made lowercase. - preparationid = models.ForeignKey('Preparation', models.DO_NOTHING, db_column='PreparationID', blank=True, null=True) # Field name made lowercase. - giftid = models.ForeignKey(Gift, models.DO_NOTHING, db_column='GiftID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - text1 = models.TextField(db_column='Text1', blank=True, null=True) # Field name made lowercase. - text2 = models.TextField(db_column='Text2', blank=True, null=True) # Field name made lowercase. - text3 = models.TextField(db_column='Text3', blank=True, null=True) # Field name made lowercase. - text4 = models.TextField(db_column='Text4', blank=True, null=True) # Field name made lowercase. - text5 = models.TextField(db_column='Text5', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'giftpreparation' - - -class Groupperson(models.Model): - grouppersonid = models.AutoField(db_column='GroupPersonID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - ordernumber = models.SmallIntegerField(db_column='OrderNumber') # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - groupid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='GroupID') # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - memberid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='MemberID') # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - divisionid = models.ForeignKey(Division, models.DO_NOTHING, db_column='DivisionID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'groupperson' - unique_together = (('ordernumber', 'groupid'),) - - -class HibernateUniqueKey(models.Model): - next_hi = models.IntegerField(blank=True, null=True) - - class Meta: - managed = False - db_table = 'hibernate_unique_key' - - -class Inforequest(models.Model): - inforequestid = models.AutoField(db_column='InfoRequestID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - collectionmemberid = models.IntegerField(db_column='CollectionMemberID') # Field name made lowercase. - email = models.CharField(db_column='Email', max_length=50, blank=True, null=True) # Field name made lowercase. - firstname = models.CharField(db_column='Firstname', max_length=50, blank=True, null=True) # Field name made lowercase. - inforeqnumber = models.CharField(db_column='InfoReqNumber', max_length=32, blank=True, null=True) # Field name made lowercase. - institution = models.CharField(db_column='Institution', max_length=127, blank=True, null=True) # Field name made lowercase. - lastname = models.CharField(db_column='Lastname', max_length=50, blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - replydate = models.DateField(db_column='ReplyDate', blank=True, null=True) # Field name made lowercase. - requestdate = models.DateField(db_column='RequestDate', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - agentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='AgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'inforequest' - - -class Institution(models.Model): - usergroupscopeid = models.IntegerField(db_column='UserGroupScopeId', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - altname = models.CharField(db_column='AltName', max_length=128, blank=True, null=True) # Field name made lowercase. - code = models.CharField(db_column='Code', max_length=64, blank=True, null=True) # Field name made lowercase. - copyright = models.TextField(db_column='Copyright', blank=True, null=True) # Field name made lowercase. - currentmanagedrelversion = models.CharField(db_column='CurrentManagedRelVersion', max_length=8, blank=True, null=True) # Field name made lowercase. - currentmanagedschemaversion = models.CharField(db_column='CurrentManagedSchemaVersion', max_length=8, blank=True, null=True) # Field name made lowercase. - description = models.TextField(db_column='Description', blank=True, null=True) # Field name made lowercase. - disclaimer = models.TextField(db_column='Disclaimer', blank=True, null=True) # Field name made lowercase. - hasbeenasked = models.BooleanField(db_column='HasBeenAsked', blank=True, null=True) # Field name made lowercase. - iconuri = models.CharField(db_column='IconURI', max_length=255, blank=True, null=True) # Field name made lowercase. - institutionid = models.IntegerField(db_column='institutionId', blank=True, null=True) # Field name made lowercase. - ipr = models.TextField(db_column='Ipr', blank=True, null=True) # Field name made lowercase. - isaccessionsglobal = models.BooleanField(db_column='IsAccessionsGlobal') # Field name made lowercase. - isanonymous = models.BooleanField(db_column='IsAnonymous', blank=True, null=True) # Field name made lowercase. - isreleasemanagedglobally = models.BooleanField(db_column='IsReleaseManagedGlobally', blank=True, null=True) # Field name made lowercase. - issecurityon = models.BooleanField(db_column='IsSecurityOn') # Field name made lowercase. - isserverbased = models.BooleanField(db_column='IsServerBased') # Field name made lowercase. - issharinglocalities = models.BooleanField(db_column='IsSharingLocalities') # Field name made lowercase. - issinglegeographytree = models.BooleanField(db_column='IsSingleGeographyTree') # Field name made lowercase. - license = models.TextField(db_column='License', blank=True, null=True) # Field name made lowercase. - lsidauthority = models.CharField(db_column='LsidAuthority', max_length=64, blank=True, null=True) # Field name made lowercase. - minimumpwdlength = models.IntegerField(db_column='MinimumPwdLength', blank=True, null=True) # Field name made lowercase. - guid = models.CharField(db_column='GUID', max_length=128, blank=True, null=True) # Field name made lowercase. - name = models.CharField(db_column='Name', max_length=255, blank=True, null=True) # Field name made lowercase. - regnumber = models.CharField(db_column='RegNumber', max_length=24, blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - termsofuse = models.TextField(db_column='TermsOfUse', blank=True, null=True) # Field name made lowercase. - uri = models.CharField(db_column='Uri', max_length=255, blank=True, null=True) # Field name made lowercase. - storagetreedefid = models.ForeignKey('Storagetreedef', models.DO_NOTHING, db_column='StorageTreeDefID', blank=True, null=True) # Field name made lowercase. - addressid = models.ForeignKey(Address, models.DO_NOTHING, db_column='AddressID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'institution' - - -class Institutionnetwork(models.Model): - institutionnetworkid = models.AutoField(db_column='InstitutionNetworkID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - altname = models.CharField(db_column='AltName', max_length=128, blank=True, null=True) # Field name made lowercase. - code = models.CharField(db_column='Code', max_length=64, blank=True, null=True) # Field name made lowercase. - copyright = models.TextField(db_column='Copyright', blank=True, null=True) # Field name made lowercase. - description = models.TextField(db_column='Description', blank=True, null=True) # Field name made lowercase. - disclaimer = models.TextField(db_column='Disclaimer', blank=True, null=True) # Field name made lowercase. - iconuri = models.CharField(db_column='IconURI', max_length=255, blank=True, null=True) # Field name made lowercase. - ipr = models.TextField(db_column='Ipr', blank=True, null=True) # Field name made lowercase. - license = models.TextField(db_column='License', blank=True, null=True) # Field name made lowercase. - name = models.CharField(db_column='Name', max_length=255, blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - termsofuse = models.TextField(db_column='TermsOfUse', blank=True, null=True) # Field name made lowercase. - uri = models.CharField(db_column='Uri', max_length=255, blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - addressid = models.ForeignKey(Address, models.DO_NOTHING, db_column='AddressID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'institutionnetwork' - - -class IosColobjagents(models.Model): - oldid = models.IntegerField(db_column='OldID', primary_key=True) # Field name made lowercase. - newid = models.IntegerField(db_column='NewID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'ios_colobjagents' - - -class IosColobjbio(models.Model): - oldid = models.IntegerField(db_column='OldID', primary_key=True) # Field name made lowercase. - newid = models.IntegerField(db_column='NewID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'ios_colobjbio' - - -class IosColobjchron(models.Model): - oldid = models.IntegerField(db_column='OldID', primary_key=True) # Field name made lowercase. - newid = models.IntegerField(db_column='NewID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'ios_colobjchron' - - -class IosColobjcnts(models.Model): - oldid = models.IntegerField(db_column='OldID', primary_key=True) # Field name made lowercase. - newid = models.IntegerField(db_column='NewID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'ios_colobjcnts' - - -class IosColobjgeo(models.Model): - oldid = models.IntegerField(db_column='OldID', primary_key=True) # Field name made lowercase. - newid = models.IntegerField(db_column='NewID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'ios_colobjgeo' - - -class IosColobjlitho(models.Model): - oldid = models.IntegerField(db_column='OldID', primary_key=True) # Field name made lowercase. - newid = models.IntegerField(db_column='NewID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'ios_colobjlitho' - - -class IosGeogeoCnt(models.Model): - oldid = models.IntegerField(db_column='OldID', primary_key=True) # Field name made lowercase. - newid = models.IntegerField(db_column='NewID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'ios_geogeo_cnt' - - -class IosGeogeoCty(models.Model): - oldid = models.IntegerField(db_column='OldID', primary_key=True) # Field name made lowercase. - newid = models.IntegerField(db_column='NewID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'ios_geogeo_cty' - - -class IosGeoloc(models.Model): - oldid = models.IntegerField(db_column='OldID', primary_key=True) # Field name made lowercase. - newid = models.IntegerField(db_column='NewID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'ios_geoloc' - - -class IosGeolocCnt(models.Model): - oldid = models.IntegerField(db_column='OldID', primary_key=True) # Field name made lowercase. - newid = models.IntegerField(db_column='NewID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'ios_geoloc_cnt' - - -class IosGeolocCty(models.Model): - oldid = models.IntegerField(db_column='OldID', primary_key=True) # Field name made lowercase. - newid = models.IntegerField(db_column='NewID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'ios_geoloc_cty' - - -class IosTaxonPid(models.Model): - oldid = models.IntegerField(db_column='OldID', primary_key=True) # Field name made lowercase. - newid = models.IntegerField(db_column='NewID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'ios_taxon_pid' - - -class Journal(models.Model): - journalid = models.AutoField(db_column='JournalID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - guid = models.CharField(db_column='GUID', max_length=128, blank=True, null=True) # Field name made lowercase. - issn = models.CharField(db_column='ISSN', max_length=16, blank=True, null=True) # Field name made lowercase. - journalabbreviation = models.CharField(db_column='JournalAbbreviation', max_length=50, blank=True, null=True) # Field name made lowercase. - journalname = models.CharField(db_column='JournalName', max_length=255, blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - text1 = models.CharField(db_column='Text1', max_length=32, blank=True, null=True) # Field name made lowercase. - institutionid = models.ForeignKey(Institution, models.DO_NOTHING, db_column='InstitutionID') # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'journal' - - -class Latlonpolygon(models.Model): - latlonpolygonid = models.AutoField(db_column='LatLonPolygonID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - description = models.TextField(db_column='Description', blank=True, null=True) # Field name made lowercase. - ispolyline = models.BooleanField(db_column='IsPolyline') # Field name made lowercase. - name = models.CharField(db_column='Name', max_length=64) # Field name made lowercase. - spvisualqueryid = models.ForeignKey('Spvisualquery', models.DO_NOTHING, db_column='SpVisualQueryID', blank=True, null=True) # Field name made lowercase. - localityid = models.ForeignKey('Locality', models.DO_NOTHING, db_column='LocalityID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'latlonpolygon' - - -class Latlonpolygonpnt(models.Model): - latlonpolygonpntid = models.AutoField(db_column='LatLonPolygonPntID', primary_key=True) # Field name made lowercase. - elevation = models.IntegerField(db_column='Elevation', blank=True, null=True) # Field name made lowercase. - latitude = models.DecimalField(db_column='Latitude', max_digits=12, decimal_places=10) # Field name made lowercase. - longitude = models.DecimalField(db_column='Longitude', max_digits=12, decimal_places=10) # Field name made lowercase. - ordinal = models.IntegerField(db_column='Ordinal') # Field name made lowercase. - latlonpolygonid = models.ForeignKey(Latlonpolygon, models.DO_NOTHING, db_column='LatLonPolygonID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'latlonpolygonpnt' - - -class Lithostrat(models.Model): - lithostratid = models.AutoField(db_column='LithoStratID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - fullname = models.CharField(db_column='FullName', max_length=255, blank=True, null=True) # Field name made lowercase. - guid = models.CharField(db_column='GUID', max_length=128, blank=True, null=True) # Field name made lowercase. - highestchildnodenumber = models.IntegerField(db_column='HighestChildNodeNumber', blank=True, null=True) # Field name made lowercase. - isaccepted = models.BooleanField(db_column='IsAccepted', blank=True, null=True) # Field name made lowercase. - name = models.CharField(db_column='Name', max_length=64) # Field name made lowercase. - nodenumber = models.IntegerField(db_column='NodeNumber', blank=True, null=True) # Field name made lowercase. - number1 = models.DecimalField(db_column='Number1', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number2 = models.DecimalField(db_column='Number2', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - rankid = models.IntegerField(db_column='RankID') # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - text1 = models.TextField(db_column='Text1', blank=True, null=True) # Field name made lowercase. - text2 = models.TextField(db_column='Text2', blank=True, null=True) # Field name made lowercase. - yesno1 = models.BooleanField(db_column='YesNo1', blank=True, null=True) # Field name made lowercase. - yesno2 = models.BooleanField(db_column='YesNo2', blank=True, null=True) # Field name made lowercase. - lithostrattreedefid = models.ForeignKey('Lithostrattreedef', models.DO_NOTHING, db_column='LithoStratTreeDefID') # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - acceptedid = models.ForeignKey('self', models.DO_NOTHING, db_column='AcceptedID', blank=True, null=True) # Field name made lowercase. - lithostrattreedefitemid = models.ForeignKey('Lithostrattreedefitem', models.DO_NOTHING, db_column='LithoStratTreeDefItemID') # Field name made lowercase. - parentid = models.ForeignKey('self', models.DO_NOTHING, db_column='ParentID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'lithostrat' - - -class Lithostrattreedef(models.Model): - lithostrattreedefid = models.AutoField(db_column='LithoStratTreeDefID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - fullnamedirection = models.IntegerField(db_column='FullNameDirection', blank=True, null=True) # Field name made lowercase. - name = models.CharField(db_column='Name', max_length=64) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'lithostrattreedef' - - -class Lithostrattreedefitem(models.Model): - lithostrattreedefitemid = models.AutoField(db_column='LithoStratTreeDefItemID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - fullnameseparator = models.CharField(db_column='FullNameSeparator', max_length=32, blank=True, null=True) # Field name made lowercase. - isenforced = models.BooleanField(db_column='IsEnforced', blank=True, null=True) # Field name made lowercase. - isinfullname = models.BooleanField(db_column='IsInFullName', blank=True, null=True) # Field name made lowercase. - name = models.CharField(db_column='Name', max_length=64) # Field name made lowercase. - rankid = models.IntegerField(db_column='RankID') # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - textafter = models.CharField(db_column='TextAfter', max_length=64, blank=True, null=True) # Field name made lowercase. - textbefore = models.CharField(db_column='TextBefore', max_length=64, blank=True, null=True) # Field name made lowercase. - title = models.CharField(db_column='Title', max_length=64, blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - lithostrattreedefid = models.ForeignKey(Lithostrattreedef, models.DO_NOTHING, db_column='LithoStratTreeDefID') # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - parentitemid = models.ForeignKey('self', models.DO_NOTHING, db_column='ParentItemID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'lithostrattreedefitem' - - -class Loan(models.Model): - loanid = models.AutoField(db_column='LoanID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - currentduedate = models.DateField(db_column='CurrentDueDate', blank=True, null=True) # Field name made lowercase. - dateclosed = models.DateField(db_column='DateClosed', blank=True, null=True) # Field name made lowercase. - datereceived = models.DateField(db_column='DateReceived', blank=True, null=True) # Field name made lowercase. - isclosed = models.BooleanField(db_column='IsClosed', blank=True, null=True) # Field name made lowercase. - isfinancialresponsibility = models.BooleanField(db_column='IsFinancialResponsibility', blank=True, null=True) # Field name made lowercase. - loandate = models.DateField(db_column='LoanDate', blank=True, null=True) # Field name made lowercase. - loannumber = models.CharField(db_column='LoanNumber', max_length=50) # Field name made lowercase. - number1 = models.DecimalField(db_column='Number1', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number2 = models.DecimalField(db_column='Number2', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - originalduedate = models.DateField(db_column='OriginalDueDate', blank=True, null=True) # Field name made lowercase. - overduenotisetdate = models.DateField(db_column='OverdueNotiSetDate', blank=True, null=True) # Field name made lowercase. - purposeofloan = models.CharField(db_column='PurposeOfLoan', max_length=64, blank=True, null=True) # Field name made lowercase. - receivedcomments = models.CharField(db_column='ReceivedComments', max_length=255, blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - specialconditions = models.TextField(db_column='SpecialConditions', blank=True, null=True) # Field name made lowercase. - srcgeography = models.CharField(db_column='SrcGeography', max_length=500, blank=True, null=True) # Field name made lowercase. - srctaxonomy = models.CharField(db_column='SrcTaxonomy', max_length=500, blank=True, null=True) # Field name made lowercase. - text1 = models.TextField(db_column='Text1', blank=True, null=True) # Field name made lowercase. - text2 = models.TextField(db_column='Text2', blank=True, null=True) # Field name made lowercase. - yesno1 = models.BooleanField(db_column='YesNo1', blank=True, null=True) # Field name made lowercase. - yesno2 = models.BooleanField(db_column='YesNo2', blank=True, null=True) # Field name made lowercase. - disciplineid = models.ForeignKey(Discipline, models.DO_NOTHING, db_column='DisciplineID') # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - divisionid = models.ForeignKey(Division, models.DO_NOTHING, db_column='DivisionID', blank=True, null=True) # Field name made lowercase. - addressofrecordid = models.ForeignKey(Addressofrecord, models.DO_NOTHING, db_column='AddressOfRecordID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - contents = models.TextField(db_column='Contents', blank=True, null=True) # Field name made lowercase. - integer1 = models.IntegerField(db_column='Integer1', blank=True, null=True) # Field name made lowercase. - integer2 = models.IntegerField(db_column='Integer2', blank=True, null=True) # Field name made lowercase. - integer3 = models.IntegerField(db_column='Integer3', blank=True, null=True) # Field name made lowercase. - status = models.CharField(db_column='Status', max_length=64, blank=True, null=True) # Field name made lowercase. - text3 = models.TextField(db_column='Text3', blank=True, null=True) # Field name made lowercase. - text4 = models.TextField(db_column='Text4', blank=True, null=True) # Field name made lowercase. - text5 = models.TextField(db_column='Text5', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'loan' - - -class Loanagent(models.Model): - loanagentid = models.AutoField(db_column='LoanAgentID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - role = models.CharField(db_column='Role', max_length=50) # Field name made lowercase. - loanid = models.ForeignKey(Loan, models.DO_NOTHING, db_column='LoanID') # Field name made lowercase. - disciplineid = models.ForeignKey(Discipline, models.DO_NOTHING, db_column='DisciplineID') # Field name made lowercase. - agentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='AgentID') # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'loanagent' - unique_together = (('role', 'loanid', 'agentid'),) - - -class Loanattachment(models.Model): - loanattachmentid = models.AutoField(db_column='LoanAttachmentID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - ordinal = models.IntegerField(db_column='Ordinal') # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - attachmentid = models.ForeignKey(Attachment, models.DO_NOTHING, db_column='AttachmentID') # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - loanid = models.ForeignKey(Loan, models.DO_NOTHING, db_column='LoanID') # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'loanattachment' - - -class Loanpreparation(models.Model): - loanpreparationid = models.AutoField(db_column='LoanPreparationID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - descriptionofmaterial = models.TextField(db_column='DescriptionOfMaterial', blank=True, null=True) # Field name made lowercase. - incomments = models.TextField(db_column='InComments', blank=True, null=True) # Field name made lowercase. - isresolved = models.BooleanField(db_column='IsResolved') # Field name made lowercase. - outcomments = models.TextField(db_column='OutComments', blank=True, null=True) # Field name made lowercase. - quantity = models.IntegerField(db_column='Quantity', blank=True, null=True) # Field name made lowercase. - quantityresolved = models.IntegerField(db_column='QuantityResolved', blank=True, null=True) # Field name made lowercase. - quantityreturned = models.IntegerField(db_column='QuantityReturned', blank=True, null=True) # Field name made lowercase. - receivedcomments = models.TextField(db_column='ReceivedComments', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - loanid = models.ForeignKey(Loan, models.DO_NOTHING, db_column='LoanID') # Field name made lowercase. - disciplineid = models.ForeignKey(Discipline, models.DO_NOTHING, db_column='DisciplineID') # Field name made lowercase. - preparationid = models.ForeignKey('Preparation', models.DO_NOTHING, db_column='PreparationID', blank=True, null=True) # Field name made lowercase. - text1 = models.TextField(db_column='Text1', blank=True, null=True) # Field name made lowercase. - text2 = models.TextField(db_column='Text2', blank=True, null=True) # Field name made lowercase. - text3 = models.TextField(db_column='Text3', blank=True, null=True) # Field name made lowercase. - text4 = models.TextField(db_column='Text4', blank=True, null=True) # Field name made lowercase. - text5 = models.TextField(db_column='Text5', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'loanpreparation' - - -class Loanreturnpreparation(models.Model): - loanreturnpreparationid = models.AutoField(db_column='LoanReturnPreparationID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - quantityresolved = models.IntegerField(db_column='QuantityResolved', blank=True, null=True) # Field name made lowercase. - quantityreturned = models.IntegerField(db_column='QuantityReturned', blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - returneddate = models.DateField(db_column='ReturnedDate', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - deaccessionpreparationid = models.IntegerField(db_column='DeaccessionPreparationID', blank=True, null=True) # Field name made lowercase. - disciplineid = models.ForeignKey(Discipline, models.DO_NOTHING, db_column='DisciplineID') # Field name made lowercase. - loanpreparationid = models.ForeignKey(Loanpreparation, models.DO_NOTHING, db_column='LoanPreparationID') # Field name made lowercase. - receivedbyid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ReceivedByID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'loanreturnpreparation' - - -class Locality(models.Model): - localityid = models.AutoField(db_column='LocalityID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - datum = models.CharField(db_column='Datum', max_length=50, blank=True, null=True) # Field name made lowercase. - elevationaccuracy = models.DecimalField(db_column='ElevationAccuracy', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - elevationmethod = models.CharField(db_column='ElevationMethod', max_length=50, blank=True, null=True) # Field name made lowercase. - gml = models.TextField(db_column='GML', blank=True, null=True) # Field name made lowercase. - guid = models.CharField(db_column='GUID', max_length=128, blank=True, null=True) # Field name made lowercase. - lat1text = models.CharField(db_column='Lat1Text', max_length=50, blank=True, null=True) # Field name made lowercase. - lat2text = models.CharField(db_column='Lat2Text', max_length=50, blank=True, null=True) # Field name made lowercase. - latlongaccuracy = models.DecimalField(db_column='LatLongAccuracy', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - latlongmethod = models.CharField(db_column='LatLongMethod', max_length=50, blank=True, null=True) # Field name made lowercase. - latlongtype = models.CharField(db_column='LatLongType', max_length=50, blank=True, null=True) # Field name made lowercase. - latitude1 = models.DecimalField(db_column='Latitude1', max_digits=12, decimal_places=10, blank=True, null=True) # Field name made lowercase. - latitude2 = models.DecimalField(db_column='Latitude2', max_digits=12, decimal_places=10, blank=True, null=True) # Field name made lowercase. - localityname = models.CharField(db_column='LocalityName', max_length=1024) # Field name made lowercase. - long1text = models.CharField(db_column='Long1Text', max_length=50, blank=True, null=True) # Field name made lowercase. - long2text = models.CharField(db_column='Long2Text', max_length=50, blank=True, null=True) # Field name made lowercase. - longitude1 = models.DecimalField(db_column='Longitude1', max_digits=13, decimal_places=10, blank=True, null=True) # Field name made lowercase. - longitude2 = models.DecimalField(db_column='Longitude2', max_digits=13, decimal_places=10, blank=True, null=True) # Field name made lowercase. - maxelevation = models.DecimalField(db_column='MaxElevation', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - minelevation = models.DecimalField(db_column='MinElevation', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - namedplace = models.CharField(db_column='NamedPlace', max_length=255, blank=True, null=True) # Field name made lowercase. - originalelevationunit = models.CharField(db_column='OriginalElevationUnit', max_length=50, blank=True, null=True) # Field name made lowercase. - originallatlongunit = models.IntegerField(db_column='OriginalLatLongUnit', blank=True, null=True) # Field name made lowercase. - relationtonamedplace = models.CharField(db_column='RelationToNamedPlace', max_length=120, blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - sgrstatus = models.IntegerField(db_column='SGRStatus', blank=True, null=True) # Field name made lowercase. - shortname = models.CharField(db_column='ShortName', max_length=32, blank=True, null=True) # Field name made lowercase. - srclatlongunit = models.IntegerField(db_column='SrcLatLongUnit') # Field name made lowercase. - text1 = models.TextField(db_column='Text1', blank=True, null=True) # Field name made lowercase. - text2 = models.TextField(db_column='Text2', blank=True, null=True) # Field name made lowercase. - verbatimelevation = models.CharField(db_column='VerbatimElevation', max_length=50, blank=True, null=True) # Field name made lowercase. - visibility = models.IntegerField(db_column='Visibility', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - disciplineid = models.ForeignKey(Discipline, models.DO_NOTHING, db_column='DisciplineID') # Field name made lowercase. - visibilitysetbyid = models.ForeignKey('Specifyuser', models.DO_NOTHING, db_column='VisibilitySetByID', blank=True, null=True) # Field name made lowercase. - geographyid = models.ForeignKey(Geography, models.DO_NOTHING, db_column='GeographyID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - text3 = models.TextField(db_column='Text3', blank=True, null=True) # Field name made lowercase. - text4 = models.TextField(db_column='Text4', blank=True, null=True) # Field name made lowercase. - text5 = models.TextField(db_column='Text5', blank=True, null=True) # Field name made lowercase. - verbatimlatitude = models.CharField(db_column='VerbatimLatitude', max_length=50, blank=True, null=True) # Field name made lowercase. - verbatimlongitude = models.CharField(db_column='VerbatimLongitude', max_length=50, blank=True, null=True) # Field name made lowercase. - paleocontextid = models.ForeignKey('Paleocontext', models.DO_NOTHING, db_column='PaleoContextID', blank=True, null=True) # Field name made lowercase. - yesno1 = models.BooleanField(db_column='YesNo1', blank=True, null=True) # Field name made lowercase. - yesno2 = models.BooleanField(db_column='YesNo2', blank=True, null=True) # Field name made lowercase. - yesno3 = models.BooleanField(db_column='YesNo3', blank=True, null=True) # Field name made lowercase. - yesno4 = models.BooleanField(db_column='YesNo4', blank=True, null=True) # Field name made lowercase. - yesno5 = models.BooleanField(db_column='YesNo5', blank=True, null=True) # Field name made lowercase. - uniqueidentifier = models.CharField(db_column='UniqueIdentifier', max_length=128, blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'locality' - unique_together = (('disciplineid', 'uniqueidentifier'),) - - -class Localityattachment(models.Model): - localityattachmentid = models.AutoField(db_column='LocalityAttachmentID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - ordinal = models.IntegerField(db_column='Ordinal') # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - localityid = models.ForeignKey(Locality, models.DO_NOTHING, db_column='LocalityID') # Field name made lowercase. - attachmentid = models.ForeignKey(Attachment, models.DO_NOTHING, db_column='AttachmentID') # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'localityattachment' - - -class Localitycitation(models.Model): - localitycitationid = models.AutoField(db_column='LocalityCitationID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - localityid = models.ForeignKey(Locality, models.DO_NOTHING, db_column='LocalityID') # Field name made lowercase. - referenceworkid = models.ForeignKey('Referencework', models.DO_NOTHING, db_column='ReferenceWorkID') # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - disciplineid = models.ForeignKey(Discipline, models.DO_NOTHING, db_column='DisciplineID') # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - figurenumber = models.CharField(db_column='FigureNumber', max_length=50, blank=True, null=True) # Field name made lowercase. - isfigured = models.BooleanField(db_column='IsFigured', blank=True, null=True) # Field name made lowercase. - pagenumber = models.CharField(db_column='PageNumber', max_length=50, blank=True, null=True) # Field name made lowercase. - platenumber = models.CharField(db_column='PlateNumber', max_length=50, blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'localitycitation' - unique_together = (('referenceworkid', 'localityid'),) - - -class Localitydetail(models.Model): - localitydetailid = models.AutoField(db_column='LocalityDetailID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - basemeridian = models.CharField(db_column='BaseMeridian', max_length=50, blank=True, null=True) # Field name made lowercase. - drainage = models.CharField(db_column='Drainage', max_length=64, blank=True, null=True) # Field name made lowercase. - enddepth = models.DecimalField(db_column='EndDepth', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - enddepthunit = models.CharField(max_length=23, blank=True, null=True) - enddepthverbatim = models.CharField(db_column='EndDepthVerbatim', max_length=32, blank=True, null=True) # Field name made lowercase. - gml = models.TextField(db_column='GML', blank=True, null=True) # Field name made lowercase. - huccode = models.CharField(db_column='HucCode', max_length=16, blank=True, null=True) # Field name made lowercase. - island = models.CharField(db_column='Island', max_length=64, blank=True, null=True) # Field name made lowercase. - islandgroup = models.CharField(db_column='IslandGroup', max_length=64, blank=True, null=True) # Field name made lowercase. - mgrszone = models.CharField(db_column='MgrsZone', max_length=4, blank=True, null=True) # Field name made lowercase. - nationalparkname = models.CharField(db_column='NationalParkName', max_length=64, blank=True, null=True) # Field name made lowercase. - number1 = models.DecimalField(db_column='Number1', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number2 = models.DecimalField(db_column='Number2', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - rangedesc = models.CharField(db_column='RangeDesc', max_length=50, blank=True, null=True) # Field name made lowercase. - rangedirection = models.CharField(db_column='RangeDirection', max_length=50, blank=True, null=True) # Field name made lowercase. - section = models.CharField(db_column='Section', max_length=50, blank=True, null=True) # Field name made lowercase. - sectionpart = models.CharField(db_column='SectionPart', max_length=50, blank=True, null=True) # Field name made lowercase. - startdepth = models.DecimalField(db_column='StartDepth', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - startdepthunit = models.CharField(max_length=23, blank=True, null=True) - startdepthverbatim = models.CharField(db_column='StartDepthVerbatim', max_length=32, blank=True, null=True) # Field name made lowercase. - text1 = models.TextField(db_column='Text1', blank=True, null=True) # Field name made lowercase. - text2 = models.TextField(db_column='Text2', blank=True, null=True) # Field name made lowercase. - township = models.CharField(db_column='Township', max_length=50, blank=True, null=True) # Field name made lowercase. - townshipdirection = models.CharField(db_column='TownshipDirection', max_length=50, blank=True, null=True) # Field name made lowercase. - utmdatum = models.CharField(db_column='UtmDatum', max_length=255, blank=True, null=True) # Field name made lowercase. - utmeasting = models.DecimalField(db_column='UtmEasting', max_digits=19, decimal_places=2, blank=True, null=True) # Field name made lowercase. - utmfalseeasting = models.IntegerField(db_column='UtmFalseEasting', blank=True, null=True) # Field name made lowercase. - utmfalsenorthing = models.IntegerField(db_column='UtmFalseNorthing', blank=True, null=True) # Field name made lowercase. - utmnorthing = models.DecimalField(db_column='UtmNorthing', max_digits=19, decimal_places=2, blank=True, null=True) # Field name made lowercase. - utmoriglatitude = models.DecimalField(db_column='UtmOrigLatitude', max_digits=19, decimal_places=2, blank=True, null=True) # Field name made lowercase. - utmoriglongitude = models.DecimalField(db_column='UtmOrigLongitude', max_digits=19, decimal_places=2, blank=True, null=True) # Field name made lowercase. - utmscale = models.DecimalField(db_column='UtmScale', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - utmzone = models.SmallIntegerField(db_column='UtmZone', blank=True, null=True) # Field name made lowercase. - waterbody = models.CharField(db_column='WaterBody', max_length=64, blank=True, null=True) # Field name made lowercase. - yesno1 = models.BooleanField(db_column='YesNo1', blank=True, null=True) # Field name made lowercase. - yesno2 = models.BooleanField(db_column='YesNo2', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - localityid = models.ForeignKey(Locality, models.DO_NOTHING, db_column='LocalityID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - number3 = models.DecimalField(db_column='Number3', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number4 = models.DecimalField(db_column='Number4', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number5 = models.DecimalField(db_column='Number5', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - paleolat = models.CharField(db_column='PaleoLat', max_length=32, blank=True, null=True) # Field name made lowercase. - paleolng = models.CharField(db_column='PaleoLng', max_length=32, blank=True, null=True) # Field name made lowercase. - text3 = models.TextField(db_column='Text3', blank=True, null=True) # Field name made lowercase. - text4 = models.TextField(db_column='Text4', blank=True, null=True) # Field name made lowercase. - text5 = models.TextField(db_column='Text5', blank=True, null=True) # Field name made lowercase. - yesno3 = models.BooleanField(db_column='YesNo3', blank=True, null=True) # Field name made lowercase. - yesno4 = models.BooleanField(db_column='YesNo4', blank=True, null=True) # Field name made lowercase. - yesno5 = models.BooleanField(db_column='YesNo5', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'localitydetail' - - -class Localitynamealias(models.Model): - localitynamealiasid = models.AutoField(db_column='LocalityNameAliasID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - name = models.CharField(db_column='Name', max_length=255) # Field name made lowercase. - source = models.CharField(db_column='Source', max_length=64) # Field name made lowercase. - localityid = models.ForeignKey(Locality, models.DO_NOTHING, db_column='LocalityID') # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - disciplineid = models.ForeignKey(Discipline, models.DO_NOTHING, db_column='DisciplineID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'localitynamealias' - - -class Localityupdate(models.Model): - taskid = models.CharField(max_length=256) - status = models.CharField(max_length=256) - timestampcreated = models.DateTimeField() - timestampmodified = models.DateTimeField() - localityupdateid = models.AutoField(db_column='LocalityUpdateID', primary_key=True) # Field name made lowercase. - collectionid = models.ForeignKey(Collection, models.DO_NOTHING, db_column='CollectionID') # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - recordsetid = models.ForeignKey('Recordset', models.DO_NOTHING, db_column='RecordSetID', blank=True, null=True) # Field name made lowercase. - specifyuserid = models.ForeignKey('Specifyuser', models.DO_NOTHING, db_column='SpecifyUserID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'localityupdate' - - -class Localityupdaterowresult(models.Model): - localityupdaterowresultid = models.AutoField(db_column='LocalityUpdateRowResultID', primary_key=True) # Field name made lowercase. - rownumber = models.IntegerField() - result = models.JSONField() - localityupdateid = models.ForeignKey(Localityupdate, models.DO_NOTHING, db_column='LocalityUpdateID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'localityupdaterowresult' - - -class Materialsample(models.Model): - materialsampleid = models.AutoField(db_column='MaterialSampleID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - collectionmemberid = models.IntegerField(db_column='CollectionMemberID') # Field name made lowercase. - ggbnabsorbanceratio260_230 = models.DecimalField(db_column='GGBNAbsorbanceRatio260_230', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - ggbnabsorbanceratio260_280 = models.DecimalField(db_column='GGBNAbsorbanceRatio260_280', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - ggbnrabsorbanceratiomethod = models.CharField(db_column='GGBNRAbsorbanceRatioMethod', max_length=64, blank=True, null=True) # Field name made lowercase. - ggbnconcentration = models.DecimalField(db_column='GGBNConcentration', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - ggbnconcentrationunit = models.CharField(db_column='GGBNConcentrationUnit', max_length=64, blank=True, null=True) # Field name made lowercase. - ggbnmaterialsampletype = models.CharField(db_column='GGBNMaterialSampleType', max_length=64, blank=True, null=True) # Field name made lowercase. - ggbnmedium = models.CharField(db_column='GGBNMedium', max_length=64, blank=True, null=True) # Field name made lowercase. - ggbnpurificationmethod = models.CharField(db_column='GGBNPurificationMethod', max_length=64, blank=True, null=True) # Field name made lowercase. - ggbnquality = models.CharField(db_column='GGBNQuality', max_length=64, blank=True, null=True) # Field name made lowercase. - ggbnqualitycheckdate = models.DateField(db_column='GGBNQualityCheckDate', blank=True, null=True) # Field name made lowercase. - ggbnqualityremarks = models.TextField(db_column='GGBNQualityRemarks', blank=True, null=True) # Field name made lowercase. - ggbnsampledesignation = models.CharField(db_column='GGBNSampleDesignation', max_length=128, blank=True, null=True) # Field name made lowercase. - ggbnsamplesize = models.DecimalField(db_column='GGBNSampleSize', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - ggbnvolume = models.DecimalField(db_column='GGBNVolume', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - ggbnvolumeunit = models.CharField(db_column='GGBNVolumeUnit', max_length=64, blank=True, null=True) # Field name made lowercase. - ggbnweight = models.DecimalField(db_column='GGBNWeight', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - ggbnweightmethod = models.CharField(db_column='GGBNWeightMethod', max_length=64, blank=True, null=True) # Field name made lowercase. - ggbnweightunit = models.CharField(db_column='GGBNWeightUnit', max_length=64, blank=True, null=True) # Field name made lowercase. - guid = models.CharField(db_column='GUID', max_length=128, blank=True, null=True) # Field name made lowercase. - integer1 = models.IntegerField(db_column='Integer1', blank=True, null=True) # Field name made lowercase. - integer2 = models.IntegerField(db_column='Integer2', blank=True, null=True) # Field name made lowercase. - number1 = models.DecimalField(db_column='Number1', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number2 = models.DecimalField(db_column='Number2', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - reservedinteger3 = models.IntegerField(db_column='ReservedInteger3', blank=True, null=True) # Field name made lowercase. - reservedinteger4 = models.IntegerField(db_column='ReservedInteger4', blank=True, null=True) # Field name made lowercase. - reservednumber3 = models.DecimalField(db_column='ReservedNumber3', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - reservednumber4 = models.DecimalField(db_column='ReservedNumber4', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - reservedtext3 = models.TextField(db_column='ReservedText3', blank=True, null=True) # Field name made lowercase. - reservedtext4 = models.TextField(db_column='ReservedText4', blank=True, null=True) # Field name made lowercase. - srabioprojectid = models.CharField(db_column='SRABioProjectID', max_length=64, blank=True, null=True) # Field name made lowercase. - srabiosampleid = models.CharField(db_column='SRABioSampleID', max_length=64, blank=True, null=True) # Field name made lowercase. - sraprojectid = models.CharField(db_column='SRAProjectID', max_length=64, blank=True, null=True) # Field name made lowercase. - srasampleid = models.CharField(db_column='SRASampleID', max_length=64, blank=True, null=True) # Field name made lowercase. - text1 = models.TextField(db_column='Text1', blank=True, null=True) # Field name made lowercase. - text2 = models.TextField(db_column='Text2', blank=True, null=True) # Field name made lowercase. - yesno1 = models.BooleanField(db_column='YesNo1', blank=True, null=True) # Field name made lowercase. - yesno2 = models.BooleanField(db_column='YesNo2', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - preparationid = models.ForeignKey('Preparation', models.DO_NOTHING, db_column='PreparationID') # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - extractiondate = models.DateField(db_column='ExtractionDate', blank=True, null=True) # Field name made lowercase. - extractorid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ExtractorID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'materialsample' - - -class Morphbankview(models.Model): - morphbankviewid = models.AutoField(db_column='MorphBankViewID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - developmentstate = models.CharField(db_column='DevelopmentState', max_length=128, blank=True, null=True) # Field name made lowercase. - form = models.CharField(db_column='Form', max_length=128, blank=True, null=True) # Field name made lowercase. - imagingpreparationtechnique = models.CharField(db_column='ImagingPreparationTechnique', max_length=128, blank=True, null=True) # Field name made lowercase. - imagingtechnique = models.CharField(db_column='ImagingTechnique', max_length=128, blank=True, null=True) # Field name made lowercase. - morphbankexternalviewid = models.IntegerField(db_column='MorphBankExternalViewID', blank=True, null=True) # Field name made lowercase. - sex = models.CharField(db_column='Sex', max_length=32, blank=True, null=True) # Field name made lowercase. - specimenpart = models.CharField(db_column='SpecimenPart', max_length=128, blank=True, null=True) # Field name made lowercase. - viewangle = models.CharField(db_column='ViewAngle', max_length=128, blank=True, null=True) # Field name made lowercase. - viewname = models.CharField(db_column='ViewName', max_length=128, blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'morphbankview' - - -class NotificationsMessage(models.Model): - timestampcreated = models.DateTimeField() - content = models.TextField() - user = models.ForeignKey('Specifyuser', models.DO_NOTHING) - read = models.IntegerField() - - class Meta: - managed = False - db_table = 'notifications_message' - - -class Otheridentifier(models.Model): - otheridentifierid = models.AutoField(db_column='OtherIdentifierID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - collectionmemberid = models.IntegerField(db_column='CollectionMemberID') # Field name made lowercase. - identifier = models.CharField(db_column='Identifier', max_length=64) # Field name made lowercase. - institution = models.CharField(db_column='Institution', max_length=64, blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - collectionobjectid = models.ForeignKey(Collectionobject, models.DO_NOTHING, db_column='CollectionObjectID') # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - date1 = models.DateField(db_column='Date1', blank=True, null=True) # Field name made lowercase. - date1precision = models.IntegerField(db_column='Date1Precision', blank=True, null=True) # Field name made lowercase. - date2 = models.DateField(db_column='Date2', blank=True, null=True) # Field name made lowercase. - date2precision = models.IntegerField(db_column='Date2Precision', blank=True, null=True) # Field name made lowercase. - text1 = models.TextField(db_column='Text1', blank=True, null=True) # Field name made lowercase. - text2 = models.TextField(db_column='Text2', blank=True, null=True) # Field name made lowercase. - text3 = models.TextField(db_column='Text3', blank=True, null=True) # Field name made lowercase. - text4 = models.TextField(db_column='Text4', blank=True, null=True) # Field name made lowercase. - text5 = models.TextField(db_column='Text5', blank=True, null=True) # Field name made lowercase. - yesno1 = models.BooleanField(db_column='YesNo1', blank=True, null=True) # Field name made lowercase. - yesno2 = models.BooleanField(db_column='YesNo2', blank=True, null=True) # Field name made lowercase. - yesno3 = models.BooleanField(db_column='YesNo3', blank=True, null=True) # Field name made lowercase. - yesno4 = models.BooleanField(db_column='YesNo4', blank=True, null=True) # Field name made lowercase. - yesno5 = models.BooleanField(db_column='YesNo5', blank=True, null=True) # Field name made lowercase. - agent2id = models.ForeignKey(Agent, models.DO_NOTHING, db_column='Agent2ID', blank=True, null=True) # Field name made lowercase. - agent1id = models.ForeignKey(Agent, models.DO_NOTHING, db_column='Agent1ID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'otheridentifier' - - -class Paleocontext(models.Model): - paleocontextid = models.AutoField(db_column='PaleoContextID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - text1 = models.CharField(db_column='Text1', max_length=64, blank=True, null=True) # Field name made lowercase. - text2 = models.CharField(db_column='Text2', max_length=64, blank=True, null=True) # Field name made lowercase. - yesno1 = models.BooleanField(db_column='YesNo1', blank=True, null=True) # Field name made lowercase. - yesno2 = models.BooleanField(db_column='YesNo2', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - biostratid = models.ForeignKey(Geologictimeperiod, models.DO_NOTHING, db_column='BioStratID', blank=True, null=True) # Field name made lowercase. - chronosstratendid = models.ForeignKey(Geologictimeperiod, models.DO_NOTHING, db_column='ChronosStratEndID', blank=True, null=True) # Field name made lowercase. - lithostratid = models.ForeignKey(Lithostrat, models.DO_NOTHING, db_column='LithoStratID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - chronosstratid = models.ForeignKey(Geologictimeperiod, models.DO_NOTHING, db_column='ChronosStratID', blank=True, null=True) # Field name made lowercase. - number1 = models.DecimalField(db_column='Number1', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number2 = models.DecimalField(db_column='Number2', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number3 = models.DecimalField(db_column='Number3', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number4 = models.DecimalField(db_column='Number4', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number5 = models.DecimalField(db_column='Number5', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - paleocontextname = models.CharField(db_column='PaleoContextName', max_length=80, blank=True, null=True) # Field name made lowercase. - text3 = models.CharField(db_column='Text3', max_length=500, blank=True, null=True) # Field name made lowercase. - text4 = models.CharField(db_column='Text4', max_length=500, blank=True, null=True) # Field name made lowercase. - text5 = models.CharField(db_column='Text5', max_length=500, blank=True, null=True) # Field name made lowercase. - yesno3 = models.BooleanField(db_column='YesNo3', blank=True, null=True) # Field name made lowercase. - yesno4 = models.BooleanField(db_column='YesNo4', blank=True, null=True) # Field name made lowercase. - yesno5 = models.BooleanField(db_column='YesNo5', blank=True, null=True) # Field name made lowercase. - disciplineid = models.ForeignKey(Discipline, models.DO_NOTHING, db_column='DisciplineID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'paleocontext' - - -class Pcrperson(models.Model): - pcrpersonid = models.AutoField(db_column='PcrPersonID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - ordernumber = models.IntegerField(db_column='OrderNumber') # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - text1 = models.TextField(db_column='Text1', blank=True, null=True) # Field name made lowercase. - text2 = models.TextField(db_column='Text2', blank=True, null=True) # Field name made lowercase. - yesno1 = models.BooleanField(db_column='YesNo1', blank=True, null=True) # Field name made lowercase. - yesno2 = models.BooleanField(db_column='YesNo2', blank=True, null=True) # Field name made lowercase. - dnasequenceid = models.ForeignKey(Dnasequence, models.DO_NOTHING, db_column='DNASequenceID') # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - agentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='AgentID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'pcrperson' - unique_together = (('agentid', 'dnasequenceid'),) - - -class Permit(models.Model): - permitid = models.AutoField(db_column='PermitID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - enddate = models.DateField(db_column='EndDate', blank=True, null=True) # Field name made lowercase. - issueddate = models.DateField(db_column='IssuedDate', blank=True, null=True) # Field name made lowercase. - number1 = models.DecimalField(db_column='Number1', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number2 = models.DecimalField(db_column='Number2', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - permitnumber = models.CharField(db_column='PermitNumber', max_length=50) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - renewaldate = models.DateField(db_column='RenewalDate', blank=True, null=True) # Field name made lowercase. - startdate = models.DateField(db_column='StartDate', blank=True, null=True) # Field name made lowercase. - text1 = models.TextField(db_column='Text1', blank=True, null=True) # Field name made lowercase. - text2 = models.TextField(db_column='Text2', blank=True, null=True) # Field name made lowercase. - type = models.CharField(db_column='Type', max_length=50, blank=True, null=True) # Field name made lowercase. - yesno1 = models.BooleanField(db_column='YesNo1', blank=True, null=True) # Field name made lowercase. - yesno2 = models.BooleanField(db_column='YesNo2', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - issuedbyid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='IssuedByID', blank=True, null=True) # Field name made lowercase. - issuedtoid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='IssuedToID', blank=True, null=True) # Field name made lowercase. - institutionid = models.ForeignKey(Institution, models.DO_NOTHING, db_column='InstitutionID') # Field name made lowercase. - copyright = models.CharField(db_column='Copyright', max_length=256, blank=True, null=True) # Field name made lowercase. - isavailable = models.BooleanField(db_column='IsAvailable', blank=True, null=True) # Field name made lowercase. - isrequired = models.BooleanField(db_column='IsRequired', blank=True, null=True) # Field name made lowercase. - permittext = models.TextField(db_column='PermitText', blank=True, null=True) # Field name made lowercase. - reservedinteger1 = models.IntegerField(db_column='ReservedInteger1', blank=True, null=True) # Field name made lowercase. - reservedinteger2 = models.IntegerField(db_column='ReservedInteger2', blank=True, null=True) # Field name made lowercase. - reservedtext3 = models.CharField(db_column='ReservedText3', max_length=128, blank=True, null=True) # Field name made lowercase. - reservedtext4 = models.CharField(db_column='ReservedText4', max_length=128, blank=True, null=True) # Field name made lowercase. - status = models.CharField(db_column='Status', max_length=64, blank=True, null=True) # Field name made lowercase. - statusqualifier = models.CharField(db_column='StatusQualifier', max_length=128, blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'permit' - - -class Permitattachment(models.Model): - permitattachmentid = models.AutoField(db_column='PermitAttachmentID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - ordinal = models.IntegerField(db_column='Ordinal') # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - attachmentid = models.ForeignKey(Attachment, models.DO_NOTHING, db_column='AttachmentID') # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - permitid = models.ForeignKey(Permit, models.DO_NOTHING, db_column='PermitID') # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'permitattachment' - - -class Picklist(models.Model): - picklistid = models.AutoField(db_column='PickListID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - fieldname = models.CharField(db_column='FieldName', max_length=64, blank=True, null=True) # Field name made lowercase. - filterfieldname = models.CharField(db_column='FilterFieldName', max_length=32, blank=True, null=True) # Field name made lowercase. - filtervalue = models.CharField(db_column='FilterValue', max_length=32, blank=True, null=True) # Field name made lowercase. - formatter = models.CharField(db_column='Formatter', max_length=64, blank=True, null=True) # Field name made lowercase. - issystem = models.BooleanField(db_column='IsSystem') # Field name made lowercase. - name = models.CharField(db_column='Name', max_length=64) # Field name made lowercase. - readonly = models.BooleanField(db_column='ReadOnly') # Field name made lowercase. - sizelimit = models.IntegerField(db_column='SizeLimit', blank=True, null=True) # Field name made lowercase. - sorttype = models.IntegerField(db_column='SortType', blank=True, null=True) # Field name made lowercase. - tablename = models.CharField(db_column='TableName', max_length=64, blank=True, null=True) # Field name made lowercase. - type = models.IntegerField(db_column='Type') # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - collectionid = models.ForeignKey(Collection, models.DO_NOTHING, db_column='CollectionID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'picklist' - - -class Picklistitem(models.Model): - picklistitemid = models.AutoField(db_column='PickListItemID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - ordinal = models.IntegerField(db_column='Ordinal', blank=True, null=True) # Field name made lowercase. - title = models.CharField(db_column='Title', max_length=1024) # Field name made lowercase. - value = models.CharField(db_column='Value', max_length=1024, blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - picklistid = models.ForeignKey(Picklist, models.DO_NOTHING, db_column='PickListID') # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'picklistitem' - - -class Preparation(models.Model): - preparationid = models.AutoField(db_column='PreparationID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - collectionmemberid = models.IntegerField(db_column='CollectionMemberID') # Field name made lowercase. - countamt = models.IntegerField(db_column='CountAmt', blank=True, null=True) # Field name made lowercase. - description = models.CharField(db_column='Description', max_length=255, blank=True, null=True) # Field name made lowercase. - number1 = models.DecimalField(db_column='Number1', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number2 = models.DecimalField(db_column='Number2', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - prepareddate = models.DateField(db_column='PreparedDate', blank=True, null=True) # Field name made lowercase. - prepareddateprecision = models.IntegerField(db_column='PreparedDatePrecision', blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - samplenumber = models.CharField(db_column='SampleNumber', max_length=32, blank=True, null=True) # Field name made lowercase. - status = models.CharField(db_column='Status', max_length=32, blank=True, null=True) # Field name made lowercase. - storagelocation = models.CharField(db_column='StorageLocation', max_length=50, blank=True, null=True) # Field name made lowercase. - text1 = models.TextField(db_column='Text1', blank=True, null=True) # Field name made lowercase. - text2 = models.TextField(db_column='Text2', blank=True, null=True) # Field name made lowercase. - yesno1 = models.BooleanField(db_column='YesNo1', blank=True, null=True) # Field name made lowercase. - yesno2 = models.BooleanField(db_column='YesNo2', blank=True, null=True) # Field name made lowercase. - yesno3 = models.BooleanField(db_column='YesNo3', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - preptypeid = models.ForeignKey('Preptype', models.DO_NOTHING, db_column='PrepTypeID') # Field name made lowercase. - collectionobjectid = models.ForeignKey(Collectionobject, models.DO_NOTHING, db_column='CollectionObjectID') # Field name made lowercase. - preparedbyid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='PreparedByID', blank=True, null=True) # Field name made lowercase. - storageid = models.ForeignKey('Storage', models.DO_NOTHING, db_column='StorageID', blank=True, null=True) # Field name made lowercase. - preparationattributeid = models.ForeignKey('Preparationattribute', models.DO_NOTHING, db_column='PreparationAttributeID', blank=True, null=True) # Field name made lowercase. - integer1 = models.IntegerField(db_column='Integer1', blank=True, null=True) # Field name made lowercase. - integer2 = models.IntegerField(db_column='Integer2', blank=True, null=True) # Field name made lowercase. - reservedinteger3 = models.IntegerField(db_column='ReservedInteger3', blank=True, null=True) # Field name made lowercase. - reservedinteger4 = models.IntegerField(db_column='ReservedInteger4', blank=True, null=True) # Field name made lowercase. - guid = models.CharField(db_column='GUID', unique=True, max_length=128, blank=True, null=True) # Field name made lowercase. - text3 = models.TextField(db_column='Text3', blank=True, null=True) # Field name made lowercase. - text4 = models.TextField(db_column='Text4', blank=True, null=True) # Field name made lowercase. - text5 = models.TextField(db_column='Text5', blank=True, null=True) # Field name made lowercase. - date1 = models.DateField(db_column='Date1', blank=True, null=True) # Field name made lowercase. - date1precision = models.IntegerField(db_column='Date1Precision', blank=True, null=True) # Field name made lowercase. - date2 = models.DateField(db_column='Date2', blank=True, null=True) # Field name made lowercase. - date2precision = models.IntegerField(db_column='Date2Precision', blank=True, null=True) # Field name made lowercase. - date3 = models.DateField(db_column='Date3', blank=True, null=True) # Field name made lowercase. - date3precision = models.IntegerField(db_column='Date3Precision', blank=True, null=True) # Field name made lowercase. - date4 = models.DateField(db_column='Date4', blank=True, null=True) # Field name made lowercase. - date4precision = models.IntegerField(db_column='Date4Precision', blank=True, null=True) # Field name made lowercase. - text6 = models.TextField(db_column='Text6', blank=True, null=True) # Field name made lowercase. - text7 = models.TextField(db_column='Text7', blank=True, null=True) # Field name made lowercase. - text8 = models.TextField(db_column='Text8', blank=True, null=True) # Field name made lowercase. - text9 = models.TextField(db_column='Text9', blank=True, null=True) # Field name made lowercase. - alternatestorageid = models.ForeignKey('Storage', models.DO_NOTHING, db_column='AlternateStorageID', blank=True, null=True) # Field name made lowercase. - barcode = models.CharField(db_column='BarCode', max_length=256, blank=True, null=True) # Field name made lowercase. - text10 = models.TextField(db_column='Text10', blank=True, null=True) # Field name made lowercase. - text11 = models.TextField(db_column='Text11', blank=True, null=True) # Field name made lowercase. - text12 = models.CharField(db_column='Text12', max_length=128, blank=True, null=True) # Field name made lowercase. - text13 = models.CharField(db_column='Text13', max_length=128, blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'preparation' - unique_together = (('collectionmemberid', 'barcode'),) - - -class Preparationattachment(models.Model): - preparationattachmentid = models.AutoField(db_column='PreparationAttachmentID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - collectionmemberid = models.IntegerField(db_column='CollectionMemberID') # Field name made lowercase. - ordinal = models.IntegerField(db_column='Ordinal') # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - attachmentid = models.ForeignKey(Attachment, models.DO_NOTHING, db_column='AttachmentID') # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - preparationid = models.ForeignKey(Preparation, models.DO_NOTHING, db_column='PreparationID') # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'preparationattachment' - - -class Preparationattr(models.Model): - attrid = models.AutoField(db_column='AttrID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - collectionmemberid = models.IntegerField(db_column='CollectionMemberID') # Field name made lowercase. - doublevalue = models.FloatField(db_column='DoubleValue', blank=True, null=True) # Field name made lowercase. - strvalue = models.CharField(db_column='StrValue', max_length=255, blank=True, null=True) # Field name made lowercase. - preparationid = models.ForeignKey(Preparation, models.DO_NOTHING, db_column='PreparationId') # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - attributedefid = models.ForeignKey(Attributedef, models.DO_NOTHING, db_column='AttributeDefID') # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'preparationattr' - - -class Preparationattribute(models.Model): - preparationattributeid = models.AutoField(db_column='PreparationAttributeID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - collectionmemberid = models.IntegerField(db_column='CollectionMemberID') # Field name made lowercase. - attrdate = models.DateField(blank=True, null=True) - number1 = models.DecimalField(db_column='Number1', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number2 = models.DecimalField(db_column='Number2', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number3 = models.DecimalField(db_column='Number3', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number4 = models.IntegerField(db_column='Number4', blank=True, null=True) # Field name made lowercase. - number5 = models.IntegerField(db_column='Number5', blank=True, null=True) # Field name made lowercase. - number6 = models.IntegerField(db_column='Number6', blank=True, null=True) # Field name made lowercase. - number7 = models.IntegerField(db_column='Number7', blank=True, null=True) # Field name made lowercase. - number8 = models.IntegerField(db_column='Number8', blank=True, null=True) # Field name made lowercase. - number9 = models.SmallIntegerField(db_column='Number9', blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - text1 = models.TextField(db_column='Text1', blank=True, null=True) # Field name made lowercase. - text10 = models.TextField(db_column='Text10', blank=True, null=True) # Field name made lowercase. - text11 = models.CharField(db_column='Text11', max_length=50, blank=True, null=True) # Field name made lowercase. - text12 = models.CharField(db_column='Text12', max_length=50, blank=True, null=True) # Field name made lowercase. - text13 = models.CharField(db_column='Text13', max_length=50, blank=True, null=True) # Field name made lowercase. - text14 = models.CharField(db_column='Text14', max_length=50, blank=True, null=True) # Field name made lowercase. - text15 = models.CharField(db_column='Text15', max_length=50, blank=True, null=True) # Field name made lowercase. - text16 = models.CharField(db_column='Text16', max_length=50, blank=True, null=True) # Field name made lowercase. - text17 = models.CharField(db_column='Text17', max_length=50, blank=True, null=True) # Field name made lowercase. - text18 = models.CharField(db_column='Text18', max_length=50, blank=True, null=True) # Field name made lowercase. - text19 = models.CharField(db_column='Text19', max_length=50, blank=True, null=True) # Field name made lowercase. - text2 = models.TextField(db_column='Text2', blank=True, null=True) # Field name made lowercase. - text20 = models.CharField(db_column='Text20', max_length=50, blank=True, null=True) # Field name made lowercase. - text21 = models.CharField(db_column='Text21', max_length=50, blank=True, null=True) # Field name made lowercase. - text22 = models.CharField(db_column='Text22', max_length=50, blank=True, null=True) # Field name made lowercase. - text23 = models.CharField(db_column='Text23', max_length=50, blank=True, null=True) # Field name made lowercase. - text24 = models.CharField(db_column='Text24', max_length=50, blank=True, null=True) # Field name made lowercase. - text25 = models.CharField(db_column='Text25', max_length=50, blank=True, null=True) # Field name made lowercase. - text26 = models.CharField(db_column='Text26', max_length=50, blank=True, null=True) # Field name made lowercase. - text3 = models.CharField(db_column='Text3', max_length=50, blank=True, null=True) # Field name made lowercase. - text4 = models.CharField(db_column='Text4', max_length=50, blank=True, null=True) # Field name made lowercase. - text5 = models.CharField(db_column='Text5', max_length=50, blank=True, null=True) # Field name made lowercase. - text6 = models.CharField(db_column='Text6', max_length=50, blank=True, null=True) # Field name made lowercase. - text7 = models.CharField(db_column='Text7', max_length=50, blank=True, null=True) # Field name made lowercase. - text8 = models.CharField(db_column='Text8', max_length=50, blank=True, null=True) # Field name made lowercase. - text9 = models.CharField(db_column='Text9', max_length=50, blank=True, null=True) # Field name made lowercase. - yesno1 = models.BooleanField(db_column='YesNo1', blank=True, null=True) # Field name made lowercase. - yesno2 = models.BooleanField(db_column='YesNo2', blank=True, null=True) # Field name made lowercase. - yesno3 = models.BooleanField(db_column='YesNo3', blank=True, null=True) # Field name made lowercase. - yesno4 = models.BooleanField(db_column='YesNo4', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'preparationattribute' - - -class Preparationproperty(models.Model): - preparationpropertyid = models.AutoField(db_column='PreparationPropertyID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - collectionmemberid = models.IntegerField(db_column='CollectionMemberID') # Field name made lowercase. - date1 = models.DateField(db_column='Date1', blank=True, null=True) # Field name made lowercase. - date10 = models.DateField(db_column='Date10', blank=True, null=True) # Field name made lowercase. - date11 = models.DateField(db_column='Date11', blank=True, null=True) # Field name made lowercase. - date12 = models.DateField(db_column='Date12', blank=True, null=True) # Field name made lowercase. - date13 = models.DateField(db_column='Date13', blank=True, null=True) # Field name made lowercase. - date14 = models.DateField(db_column='Date14', blank=True, null=True) # Field name made lowercase. - date15 = models.DateField(db_column='Date15', blank=True, null=True) # Field name made lowercase. - date16 = models.DateField(db_column='Date16', blank=True, null=True) # Field name made lowercase. - date17 = models.DateField(db_column='Date17', blank=True, null=True) # Field name made lowercase. - date18 = models.DateField(db_column='Date18', blank=True, null=True) # Field name made lowercase. - date19 = models.DateField(db_column='Date19', blank=True, null=True) # Field name made lowercase. - date2 = models.DateField(db_column='Date2', blank=True, null=True) # Field name made lowercase. - date20 = models.DateField(db_column='Date20', blank=True, null=True) # Field name made lowercase. - date3 = models.DateField(db_column='Date3', blank=True, null=True) # Field name made lowercase. - date4 = models.DateField(db_column='Date4', blank=True, null=True) # Field name made lowercase. - date5 = models.DateField(db_column='Date5', blank=True, null=True) # Field name made lowercase. - date6 = models.DateField(db_column='Date6', blank=True, null=True) # Field name made lowercase. - date7 = models.DateField(db_column='Date7', blank=True, null=True) # Field name made lowercase. - date8 = models.DateField(db_column='Date8', blank=True, null=True) # Field name made lowercase. - date9 = models.DateField(db_column='Date9', blank=True, null=True) # Field name made lowercase. - guid = models.CharField(db_column='GUID', max_length=128, blank=True, null=True) # Field name made lowercase. - integer1 = models.SmallIntegerField(db_column='Integer1', blank=True, null=True) # Field name made lowercase. - integer10 = models.SmallIntegerField(db_column='Integer10', blank=True, null=True) # Field name made lowercase. - integer11 = models.SmallIntegerField(db_column='Integer11', blank=True, null=True) # Field name made lowercase. - integer12 = models.SmallIntegerField(db_column='Integer12', blank=True, null=True) # Field name made lowercase. - integer13 = models.SmallIntegerField(db_column='Integer13', blank=True, null=True) # Field name made lowercase. - integer14 = models.SmallIntegerField(db_column='Integer14', blank=True, null=True) # Field name made lowercase. - integer15 = models.SmallIntegerField(db_column='Integer15', blank=True, null=True) # Field name made lowercase. - integer16 = models.SmallIntegerField(db_column='Integer16', blank=True, null=True) # Field name made lowercase. - integer17 = models.SmallIntegerField(db_column='Integer17', blank=True, null=True) # Field name made lowercase. - integer18 = models.SmallIntegerField(db_column='Integer18', blank=True, null=True) # Field name made lowercase. - integer19 = models.SmallIntegerField(db_column='Integer19', blank=True, null=True) # Field name made lowercase. - integer2 = models.SmallIntegerField(db_column='Integer2', blank=True, null=True) # Field name made lowercase. - integer20 = models.SmallIntegerField(db_column='Integer20', blank=True, null=True) # Field name made lowercase. - integer21 = models.IntegerField(db_column='Integer21', blank=True, null=True) # Field name made lowercase. - integer22 = models.IntegerField(db_column='Integer22', blank=True, null=True) # Field name made lowercase. - integer23 = models.IntegerField(db_column='Integer23', blank=True, null=True) # Field name made lowercase. - integer24 = models.IntegerField(db_column='Integer24', blank=True, null=True) # Field name made lowercase. - integer25 = models.IntegerField(db_column='Integer25', blank=True, null=True) # Field name made lowercase. - integer26 = models.IntegerField(db_column='Integer26', blank=True, null=True) # Field name made lowercase. - integer27 = models.IntegerField(db_column='Integer27', blank=True, null=True) # Field name made lowercase. - integer28 = models.IntegerField(db_column='Integer28', blank=True, null=True) # Field name made lowercase. - integer29 = models.IntegerField(db_column='Integer29', blank=True, null=True) # Field name made lowercase. - integer3 = models.SmallIntegerField(db_column='Integer3', blank=True, null=True) # Field name made lowercase. - integer30 = models.IntegerField(db_column='Integer30', blank=True, null=True) # Field name made lowercase. - integer4 = models.SmallIntegerField(db_column='Integer4', blank=True, null=True) # Field name made lowercase. - integer5 = models.SmallIntegerField(db_column='Integer5', blank=True, null=True) # Field name made lowercase. - integer6 = models.SmallIntegerField(db_column='Integer6', blank=True, null=True) # Field name made lowercase. - integer7 = models.SmallIntegerField(db_column='Integer7', blank=True, null=True) # Field name made lowercase. - integer8 = models.SmallIntegerField(db_column='Integer8', blank=True, null=True) # Field name made lowercase. - integer9 = models.SmallIntegerField(db_column='Integer9', blank=True, null=True) # Field name made lowercase. - number1 = models.DecimalField(db_column='Number1', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number10 = models.DecimalField(db_column='Number10', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number11 = models.DecimalField(db_column='Number11', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number12 = models.DecimalField(db_column='Number12', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number13 = models.DecimalField(db_column='Number13', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number14 = models.DecimalField(db_column='Number14', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number15 = models.DecimalField(db_column='Number15', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number16 = models.DecimalField(db_column='Number16', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number17 = models.DecimalField(db_column='Number17', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number18 = models.DecimalField(db_column='Number18', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number19 = models.DecimalField(db_column='Number19', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number2 = models.DecimalField(db_column='Number2', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number20 = models.DecimalField(db_column='Number20', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number21 = models.DecimalField(db_column='Number21', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number22 = models.DecimalField(db_column='Number22', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number23 = models.DecimalField(db_column='Number23', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number24 = models.DecimalField(db_column='Number24', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number25 = models.DecimalField(db_column='Number25', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number26 = models.DecimalField(db_column='Number26', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number27 = models.DecimalField(db_column='Number27', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number28 = models.DecimalField(db_column='Number28', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number29 = models.DecimalField(db_column='Number29', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number3 = models.DecimalField(db_column='Number3', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number30 = models.DecimalField(db_column='Number30', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number4 = models.DecimalField(db_column='Number4', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number5 = models.DecimalField(db_column='Number5', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number6 = models.DecimalField(db_column='Number6', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number7 = models.DecimalField(db_column='Number7', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number8 = models.DecimalField(db_column='Number8', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number9 = models.DecimalField(db_column='Number9', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - text1 = models.CharField(db_column='Text1', max_length=50, blank=True, null=True) # Field name made lowercase. - text10 = models.CharField(db_column='Text10', max_length=50, blank=True, null=True) # Field name made lowercase. - text11 = models.CharField(db_column='Text11', max_length=50, blank=True, null=True) # Field name made lowercase. - text12 = models.CharField(db_column='Text12', max_length=50, blank=True, null=True) # Field name made lowercase. - text13 = models.CharField(db_column='Text13', max_length=50, blank=True, null=True) # Field name made lowercase. - text14 = models.CharField(db_column='Text14', max_length=50, blank=True, null=True) # Field name made lowercase. - text15 = models.CharField(db_column='Text15', max_length=50, blank=True, null=True) # Field name made lowercase. - text16 = models.CharField(db_column='Text16', max_length=100, blank=True, null=True) # Field name made lowercase. - text17 = models.CharField(db_column='Text17', max_length=100, blank=True, null=True) # Field name made lowercase. - text18 = models.CharField(db_column='Text18', max_length=100, blank=True, null=True) # Field name made lowercase. - text19 = models.CharField(db_column='Text19', max_length=100, blank=True, null=True) # Field name made lowercase. - text2 = models.CharField(db_column='Text2', max_length=50, blank=True, null=True) # Field name made lowercase. - text20 = models.CharField(db_column='Text20', max_length=100, blank=True, null=True) # Field name made lowercase. - text21 = models.CharField(db_column='Text21', max_length=100, blank=True, null=True) # Field name made lowercase. - text22 = models.CharField(db_column='Text22', max_length=100, blank=True, null=True) # Field name made lowercase. - text23 = models.CharField(db_column='Text23', max_length=100, blank=True, null=True) # Field name made lowercase. - text24 = models.CharField(db_column='Text24', max_length=100, blank=True, null=True) # Field name made lowercase. - text25 = models.CharField(db_column='Text25', max_length=100, blank=True, null=True) # Field name made lowercase. - text26 = models.CharField(db_column='Text26', max_length=100, blank=True, null=True) # Field name made lowercase. - text27 = models.CharField(db_column='Text27', max_length=100, blank=True, null=True) # Field name made lowercase. - text28 = models.CharField(db_column='Text28', max_length=100, blank=True, null=True) # Field name made lowercase. - text29 = models.CharField(db_column='Text29', max_length=100, blank=True, null=True) # Field name made lowercase. - text3 = models.CharField(db_column='Text3', max_length=50, blank=True, null=True) # Field name made lowercase. - text30 = models.CharField(db_column='Text30', max_length=100, blank=True, null=True) # Field name made lowercase. - text31 = models.TextField(db_column='Text31', blank=True, null=True) # Field name made lowercase. - text32 = models.TextField(db_column='Text32', blank=True, null=True) # Field name made lowercase. - text33 = models.TextField(db_column='Text33', blank=True, null=True) # Field name made lowercase. - text34 = models.TextField(db_column='Text34', blank=True, null=True) # Field name made lowercase. - text35 = models.TextField(db_column='Text35', blank=True, null=True) # Field name made lowercase. - text36 = models.TextField(db_column='Text36', blank=True, null=True) # Field name made lowercase. - text37 = models.TextField(db_column='Text37', blank=True, null=True) # Field name made lowercase. - text38 = models.TextField(db_column='Text38', blank=True, null=True) # Field name made lowercase. - text39 = models.TextField(db_column='Text39', blank=True, null=True) # Field name made lowercase. - text4 = models.CharField(db_column='Text4', max_length=50, blank=True, null=True) # Field name made lowercase. - text40 = models.TextField(db_column='Text40', blank=True, null=True) # Field name made lowercase. - text5 = models.CharField(db_column='Text5', max_length=50, blank=True, null=True) # Field name made lowercase. - text6 = models.CharField(db_column='Text6', max_length=50, blank=True, null=True) # Field name made lowercase. - text7 = models.CharField(db_column='Text7', max_length=50, blank=True, null=True) # Field name made lowercase. - text8 = models.CharField(db_column='Text8', max_length=50, blank=True, null=True) # Field name made lowercase. - text9 = models.CharField(db_column='Text9', max_length=50, blank=True, null=True) # Field name made lowercase. - yesno1 = models.BooleanField(db_column='YesNo1', blank=True, null=True) # Field name made lowercase. - yesno10 = models.BooleanField(db_column='YesNo10', blank=True, null=True) # Field name made lowercase. - yesno11 = models.BooleanField(db_column='YesNo11', blank=True, null=True) # Field name made lowercase. - yesno12 = models.BooleanField(db_column='YesNo12', blank=True, null=True) # Field name made lowercase. - yesno13 = models.BooleanField(db_column='YesNo13', blank=True, null=True) # Field name made lowercase. - yesno14 = models.BooleanField(db_column='YesNo14', blank=True, null=True) # Field name made lowercase. - yesno15 = models.BooleanField(db_column='YesNo15', blank=True, null=True) # Field name made lowercase. - yesno16 = models.BooleanField(db_column='YesNo16', blank=True, null=True) # Field name made lowercase. - yesno17 = models.BooleanField(db_column='YesNo17', blank=True, null=True) # Field name made lowercase. - yesno18 = models.BooleanField(db_column='YesNo18', blank=True, null=True) # Field name made lowercase. - yesno19 = models.BooleanField(db_column='YesNo19', blank=True, null=True) # Field name made lowercase. - yesno2 = models.BooleanField(db_column='YesNo2', blank=True, null=True) # Field name made lowercase. - yesno20 = models.BooleanField(db_column='YesNo20', blank=True, null=True) # Field name made lowercase. - yesno3 = models.BooleanField(db_column='YesNo3', blank=True, null=True) # Field name made lowercase. - yesno4 = models.BooleanField(db_column='YesNo4', blank=True, null=True) # Field name made lowercase. - yesno5 = models.BooleanField(db_column='YesNo5', blank=True, null=True) # Field name made lowercase. - yesno6 = models.BooleanField(db_column='YesNo6', blank=True, null=True) # Field name made lowercase. - yesno7 = models.BooleanField(db_column='YesNo7', blank=True, null=True) # Field name made lowercase. - yesno8 = models.BooleanField(db_column='YesNo8', blank=True, null=True) # Field name made lowercase. - yesno9 = models.BooleanField(db_column='YesNo9', blank=True, null=True) # Field name made lowercase. - agent10id = models.ForeignKey(Agent, models.DO_NOTHING, db_column='Agent10ID', blank=True, null=True) # Field name made lowercase. - agent18id = models.ForeignKey(Agent, models.DO_NOTHING, db_column='Agent18ID', blank=True, null=True) # Field name made lowercase. - agent5id = models.ForeignKey(Agent, models.DO_NOTHING, db_column='Agent5ID', blank=True, null=True) # Field name made lowercase. - agent19id = models.ForeignKey(Agent, models.DO_NOTHING, db_column='Agent19ID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - agent16id = models.ForeignKey(Agent, models.DO_NOTHING, db_column='Agent16ID', blank=True, null=True) # Field name made lowercase. - agent15id = models.ForeignKey(Agent, models.DO_NOTHING, db_column='Agent15ID', blank=True, null=True) # Field name made lowercase. - agent11id = models.ForeignKey(Agent, models.DO_NOTHING, db_column='Agent11ID', blank=True, null=True) # Field name made lowercase. - agent2id = models.ForeignKey(Agent, models.DO_NOTHING, db_column='Agent2ID', blank=True, null=True) # Field name made lowercase. - agent4id = models.ForeignKey(Agent, models.DO_NOTHING, db_column='Agent4ID', blank=True, null=True) # Field name made lowercase. - agent9id = models.ForeignKey(Agent, models.DO_NOTHING, db_column='Agent9ID', blank=True, null=True) # Field name made lowercase. - agent7id = models.ForeignKey(Agent, models.DO_NOTHING, db_column='Agent7ID', blank=True, null=True) # Field name made lowercase. - agent6id = models.ForeignKey(Agent, models.DO_NOTHING, db_column='Agent6ID', blank=True, null=True) # Field name made lowercase. - agent17id = models.ForeignKey(Agent, models.DO_NOTHING, db_column='Agent17ID', blank=True, null=True) # Field name made lowercase. - agent1id = models.ForeignKey(Agent, models.DO_NOTHING, db_column='Agent1ID', blank=True, null=True) # Field name made lowercase. - agent14id = models.ForeignKey(Agent, models.DO_NOTHING, db_column='Agent14ID', blank=True, null=True) # Field name made lowercase. - agent20id = models.ForeignKey(Agent, models.DO_NOTHING, db_column='Agent20ID', blank=True, null=True) # Field name made lowercase. - preparationid = models.ForeignKey(Preparation, models.DO_NOTHING, db_column='PreparationID') # Field name made lowercase. - agent8d = models.ForeignKey(Agent, models.DO_NOTHING, db_column='Agent8D', blank=True, null=True) # Field name made lowercase. - agent13id = models.ForeignKey(Agent, models.DO_NOTHING, db_column='Agent13ID', blank=True, null=True) # Field name made lowercase. - agent3id = models.ForeignKey(Agent, models.DO_NOTHING, db_column='Agent3ID', blank=True, null=True) # Field name made lowercase. - agent12id = models.ForeignKey(Agent, models.DO_NOTHING, db_column='Agent12ID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'preparationproperty' - - -class Preptype(models.Model): - preptypeid = models.AutoField(db_column='PrepTypeID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - isloanable = models.BooleanField(db_column='IsLoanable') # Field name made lowercase. - name = models.CharField(db_column='Name', max_length=64) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - collectionid = models.ForeignKey(Collection, models.DO_NOTHING, db_column='CollectionID') # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'preptype' - - -class Project(models.Model): - projectid = models.AutoField(db_column='ProjectID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - collectionmemberid = models.IntegerField(db_column='CollectionMemberID') # Field name made lowercase. - enddate = models.DateField(db_column='EndDate', blank=True, null=True) # Field name made lowercase. - grantagency = models.CharField(db_column='GrantAgency', max_length=64, blank=True, null=True) # Field name made lowercase. - grantnumber = models.CharField(db_column='GrantNumber', max_length=64, blank=True, null=True) # Field name made lowercase. - number1 = models.DecimalField(db_column='Number1', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number2 = models.DecimalField(db_column='Number2', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - projectdescription = models.CharField(db_column='ProjectDescription', max_length=255, blank=True, null=True) # Field name made lowercase. - projectname = models.CharField(db_column='ProjectName', max_length=128) # Field name made lowercase. - projectnumber = models.CharField(db_column='ProjectNumber', max_length=64, blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - startdate = models.DateField(db_column='StartDate', blank=True, null=True) # Field name made lowercase. - text1 = models.TextField(db_column='Text1', blank=True, null=True) # Field name made lowercase. - text2 = models.TextField(db_column='Text2', blank=True, null=True) # Field name made lowercase. - url = models.TextField(db_column='URL', blank=True, null=True) # Field name made lowercase. - yesno1 = models.BooleanField(db_column='YesNo1', blank=True, null=True) # Field name made lowercase. - yesno2 = models.BooleanField(db_column='YesNo2', blank=True, null=True) # Field name made lowercase. - projectagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ProjectAgentID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'project' - - -class ProjectColobj(models.Model): - projectid = models.OneToOneField(Project, models.DO_NOTHING, db_column='ProjectID', primary_key=True) # Field name made lowercase. - collectionobjectid = models.ForeignKey(Collectionobject, models.DO_NOTHING, db_column='CollectionObjectID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'project_colobj' - unique_together = (('projectid', 'collectionobjectid'),) - - -class Recordset(models.Model): - recordsetid = models.AutoField(db_column='RecordSetID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - collectionmemberid = models.IntegerField(db_column='CollectionMemberID') # Field name made lowercase. - allpermissionlevel = models.IntegerField(db_column='AllPermissionLevel', blank=True, null=True) # Field name made lowercase. - tableid = models.IntegerField(db_column='TableID') # Field name made lowercase. - grouppermissionlevel = models.IntegerField(db_column='GroupPermissionLevel', blank=True, null=True) # Field name made lowercase. - name = models.CharField(db_column='Name', max_length=280) # Field name made lowercase. - ownerpermissionlevel = models.IntegerField(db_column='OwnerPermissionLevel', blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - type = models.IntegerField(db_column='Type') # Field name made lowercase. - specifyuserid = models.ForeignKey('Specifyuser', models.DO_NOTHING, db_column='SpecifyUserID') # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - spprincipalid = models.ForeignKey('Spprincipal', models.DO_NOTHING, db_column='SpPrincipalID', blank=True, null=True) # Field name made lowercase. - inforequestid = models.ForeignKey(Inforequest, models.DO_NOTHING, db_column='InfoRequestID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'recordset' - - -class Recordsetitem(models.Model): - recordsetitemid = models.AutoField(db_column='RecordSetItemID', primary_key=True) # Field name made lowercase. - recordid = models.IntegerField(db_column='RecordId') # Field name made lowercase. - recordsetid = models.ForeignKey(Recordset, models.DO_NOTHING, db_column='RecordSetID') # Field name made lowercase. - ordernumber = models.IntegerField(db_column='OrderNumber', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'recordsetitem' - - -class Referencework(models.Model): - referenceworkid = models.AutoField(db_column='ReferenceWorkID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - guid = models.CharField(db_column='GUID', max_length=128, blank=True, null=True) # Field name made lowercase. - ispublished = models.BooleanField(db_column='IsPublished', blank=True, null=True) # Field name made lowercase. - isbn = models.CharField(db_column='ISBN', max_length=16, blank=True, null=True) # Field name made lowercase. - librarynumber = models.CharField(db_column='LibraryNumber', max_length=50, blank=True, null=True) # Field name made lowercase. - number1 = models.DecimalField(db_column='Number1', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number2 = models.DecimalField(db_column='Number2', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - pages = models.CharField(db_column='Pages', max_length=50, blank=True, null=True) # Field name made lowercase. - placeofpublication = models.CharField(db_column='PlaceOfPublication', max_length=50, blank=True, null=True) # Field name made lowercase. - publisher = models.CharField(db_column='Publisher', max_length=250, blank=True, null=True) # Field name made lowercase. - referenceworktype = models.IntegerField(db_column='ReferenceWorkType') # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - text1 = models.TextField(db_column='Text1', blank=True, null=True) # Field name made lowercase. - text2 = models.TextField(db_column='Text2', blank=True, null=True) # Field name made lowercase. - title = models.CharField(db_column='Title', max_length=400, blank=True, null=True) # Field name made lowercase. - url = models.TextField(db_column='URL', blank=True, null=True) # Field name made lowercase. - volume = models.CharField(db_column='Volume', max_length=25, blank=True, null=True) # Field name made lowercase. - workdate = models.CharField(db_column='WorkDate', max_length=25, blank=True, null=True) # Field name made lowercase. - yesno1 = models.BooleanField(db_column='YesNo1', blank=True, null=True) # Field name made lowercase. - yesno2 = models.BooleanField(db_column='YesNo2', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - containedrfparentid = models.ForeignKey('self', models.DO_NOTHING, db_column='ContainedRFParentID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - journalid = models.ForeignKey(Journal, models.DO_NOTHING, db_column='JournalID', blank=True, null=True) # Field name made lowercase. - institutionid = models.ForeignKey(Institution, models.DO_NOTHING, db_column='InstitutionID') # Field name made lowercase. - doi = models.TextField(db_column='Doi', blank=True, null=True) # Field name made lowercase. - uri = models.TextField(db_column='Uri', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'referencework' - - -class Referenceworkattachment(models.Model): - referenceworkattachmentid = models.AutoField(db_column='ReferenceWorkAttachmentID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - ordinal = models.IntegerField(db_column='Ordinal') # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - attachmentid = models.ForeignKey(Attachment, models.DO_NOTHING, db_column='AttachmentID') # Field name made lowercase. - referenceworkid = models.ForeignKey(Referencework, models.DO_NOTHING, db_column='ReferenceWorkID') # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'referenceworkattachment' - - -class Repositoryagreement(models.Model): - repositoryagreementid = models.AutoField(db_column='RepositoryAgreementID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - datereceived = models.DateField(db_column='DateReceived', blank=True, null=True) # Field name made lowercase. - enddate = models.DateField(db_column='EndDate', blank=True, null=True) # Field name made lowercase. - number1 = models.DecimalField(db_column='Number1', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number2 = models.DecimalField(db_column='Number2', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - repositoryagreementnumber = models.CharField(db_column='RepositoryAgreementNumber', max_length=60) # Field name made lowercase. - startdate = models.DateField(db_column='StartDate', blank=True, null=True) # Field name made lowercase. - status = models.CharField(db_column='Status', max_length=32, blank=True, null=True) # Field name made lowercase. - text1 = models.CharField(db_column='Text1', max_length=255, blank=True, null=True) # Field name made lowercase. - text2 = models.CharField(db_column='Text2', max_length=255, blank=True, null=True) # Field name made lowercase. - text3 = models.CharField(db_column='Text3', max_length=255, blank=True, null=True) # Field name made lowercase. - yesno1 = models.BooleanField(db_column='YesNo1', blank=True, null=True) # Field name made lowercase. - yesno2 = models.BooleanField(db_column='YesNo2', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - addressofrecordid = models.ForeignKey(Addressofrecord, models.DO_NOTHING, db_column='AddressOfRecordID', blank=True, null=True) # Field name made lowercase. - agentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='AgentID') # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - divisionid = models.ForeignKey(Division, models.DO_NOTHING, db_column='DivisionID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'repositoryagreement' - - -class Repositoryagreementattachment(models.Model): - repositoryagreementattachmentid = models.AutoField(db_column='RepositoryAgreementAttachmentID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - ordinal = models.IntegerField(db_column='Ordinal') # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - repositoryagreementid = models.ForeignKey(Repositoryagreement, models.DO_NOTHING, db_column='RepositoryAgreementID') # Field name made lowercase. - attachmentid = models.ForeignKey(Attachment, models.DO_NOTHING, db_column='AttachmentID') # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'repositoryagreementattachment' - - -class Sgrbatchmatchresultitem(models.Model): - id = models.BigAutoField(primary_key=True) - matchedid = models.CharField(db_column='matchedId', max_length=128) # Field name made lowercase. - maxscore = models.FloatField(db_column='maxScore') # Field name made lowercase. - batchmatchresultsetid = models.ForeignKey('Sgrbatchmatchresultset', models.DO_NOTHING, db_column='batchMatchResultSetId') # Field name made lowercase. - qtime = models.IntegerField(db_column='qTime') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'sgrbatchmatchresultitem' - - -class Sgrbatchmatchresultset(models.Model): - id = models.BigAutoField(primary_key=True) - inserttime = models.DateTimeField(db_column='insertTime') # Field name made lowercase. - name = models.CharField(max_length=128) - recordsetid = models.BigIntegerField(db_column='recordSetID', blank=True, null=True) # Field name made lowercase. - matchconfigurationid = models.ForeignKey('Sgrmatchconfiguration', models.DO_NOTHING, db_column='matchConfigurationId') # Field name made lowercase. - query = models.TextField() - remarks = models.TextField() - dbtableid = models.IntegerField(db_column='dbTableId', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'sgrbatchmatchresultset' - - -class Sgrmatchconfiguration(models.Model): - id = models.BigAutoField(primary_key=True) - name = models.CharField(max_length=128) - similarityfields = models.TextField(db_column='similarityFields') # Field name made lowercase. - serverurl = models.TextField(db_column='serverUrl') # Field name made lowercase. - filterquery = models.CharField(db_column='filterQuery', max_length=128) # Field name made lowercase. - queryfields = models.TextField(db_column='queryFields') # Field name made lowercase. - remarks = models.TextField() - boostinterestingterms = models.IntegerField(db_column='boostInterestingTerms') # Field name made lowercase. - nrows = models.IntegerField(db_column='nRows') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'sgrmatchconfiguration' - - -class Shipment(models.Model): - shipmentid = models.AutoField(db_column='ShipmentID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - insuredforamount = models.CharField(db_column='InsuredForAmount', max_length=50, blank=True, null=True) # Field name made lowercase. - number1 = models.DecimalField(db_column='Number1', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number2 = models.DecimalField(db_column='Number2', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - numberofpackages = models.SmallIntegerField(db_column='NumberOfPackages', blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - shipmentdate = models.DateField(db_column='ShipmentDate', blank=True, null=True) # Field name made lowercase. - shipmentmethod = models.CharField(db_column='ShipmentMethod', max_length=50, blank=True, null=True) # Field name made lowercase. - shipmentnumber = models.CharField(db_column='ShipmentNumber', max_length=50) # Field name made lowercase. - text1 = models.TextField(db_column='Text1', blank=True, null=True) # Field name made lowercase. - text2 = models.TextField(db_column='Text2', blank=True, null=True) # Field name made lowercase. - weight = models.CharField(db_column='Weight', max_length=50, blank=True, null=True) # Field name made lowercase. - yesno1 = models.BooleanField(db_column='YesNo1', blank=True, null=True) # Field name made lowercase. - yesno2 = models.BooleanField(db_column='YesNo2', blank=True, null=True) # Field name made lowercase. - shipperid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ShipperID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - borrowid = models.ForeignKey(Borrow, models.DO_NOTHING, db_column='BorrowID', blank=True, null=True) # Field name made lowercase. - giftid = models.ForeignKey(Gift, models.DO_NOTHING, db_column='GiftID', blank=True, null=True) # Field name made lowercase. - shippedtoid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ShippedToID', blank=True, null=True) # Field name made lowercase. - shippedbyid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ShippedByID', blank=True, null=True) # Field name made lowercase. - loanid = models.ForeignKey(Loan, models.DO_NOTHING, db_column='LoanID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - disciplineid = models.ForeignKey(Discipline, models.DO_NOTHING, db_column='DisciplineID') # Field name made lowercase. - exchangeoutid = models.ForeignKey(Exchangeout, models.DO_NOTHING, db_column='ExchangeOutID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'shipment' - - -class SpSchemaMapping(models.Model): - spexportschemamappingid = models.OneToOneField('Spexportschemamapping', models.DO_NOTHING, db_column='SpExportSchemaMappingID', primary_key=True) # Field name made lowercase. - spexportschemaid = models.ForeignKey('Spexportschema', models.DO_NOTHING, db_column='SpExportSchemaID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'sp_schema_mapping' - unique_together = (('spexportschemamappingid', 'spexportschemaid'),) - - -class Spappresource(models.Model): - spappresourceid = models.AutoField(db_column='SpAppResourceID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - allpermissionlevel = models.IntegerField(db_column='AllPermissionLevel', blank=True, null=True) # Field name made lowercase. - description = models.CharField(db_column='Description', max_length=255, blank=True, null=True) # Field name made lowercase. - grouppermissionlevel = models.IntegerField(db_column='GroupPermissionLevel', blank=True, null=True) # Field name made lowercase. - level = models.SmallIntegerField(db_column='Level') # Field name made lowercase. - metadata = models.CharField(db_column='MetaData', max_length=255, blank=True, null=True) # Field name made lowercase. - mimetype = models.CharField(db_column='MimeType', max_length=255, blank=True, null=True) # Field name made lowercase. - name = models.CharField(db_column='Name', max_length=64) # Field name made lowercase. - ownerpermissionlevel = models.IntegerField(db_column='OwnerPermissionLevel', blank=True, null=True) # Field name made lowercase. - specifyuserid = models.ForeignKey('Specifyuser', models.DO_NOTHING, db_column='SpecifyUserID') # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - spprincipalid = models.ForeignKey('Spprincipal', models.DO_NOTHING, db_column='SpPrincipalID', blank=True, null=True) # Field name made lowercase. - spappresourcedirid = models.ForeignKey('Spappresourcedir', models.DO_NOTHING, db_column='SpAppResourceDirID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'spappresource' - - -class Spappresourcedata(models.Model): - spappresourcedataid = models.AutoField(db_column='SpAppResourceDataID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - data = models.TextField(blank=True, null=True) - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - spappresourceid = models.ForeignKey(Spappresource, models.DO_NOTHING, db_column='SpAppResourceID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - spviewsetobjid = models.ForeignKey('Spviewsetobj', models.DO_NOTHING, db_column='SpViewSetObjID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'spappresourcedata' - - -class Spappresourcedir(models.Model): - spappresourcedirid = models.AutoField(db_column='SpAppResourceDirID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - disciplinetype = models.CharField(db_column='DisciplineType', max_length=64, blank=True, null=True) # Field name made lowercase. - ispersonal = models.BooleanField(db_column='IsPersonal') # Field name made lowercase. - usertype = models.CharField(db_column='UserType', max_length=64, blank=True, null=True) # Field name made lowercase. - disciplineid = models.ForeignKey(Discipline, models.DO_NOTHING, db_column='DisciplineID', blank=True, null=True) # Field name made lowercase. - collectionid = models.ForeignKey(Collection, models.DO_NOTHING, db_column='CollectionID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - specifyuserid = models.ForeignKey('Specifyuser', models.DO_NOTHING, db_column='SpecifyUserID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'spappresourcedir' - - -class Spauditlog(models.Model): - spauditlogid = models.AutoField(db_column='SpAuditLogID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - action = models.IntegerField(db_column='Action') # Field name made lowercase. - parentrecordid = models.IntegerField(db_column='ParentRecordId', blank=True, null=True) # Field name made lowercase. - parenttablenum = models.SmallIntegerField(db_column='ParentTableNum', blank=True, null=True) # Field name made lowercase. - recordid = models.IntegerField(db_column='RecordId', blank=True, null=True) # Field name made lowercase. - recordversion = models.IntegerField(db_column='RecordVersion') # Field name made lowercase. - tablenum = models.SmallIntegerField(db_column='TableNum') # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'spauditlog' - - -class Spauditlogfield(models.Model): - spauditlogfieldid = models.AutoField(db_column='SpAuditLogFieldID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - fieldname = models.CharField(db_column='FieldName', max_length=128, blank=True, null=True) # Field name made lowercase. - newvalue = models.TextField(db_column='NewValue', blank=True, null=True) # Field name made lowercase. - oldvalue = models.TextField(db_column='OldValue', blank=True, null=True) # Field name made lowercase. - spauditlogid = models.ForeignKey(Spauditlog, models.DO_NOTHING, db_column='SpAuditLogID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'spauditlogfield' - - -class Spdataset(models.Model): - name = models.CharField(max_length=256) - columns = models.JSONField() - data = models.JSONField() - uploadplan = models.TextField(blank=True, null=True) - uploaderstatus = models.JSONField(blank=True, null=True) - uploadresult = models.JSONField(blank=True, null=True) - rowresults = models.TextField(blank=True, null=True) - collection = models.ForeignKey(Collection, models.DO_NOTHING) - specifyuser = models.ForeignKey('Specifyuser', models.DO_NOTHING) - visualorder = models.JSONField(blank=True, null=True) - importedfilename = models.TextField(blank=True, null=True) - remarks = models.TextField(blank=True, null=True) - timestampcreated = models.DateTimeField() - timestampmodified = models.DateTimeField() - createdbyagent = models.ForeignKey(Agent, models.DO_NOTHING, blank=True, null=True) - modifiedbyagent = models.ForeignKey(Agent, models.DO_NOTHING, blank=True, null=True) - - class Meta: - managed = False - db_table = 'spdataset' - - -class Specifyuser(models.Model): - specifyuserid = models.AutoField(db_column='SpecifyUserID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - accumminloggedin = models.BigIntegerField(db_column='AccumMinLoggedIn', blank=True, null=True) # Field name made lowercase. - email = models.CharField(db_column='EMail', max_length=64, blank=True, null=True) # Field name made lowercase. - isloggedin = models.BooleanField(db_column='IsLoggedIn') # Field name made lowercase. - isloggedinreport = models.BooleanField(db_column='IsLoggedInReport') # Field name made lowercase. - logincollectionname = models.CharField(db_column='LoginCollectionName', max_length=64, blank=True, null=True) # Field name made lowercase. - logindisciplinename = models.CharField(db_column='LoginDisciplineName', max_length=64, blank=True, null=True) # Field name made lowercase. - loginouttime = models.DateTimeField(db_column='LoginOutTime', blank=True, null=True) # Field name made lowercase. - name = models.CharField(db_column='Name', unique=True, max_length=64) # Field name made lowercase. - password = models.CharField(db_column='Password', max_length=255) # Field name made lowercase. - usertype = models.CharField(db_column='UserType', max_length=32, blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'specifyuser' - - -class SpecifyuserSpprincipal(models.Model): - specifyuserid = models.OneToOneField(Specifyuser, models.DO_NOTHING, db_column='SpecifyUserID', primary_key=True) # Field name made lowercase. - spprincipalid = models.ForeignKey('Spprincipal', models.DO_NOTHING, db_column='SpPrincipalID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'specifyuser_spprincipal' - unique_together = (('specifyuserid', 'spprincipalid'),) - - -class Spexportschema(models.Model): - spexportschemaid = models.AutoField(db_column='SpExportSchemaID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - description = models.CharField(db_column='Description', max_length=255, blank=True, null=True) # Field name made lowercase. - schemaname = models.CharField(db_column='SchemaName', max_length=80, blank=True, null=True) # Field name made lowercase. - schemaversion = models.CharField(db_column='SchemaVersion', max_length=80, blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - disciplineid = models.ForeignKey(Discipline, models.DO_NOTHING, db_column='DisciplineID') # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'spexportschema' - - -class Spexportschemaitem(models.Model): - spexportschemaitemid = models.AutoField(db_column='SpExportSchemaItemID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - datatype = models.CharField(db_column='DataType', max_length=32, blank=True, null=True) # Field name made lowercase. - description = models.CharField(db_column='Description', max_length=255, blank=True, null=True) # Field name made lowercase. - fieldname = models.CharField(db_column='FieldName', max_length=64, blank=True, null=True) # Field name made lowercase. - formatter = models.CharField(db_column='Formatter', max_length=32, blank=True, null=True) # Field name made lowercase. - splocalecontaineritemid = models.ForeignKey('Splocalecontaineritem', models.DO_NOTHING, db_column='SpLocaleContainerItemID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - spexportschemaid = models.ForeignKey(Spexportschema, models.DO_NOTHING, db_column='SpExportSchemaID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'spexportschemaitem' - - -class Spexportschemaitemmapping(models.Model): - spexportschemaitemmappingid = models.AutoField(db_column='SpExportSchemaItemMappingID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - remarks = models.CharField(db_column='Remarks', max_length=255, blank=True, null=True) # Field name made lowercase. - spqueryfieldid = models.ForeignKey('Spqueryfield', models.DO_NOTHING, db_column='SpQueryFieldID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - exportschemaitemid = models.ForeignKey(Spexportschemaitem, models.DO_NOTHING, db_column='ExportSchemaItemID', blank=True, null=True) # Field name made lowercase. - spexportschemamappingid = models.ForeignKey('Spexportschemamapping', models.DO_NOTHING, db_column='SpExportSchemaMappingID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - exportedfieldname = models.CharField(db_column='ExportedFieldName', max_length=64, blank=True, null=True) # Field name made lowercase. - extensionitem = models.BooleanField(db_column='ExtensionItem', blank=True, null=True) # Field name made lowercase. - rowtype = models.CharField(db_column='RowType', max_length=500, blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'spexportschemaitemmapping' - - -class Spexportschemamapping(models.Model): - spexportschemamappingid = models.AutoField(db_column='SpExportSchemaMappingID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - collectionmemberid = models.IntegerField(db_column='CollectionMemberID') # Field name made lowercase. - description = models.CharField(db_column='Description', max_length=255, blank=True, null=True) # Field name made lowercase. - mappingname = models.CharField(db_column='MappingName', max_length=50, blank=True, null=True) # Field name made lowercase. - timestampexported = models.DateTimeField(db_column='TimeStampExported', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'spexportschemamapping' - - -class Spfieldvaluedefault(models.Model): - spfieldvaluedefaultid = models.AutoField(db_column='SpFieldValueDefaultID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - collectionmemberid = models.IntegerField(db_column='CollectionMemberID') # Field name made lowercase. - fieldname = models.CharField(db_column='FieldName', max_length=32, blank=True, null=True) # Field name made lowercase. - idvalue = models.IntegerField(db_column='IdValue', blank=True, null=True) # Field name made lowercase. - strvalue = models.CharField(db_column='StrValue', max_length=64, blank=True, null=True) # Field name made lowercase. - tablename = models.CharField(db_column='TableName', max_length=32, blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'spfieldvaluedefault' - - -class Splibraryrole(models.Model): - name = models.CharField(max_length=1024) - description = models.TextField() - - class Meta: - managed = False - db_table = 'splibraryrole' - - -class Splibraryrolepolicy(models.Model): - resource = models.CharField(max_length=1024) - action = models.CharField(max_length=1024) - role = models.ForeignKey(Splibraryrole, models.DO_NOTHING) - - class Meta: - managed = False - db_table = 'splibraryrolepolicy' - - -class Splocalecontainer(models.Model): - splocalecontainerid = models.AutoField(db_column='SpLocaleContainerID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - format = models.CharField(db_column='Format', max_length=64, blank=True, null=True) # Field name made lowercase. - ishidden = models.BooleanField(db_column='IsHidden') # Field name made lowercase. - issystem = models.BooleanField(db_column='IsSystem') # Field name made lowercase. - isuiformatter = models.BooleanField(db_column='IsUIFormatter', blank=True, null=True) # Field name made lowercase. - name = models.CharField(db_column='Name', max_length=64) # Field name made lowercase. - picklistname = models.CharField(db_column='PickListName', max_length=64, blank=True, null=True) # Field name made lowercase. - type = models.CharField(db_column='Type', max_length=32, blank=True, null=True) # Field name made lowercase. - aggregator = models.CharField(db_column='Aggregator', max_length=64, blank=True, null=True) # Field name made lowercase. - defaultui = models.CharField(db_column='DefaultUI', max_length=64, blank=True, null=True) # Field name made lowercase. - schematype = models.IntegerField(db_column='SchemaType') # Field name made lowercase. - disciplineid = models.ForeignKey(Discipline, models.DO_NOTHING, db_column='DisciplineID') # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'splocalecontainer' - - -class Splocalecontaineritem(models.Model): - splocalecontaineritemid = models.AutoField(db_column='SpLocaleContainerItemID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - format = models.CharField(db_column='Format', max_length=64, blank=True, null=True) # Field name made lowercase. - ishidden = models.BooleanField(db_column='IsHidden') # Field name made lowercase. - issystem = models.BooleanField(db_column='IsSystem') # Field name made lowercase. - isuiformatter = models.BooleanField(db_column='IsUIFormatter', blank=True, null=True) # Field name made lowercase. - name = models.CharField(db_column='Name', max_length=64) # Field name made lowercase. - picklistname = models.CharField(db_column='PickListName', max_length=64, blank=True, null=True) # Field name made lowercase. - type = models.CharField(db_column='Type', max_length=32, blank=True, null=True) # Field name made lowercase. - isrequired = models.BooleanField(db_column='IsRequired', blank=True, null=True) # Field name made lowercase. - weblinkname = models.CharField(db_column='WebLinkName', max_length=32, blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - splocalecontainerid = models.ForeignKey(Splocalecontainer, models.DO_NOTHING, db_column='SpLocaleContainerID') # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'splocalecontaineritem' - - -class Splocaleitemstr(models.Model): - splocaleitemstrid = models.AutoField(db_column='SpLocaleItemStrID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - country = models.CharField(db_column='Country', max_length=2, blank=True, null=True) # Field name made lowercase. - language = models.CharField(db_column='Language', max_length=2) # Field name made lowercase. - text = models.CharField(db_column='Text', max_length=2048) # Field name made lowercase. - variant = models.CharField(db_column='Variant', max_length=2, blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - splocalecontaineritemdescid = models.ForeignKey(Splocalecontaineritem, models.DO_NOTHING, db_column='SpLocaleContainerItemDescID', blank=True, null=True) # Field name made lowercase. - splocalecontaineritemnameid = models.ForeignKey(Splocalecontaineritem, models.DO_NOTHING, db_column='SpLocaleContainerItemNameID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - splocalecontainernameid = models.ForeignKey(Splocalecontainer, models.DO_NOTHING, db_column='SpLocaleContainerNameID', blank=True, null=True) # Field name made lowercase. - splocalecontainerdescid = models.ForeignKey(Splocalecontainer, models.DO_NOTHING, db_column='SpLocaleContainerDescID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'splocaleitemstr' - - -class Spmerging(models.Model): - name = models.CharField(max_length=256) - taskid = models.CharField(max_length=256) - status = models.CharField(max_length=256) - response = models.TextField() - table = models.CharField(max_length=256) - newrecordid = models.IntegerField(blank=True, null=True) - newrecordata = models.JSONField(blank=True, null=True) - oldrecordids = models.JSONField(blank=True, null=True) - collectionid = models.ForeignKey(Collection, models.DO_NOTHING, db_column='CollectionID') # Field name made lowercase. - specifyuserid = models.ForeignKey(Specifyuser, models.DO_NOTHING, db_column='SpecifyUserID') # Field name made lowercase. - timestampcreated = models.DateTimeField() - timestampmodified = models.DateTimeField() - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'spmerging' - - -class Sppermission(models.Model): - sppermissionid = models.AutoField(db_column='SpPermissionID', primary_key=True) # Field name made lowercase. - actions = models.TextField(db_column='Actions', blank=True, null=True) # Field name made lowercase. - name = models.CharField(db_column='Name', max_length=64, blank=True, null=True) # Field name made lowercase. - permissionclass = models.TextField(db_column='PermissionClass') # Field name made lowercase. - targetid = models.IntegerField(db_column='TargetId', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'sppermission' - - -class Spprincipal(models.Model): - spprincipalid = models.AutoField(db_column='SpPrincipalID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - groupsubclass = models.CharField(db_column='GroupSubClass', max_length=255) # Field name made lowercase. - grouptype = models.CharField(db_column='groupType', max_length=32, blank=True, null=True) # Field name made lowercase. - name = models.CharField(db_column='Name', max_length=64) # Field name made lowercase. - priority = models.IntegerField(db_column='Priority') # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - usergroupscopeid = models.IntegerField(db_column='userGroupScopeID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'spprincipal' - - -class SpprincipalSppermission(models.Model): - sppermissionid = models.OneToOneField(Sppermission, models.DO_NOTHING, db_column='SpPermissionID', primary_key=True) # Field name made lowercase. - spprincipalid = models.ForeignKey(Spprincipal, models.DO_NOTHING, db_column='SpPrincipalID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'spprincipal_sppermission' - unique_together = (('sppermissionid', 'spprincipalid'),) - - -class Spquery(models.Model): - spqueryid = models.AutoField(db_column='SpQueryID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - contextname = models.CharField(db_column='ContextName', max_length=64) # Field name made lowercase. - contexttableid = models.SmallIntegerField(db_column='ContextTableId') # Field name made lowercase. - countonly = models.BooleanField(db_column='CountOnly', blank=True, null=True) # Field name made lowercase. - isfavorite = models.BooleanField(db_column='IsFavorite', blank=True, null=True) # Field name made lowercase. - name = models.CharField(db_column='Name', max_length=256) # Field name made lowercase. - ordinal = models.SmallIntegerField(db_column='Ordinal', blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - searchsynonymy = models.BooleanField(db_column='SearchSynonymy', blank=True, null=True) # Field name made lowercase. - selectdistinct = models.BooleanField(db_column='SelectDistinct', blank=True, null=True) # Field name made lowercase. - selectseries = models.BooleanField(db_column='SelectSeries', blank=True, null=True) - sqlstr = models.TextField(db_column='SqlStr', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - specifyuserid = models.ForeignKey(Specifyuser, models.DO_NOTHING, db_column='SpecifyUserID') # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - smushed = models.BooleanField(db_column='Smushed', blank=True, null=True) # Field name made lowercase. - formatauditrecids = models.BooleanField(db_column='FormatAuditRecIds', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'spquery' - - -class Spqueryfield(models.Model): - spqueryfieldid = models.AutoField(db_column='SpQueryFieldID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - allownulls = models.BooleanField(db_column='AllowNulls', blank=True, null=True) # Field name made lowercase. - alwaysfilter = models.BooleanField(db_column='AlwaysFilter', blank=True, null=True) # Field name made lowercase. - columnalias = models.CharField(db_column='ColumnAlias', max_length=64, blank=True, null=True) # Field name made lowercase. - contexttableident = models.IntegerField(db_column='ContextTableIdent', blank=True, null=True) # Field name made lowercase. - endvalue = models.TextField(db_column='EndValue', blank=True, null=True) # Field name made lowercase. - fieldname = models.CharField(db_column='FieldName', max_length=32) # Field name made lowercase. - formatname = models.CharField(db_column='FormatName', max_length=64, blank=True, null=True) # Field name made lowercase. - isdisplay = models.BooleanField(db_column='IsDisplay') # Field name made lowercase. - isnot = models.BooleanField(db_column='IsNot') # Field name made lowercase. - isprompt = models.BooleanField(db_column='IsPrompt', blank=True, null=True) # Field name made lowercase. - isrelfld = models.BooleanField(db_column='IsRelFld', blank=True, null=True) # Field name made lowercase. - operend = models.IntegerField(db_column='OperEnd', blank=True, null=True) # Field name made lowercase. - operstart = models.IntegerField(db_column='OperStart') # Field name made lowercase. - position = models.SmallIntegerField(db_column='Position') # Field name made lowercase. - sorttype = models.IntegerField(db_column='SortType') # Field name made lowercase. - startvalue = models.TextField(db_column='StartValue', blank=True, null=True) # Field name made lowercase. - stringid = models.TextField(db_column='StringId') # Field name made lowercase. - tablelist = models.TextField(db_column='TableList') # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - spqueryid = models.ForeignKey(Spquery, models.DO_NOTHING, db_column='SpQueryID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'spqueryfield' - - -class Spreport(models.Model): - spreportid = models.AutoField(db_column='SpReportId', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - name = models.CharField(db_column='Name', max_length=64) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - repeatcount = models.IntegerField(db_column='RepeatCount', blank=True, null=True) # Field name made lowercase. - repeatfield = models.CharField(db_column='RepeatField', max_length=255, blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - spqueryid = models.ForeignKey(Spquery, models.DO_NOTHING, db_column='SpQueryID', blank=True, null=True) # Field name made lowercase. - specifyuserid = models.ForeignKey(Specifyuser, models.DO_NOTHING, db_column='SpecifyUserID') # Field name made lowercase. - appresourceid = models.ForeignKey(Spappresource, models.DO_NOTHING, db_column='AppResourceID') # Field name made lowercase. - workbenchtemplateid = models.ForeignKey('Workbenchtemplate', models.DO_NOTHING, db_column='WorkbenchTemplateID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'spreport' - - -class Sprole(models.Model): - name = models.CharField(max_length=1024) - collection = models.ForeignKey(Collection, models.DO_NOTHING) - description = models.TextField() - - class Meta: - managed = False - db_table = 'sprole' - - -class Sprolepolicy(models.Model): - resource = models.CharField(max_length=1024) - action = models.CharField(max_length=1024) - role = models.ForeignKey(Sprole, models.DO_NOTHING) - - class Meta: - managed = False - db_table = 'sprolepolicy' - - -class Spstynthy(models.Model): - spstynthyid = models.AutoField(db_column='SpStynthyID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - metaxml = models.TextField(db_column='MetaXML', blank=True, null=True) # Field name made lowercase. - updateperioddays = models.IntegerField(db_column='UpdatePeriodDays') # Field name made lowercase. - lastexported = models.DateTimeField(db_column='LastExported', blank=True, null=True) # Field name made lowercase. - collectionid = models.IntegerField(db_column='CollectionID') # Field name made lowercase. - mappingxml = models.TextField(db_column='MappingXML', blank=True, null=True) # Field name made lowercase. - key1 = models.CharField(db_column='Key1', max_length=256, blank=True, null=True) # Field name made lowercase. - key2 = models.CharField(db_column='Key2', max_length=256, blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'spstynthy' - - -class Spsymbiotainstance(models.Model): - spsymbiotainstanceid = models.AutoField(db_column='SpSymbiotaInstanceID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - collectionmemberid = models.IntegerField(db_column='CollectionMemberID') # Field name made lowercase. - description = models.CharField(db_column='Description', max_length=256, blank=True, null=True) # Field name made lowercase. - instancename = models.CharField(db_column='InstanceName', max_length=256, blank=True, null=True) # Field name made lowercase. - lastcachebuild = models.DateTimeField(db_column='LastCacheBuild', blank=True, null=True) # Field name made lowercase. - lastpull = models.DateTimeField(db_column='LastPull', blank=True, null=True) # Field name made lowercase. - lastpush = models.DateTimeField(db_column='LastPush', blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - symbiotakey = models.CharField(db_column='SymbiotaKey', max_length=128, blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - schemamappingid = models.ForeignKey(Spexportschemamapping, models.DO_NOTHING, db_column='SchemaMappingID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'spsymbiotainstance' - - -class Sptasksemaphore(models.Model): - tasksemaphoreid = models.AutoField(db_column='TaskSemaphoreID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - context = models.CharField(db_column='Context', max_length=32, blank=True, null=True) # Field name made lowercase. - islocked = models.BooleanField(db_column='IsLocked', blank=True, null=True) # Field name made lowercase. - lockedtime = models.DateTimeField(db_column='LockedTime', blank=True, null=True) # Field name made lowercase. - machinename = models.CharField(db_column='MachineName', max_length=64, blank=True, null=True) # Field name made lowercase. - scope = models.IntegerField(db_column='Scope', blank=True, null=True) # Field name made lowercase. - taskname = models.CharField(db_column='TaskName', max_length=32, blank=True, null=True) # Field name made lowercase. - usagecount = models.IntegerField(db_column='UsageCount', blank=True, null=True) # Field name made lowercase. - ownerid = models.ForeignKey(Specifyuser, models.DO_NOTHING, db_column='OwnerID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - collectionid = models.ForeignKey(Collection, models.DO_NOTHING, db_column='CollectionID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - disciplineid = models.ForeignKey(Discipline, models.DO_NOTHING, db_column='DisciplineID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'sptasksemaphore' - - -class Spuserexternalid(models.Model): - provider = models.CharField(max_length=256) - providerid = models.CharField(max_length=4095) - specifyuser = models.ForeignKey(Specifyuser, models.DO_NOTHING) - enabled = models.IntegerField() - idtoken = models.JSONField(blank=True, null=True) - - class Meta: - managed = False - db_table = 'spuserexternalid' - - -class Spuserpolicy(models.Model): - resource = models.CharField(max_length=1024) - action = models.CharField(max_length=1024) - collection = models.ForeignKey(Collection, models.DO_NOTHING, blank=True, null=True) - specifyuser = models.ForeignKey(Specifyuser, models.DO_NOTHING, blank=True, null=True) - - class Meta: - managed = False - db_table = 'spuserpolicy' - - -class Spuserrole(models.Model): - role = models.ForeignKey(Sprole, models.DO_NOTHING) - specifyuser = models.ForeignKey(Specifyuser, models.DO_NOTHING) - - class Meta: - managed = False - db_table = 'spuserrole' - - -class Spversion(models.Model): - spversionid = models.AutoField(db_column='SpVersionID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - appname = models.CharField(db_column='AppName', max_length=32, blank=True, null=True) # Field name made lowercase. - appversion = models.CharField(db_column='AppVersion', max_length=16, blank=True, null=True) # Field name made lowercase. - dbclosedby = models.CharField(db_column='DbClosedBy', max_length=32, blank=True, null=True) # Field name made lowercase. - isdbclosed = models.BooleanField(db_column='IsDBClosed', blank=True, null=True) # Field name made lowercase. - schemaversion = models.CharField(db_column='SchemaVersion', max_length=16, blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - workbenchschemaversion = models.CharField(db_column='WorkbenchSchemaVersion', max_length=16, blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'spversion' - - -class Spviewsetobj(models.Model): - spviewsetobjid = models.AutoField(db_column='SpViewSetObjID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - description = models.CharField(db_column='Description', max_length=255, blank=True, null=True) # Field name made lowercase. - filename = models.CharField(db_column='FileName', max_length=255, blank=True, null=True) # Field name made lowercase. - level = models.SmallIntegerField(db_column='Level') # Field name made lowercase. - metadata = models.CharField(db_column='MetaData', max_length=255, blank=True, null=True) # Field name made lowercase. - name = models.CharField(db_column='Name', max_length=64) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - spappresourcedirid = models.ForeignKey(Spappresourcedir, models.DO_NOTHING, db_column='SpAppResourceDirID') # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'spviewsetobj' - - -class Spvisualquery(models.Model): - spvisualqueryid = models.AutoField(db_column='SpVisualQueryID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - description = models.TextField(db_column='Description', blank=True, null=True) # Field name made lowercase. - name = models.CharField(db_column='Name', max_length=64) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - specifyuserid = models.ForeignKey(Specifyuser, models.DO_NOTHING, db_column='SpecifyUserID') # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'spvisualquery' - - -class Storage(models.Model): - storageid = models.AutoField(db_column='StorageID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - abbrev = models.CharField(db_column='Abbrev', max_length=16, blank=True, null=True) # Field name made lowercase. - fullname = models.CharField(db_column='FullName', max_length=255, blank=True, null=True) # Field name made lowercase. - highestchildnodenumber = models.IntegerField(db_column='HighestChildNodeNumber', blank=True, null=True) # Field name made lowercase. - isaccepted = models.BooleanField(db_column='IsAccepted', blank=True, null=True) # Field name made lowercase. - name = models.CharField(db_column='Name', max_length=64) # Field name made lowercase. - nodenumber = models.IntegerField(db_column='NodeNumber', blank=True, null=True) # Field name made lowercase. - number1 = models.IntegerField(db_column='Number1', blank=True, null=True) # Field name made lowercase. - number2 = models.IntegerField(db_column='Number2', blank=True, null=True) # Field name made lowercase. - rankid = models.IntegerField(db_column='RankID') # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - text1 = models.CharField(db_column='Text1', max_length=32, blank=True, null=True) # Field name made lowercase. - text2 = models.CharField(db_column='Text2', max_length=32, blank=True, null=True) # Field name made lowercase. - timestampversion = models.DateTimeField(db_column='TimestampVersion', blank=True, null=True) # Field name made lowercase. - storagetreedefitemid = models.ForeignKey('Storagetreedefitem', models.DO_NOTHING, db_column='StorageTreeDefItemID') # Field name made lowercase. - storagetreedefid = models.ForeignKey('Storagetreedef', models.DO_NOTHING, db_column='StorageTreeDefID') # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - acceptedid = models.ForeignKey('self', models.DO_NOTHING, db_column='AcceptedID', blank=True, null=True) # Field name made lowercase. - parentid = models.ForeignKey('self', models.DO_NOTHING, db_column='ParentID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'storage' - - -class Storageattachment(models.Model): - storageattachmentid = models.AutoField(db_column='StorageAttachmentID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - ordinal = models.IntegerField(db_column='Ordinal') # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - storageid = models.ForeignKey(Storage, models.DO_NOTHING, db_column='StorageID') # Field name made lowercase. - attachmentid = models.ForeignKey(Attachment, models.DO_NOTHING, db_column='AttachmentID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'storageattachment' - - -class Storagetreedef(models.Model): - storagetreedefid = models.AutoField(db_column='StorageTreeDefID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - fullnamedirection = models.IntegerField(db_column='FullNameDirection', blank=True, null=True) # Field name made lowercase. - name = models.CharField(db_column='Name', max_length=64) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'storagetreedef' - - -class Storagetreedefitem(models.Model): - storagetreedefitemid = models.AutoField(db_column='StorageTreeDefItemID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - fullnameseparator = models.CharField(db_column='FullNameSeparator', max_length=32, blank=True, null=True) # Field name made lowercase. - isenforced = models.BooleanField(db_column='IsEnforced', blank=True, null=True) # Field name made lowercase. - isinfullname = models.BooleanField(db_column='IsInFullName', blank=True, null=True) # Field name made lowercase. - name = models.CharField(db_column='Name', max_length=64) # Field name made lowercase. - rankid = models.IntegerField(db_column='RankID') # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - textafter = models.CharField(db_column='TextAfter', max_length=64, blank=True, null=True) # Field name made lowercase. - textbefore = models.CharField(db_column='TextBefore', max_length=64, blank=True, null=True) # Field name made lowercase. - title = models.CharField(db_column='Title', max_length=64, blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - storagetreedefid = models.ForeignKey(Storagetreedef, models.DO_NOTHING, db_column='StorageTreeDefID') # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - parentitemid = models.ForeignKey('self', models.DO_NOTHING, db_column='ParentItemID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'storagetreedefitem' - - -class Taxon(models.Model): - taxonid = models.AutoField(db_column='TaxonID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - author = models.CharField(db_column='Author', max_length=128, blank=True, null=True) # Field name made lowercase. - citesstatus = models.CharField(db_column='CitesStatus', max_length=32, blank=True, null=True) # Field name made lowercase. - colstatus = models.CharField(db_column='COLStatus', max_length=32, blank=True, null=True) # Field name made lowercase. - commonname = models.CharField(db_column='CommonName', max_length=128, blank=True, null=True) # Field name made lowercase. - cultivarname = models.CharField(db_column='CultivarName', max_length=32, blank=True, null=True) # Field name made lowercase. - environmentalprotectionstatus = models.CharField(db_column='EnvironmentalProtectionStatus', max_length=64, blank=True, null=True) # Field name made lowercase. - esastatus = models.CharField(db_column='EsaStatus', max_length=64, blank=True, null=True) # Field name made lowercase. - fullname = models.CharField(db_column='FullName', max_length=512, blank=True, null=True) # Field name made lowercase. - groupnumber = models.CharField(db_column='GroupNumber', max_length=20, blank=True, null=True) # Field name made lowercase. - guid = models.CharField(db_column='GUID', max_length=128, blank=True, null=True) # Field name made lowercase. - highestchildnodenumber = models.IntegerField(db_column='HighestChildNodeNumber', blank=True, null=True) # Field name made lowercase. - isaccepted = models.BooleanField(db_column='IsAccepted', blank=True, null=True) # Field name made lowercase. - ishybrid = models.BooleanField(db_column='IsHybrid', blank=True, null=True) # Field name made lowercase. - isisnumber = models.CharField(db_column='IsisNumber', max_length=16, blank=True, null=True) # Field name made lowercase. - labelformat = models.CharField(db_column='LabelFormat', max_length=64, blank=True, null=True) # Field name made lowercase. - name = models.CharField(db_column='Name', max_length=256) # Field name made lowercase. - ncbitaxonnumber = models.CharField(db_column='NcbiTaxonNumber', max_length=8, blank=True, null=True) # Field name made lowercase. - nodenumber = models.IntegerField(db_column='NodeNumber', blank=True, null=True) # Field name made lowercase. - number1 = models.IntegerField(db_column='Number1', blank=True, null=True) # Field name made lowercase. - number2 = models.IntegerField(db_column='Number2', blank=True, null=True) # Field name made lowercase. - rankid = models.IntegerField(db_column='RankID') # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - source = models.CharField(db_column='Source', max_length=64, blank=True, null=True) # Field name made lowercase. - taxonomicserialnumber = models.CharField(db_column='TaxonomicSerialNumber', max_length=50, blank=True, null=True) # Field name made lowercase. - text1 = models.CharField(db_column='Text1', max_length=32, blank=True, null=True) # Field name made lowercase. - text2 = models.CharField(db_column='Text2', max_length=32, blank=True, null=True) # Field name made lowercase. - unitind1 = models.CharField(db_column='UnitInd1', max_length=50, blank=True, null=True) # Field name made lowercase. - unitind2 = models.CharField(db_column='UnitInd2', max_length=50, blank=True, null=True) # Field name made lowercase. - unitind3 = models.CharField(db_column='UnitInd3', max_length=50, blank=True, null=True) # Field name made lowercase. - unitind4 = models.CharField(db_column='UnitInd4', max_length=50, blank=True, null=True) # Field name made lowercase. - unitname1 = models.CharField(db_column='UnitName1', max_length=50, blank=True, null=True) # Field name made lowercase. - unitname2 = models.CharField(db_column='UnitName2', max_length=50, blank=True, null=True) # Field name made lowercase. - unitname3 = models.CharField(db_column='UnitName3', max_length=50, blank=True, null=True) # Field name made lowercase. - unitname4 = models.CharField(db_column='UnitName4', max_length=50, blank=True, null=True) # Field name made lowercase. - usfwscode = models.CharField(db_column='UsfwsCode', max_length=16, blank=True, null=True) # Field name made lowercase. - visibility = models.IntegerField(db_column='Visibility', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - visibilitysetbyid = models.ForeignKey(Specifyuser, models.DO_NOTHING, db_column='VisibilitySetByID', blank=True, null=True) # Field name made lowercase. - hybridparent2id = models.ForeignKey('self', models.DO_NOTHING, db_column='HybridParent2ID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - taxontreedefitemid = models.ForeignKey('Taxontreedefitem', models.DO_NOTHING, db_column='TaxonTreeDefItemID') # Field name made lowercase. - acceptedid = models.ForeignKey('self', models.DO_NOTHING, db_column='AcceptedID', blank=True, null=True) # Field name made lowercase. - parentid = models.ForeignKey('self', models.DO_NOTHING, db_column='ParentID', blank=True, null=True) # Field name made lowercase. - taxontreedefid = models.ForeignKey('Taxontreedef', models.DO_NOTHING, db_column='TaxonTreeDefID') # Field name made lowercase. - hybridparent1id = models.ForeignKey('self', models.DO_NOTHING, db_column='HybridParent1ID', blank=True, null=True) # Field name made lowercase. - number3 = models.DecimalField(db_column='Number3', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number4 = models.DecimalField(db_column='Number4', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number5 = models.DecimalField(db_column='Number5', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - text3 = models.TextField(db_column='Text3', blank=True, null=True) # Field name made lowercase. - text4 = models.TextField(db_column='Text4', blank=True, null=True) # Field name made lowercase. - text5 = models.TextField(db_column='Text5', blank=True, null=True) # Field name made lowercase. - yesno1 = models.BooleanField(db_column='YesNo1', blank=True, null=True) # Field name made lowercase. - yesno2 = models.BooleanField(db_column='YesNo2', blank=True, null=True) # Field name made lowercase. - yesno3 = models.BooleanField(db_column='YesNo3', blank=True, null=True) # Field name made lowercase. - integer1 = models.BigIntegerField(db_column='Integer1', blank=True, null=True) # Field name made lowercase. - integer2 = models.BigIntegerField(db_column='Integer2', blank=True, null=True) # Field name made lowercase. - integer3 = models.BigIntegerField(db_column='Integer3', blank=True, null=True) # Field name made lowercase. - integer4 = models.IntegerField(db_column='Integer4', blank=True, null=True) # Field name made lowercase. - integer5 = models.IntegerField(db_column='Integer5', blank=True, null=True) # Field name made lowercase. - text10 = models.CharField(db_column='Text10', max_length=128, blank=True, null=True) # Field name made lowercase. - text11 = models.CharField(db_column='Text11', max_length=128, blank=True, null=True) # Field name made lowercase. - text12 = models.CharField(db_column='Text12', max_length=128, blank=True, null=True) # Field name made lowercase. - text13 = models.CharField(db_column='Text13', max_length=128, blank=True, null=True) # Field name made lowercase. - text14 = models.CharField(db_column='Text14', max_length=256, blank=True, null=True) # Field name made lowercase. - text15 = models.CharField(db_column='Text15', max_length=256, blank=True, null=True) # Field name made lowercase. - text16 = models.CharField(db_column='Text16', max_length=256, blank=True, null=True) # Field name made lowercase. - text17 = models.CharField(db_column='Text17', max_length=256, blank=True, null=True) # Field name made lowercase. - text18 = models.CharField(db_column='Text18', max_length=256, blank=True, null=True) # Field name made lowercase. - text19 = models.CharField(db_column='Text19', max_length=256, blank=True, null=True) # Field name made lowercase. - text20 = models.CharField(db_column='Text20', max_length=256, blank=True, null=True) # Field name made lowercase. - text6 = models.TextField(db_column='Text6', blank=True, null=True) # Field name made lowercase. - text7 = models.TextField(db_column='Text7', blank=True, null=True) # Field name made lowercase. - text8 = models.TextField(db_column='Text8', blank=True, null=True) # Field name made lowercase. - text9 = models.TextField(db_column='Text9', blank=True, null=True) # Field name made lowercase. - yesno10 = models.BooleanField(db_column='YesNo10', blank=True, null=True) # Field name made lowercase. - yesno11 = models.BooleanField(db_column='YesNo11', blank=True, null=True) # Field name made lowercase. - yesno12 = models.BooleanField(db_column='YesNo12', blank=True, null=True) # Field name made lowercase. - yesno13 = models.BooleanField(db_column='YesNo13', blank=True, null=True) # Field name made lowercase. - yesno14 = models.BooleanField(db_column='YesNo14', blank=True, null=True) # Field name made lowercase. - yesno15 = models.BooleanField(db_column='YesNo15', blank=True, null=True) # Field name made lowercase. - yesno16 = models.BooleanField(db_column='YesNo16', blank=True, null=True) # Field name made lowercase. - yesno17 = models.BooleanField(db_column='YesNo17', blank=True, null=True) # Field name made lowercase. - yesno18 = models.BooleanField(db_column='YesNo18', blank=True, null=True) # Field name made lowercase. - yesno19 = models.BooleanField(db_column='YesNo19', blank=True, null=True) # Field name made lowercase. - yesno4 = models.BooleanField(db_column='YesNo4', blank=True, null=True) # Field name made lowercase. - yesno5 = models.BooleanField(db_column='YesNo5', blank=True, null=True) # Field name made lowercase. - yesno6 = models.BooleanField(db_column='YesNo6', blank=True, null=True) # Field name made lowercase. - yesno7 = models.BooleanField(db_column='YesNo7', blank=True, null=True) # Field name made lowercase. - yesno8 = models.BooleanField(db_column='YesNo8', blank=True, null=True) # Field name made lowercase. - yesno9 = models.BooleanField(db_column='YesNo9', blank=True, null=True) # Field name made lowercase. - lsid = models.TextField(db_column='LSID', blank=True, null=True) # Field name made lowercase. - taxonattributeid = models.ForeignKey('Taxonattribute', models.DO_NOTHING, db_column='TaxonAttributeID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'taxon' - - -class Taxonattachment(models.Model): - taxonattachmentid = models.AutoField(db_column='TaxonAttachmentID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - ordinal = models.IntegerField(db_column='Ordinal') # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - attachmentid = models.ForeignKey(Attachment, models.DO_NOTHING, db_column='AttachmentID') # Field name made lowercase. - taxonid = models.ForeignKey(Taxon, models.DO_NOTHING, db_column='TaxonID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'taxonattachment' - - -class Taxonattribute(models.Model): - taxonattributeid = models.AutoField(db_column='TaxonAttributeID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - date1 = models.DateField(db_column='Date1', blank=True, null=True) # Field name made lowercase. - date1precision = models.IntegerField(db_column='Date1Precision', blank=True, null=True) # Field name made lowercase. - number1 = models.DecimalField(db_column='Number1', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number10 = models.DecimalField(db_column='Number10', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number11 = models.DecimalField(db_column='Number11', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number12 = models.DecimalField(db_column='Number12', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number13 = models.DecimalField(db_column='Number13', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number14 = models.DecimalField(db_column='Number14', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number15 = models.DecimalField(db_column='Number15', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number16 = models.DecimalField(db_column='Number16', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number17 = models.DecimalField(db_column='Number17', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number18 = models.DecimalField(db_column='Number18', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number19 = models.DecimalField(db_column='Number19', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number2 = models.DecimalField(db_column='Number2', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number20 = models.DecimalField(db_column='Number20', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number3 = models.DecimalField(db_column='Number3', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number4 = models.DecimalField(db_column='Number4', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number5 = models.DecimalField(db_column='Number5', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number6 = models.DecimalField(db_column='Number6', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number7 = models.DecimalField(db_column='Number7', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number8 = models.DecimalField(db_column='Number8', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number9 = models.DecimalField(db_column='Number9', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - text1 = models.CharField(db_column='Text1', max_length=128, blank=True, null=True) # Field name made lowercase. - text10 = models.CharField(db_column='Text10', max_length=128, blank=True, null=True) # Field name made lowercase. - text11 = models.CharField(db_column='Text11', max_length=128, blank=True, null=True) # Field name made lowercase. - text12 = models.CharField(db_column='Text12', max_length=128, blank=True, null=True) # Field name made lowercase. - text13 = models.CharField(db_column='Text13', max_length=128, blank=True, null=True) # Field name made lowercase. - text14 = models.CharField(db_column='Text14', max_length=128, blank=True, null=True) # Field name made lowercase. - text15 = models.CharField(db_column='Text15', max_length=128, blank=True, null=True) # Field name made lowercase. - text16 = models.CharField(db_column='Text16', max_length=128, blank=True, null=True) # Field name made lowercase. - text17 = models.CharField(db_column='Text17', max_length=128, blank=True, null=True) # Field name made lowercase. - text18 = models.CharField(db_column='Text18', max_length=128, blank=True, null=True) # Field name made lowercase. - text19 = models.CharField(db_column='Text19', max_length=128, blank=True, null=True) # Field name made lowercase. - text2 = models.CharField(db_column='Text2', max_length=128, blank=True, null=True) # Field name made lowercase. - text20 = models.CharField(db_column='Text20', max_length=128, blank=True, null=True) # Field name made lowercase. - text21 = models.CharField(db_column='Text21', max_length=128, blank=True, null=True) # Field name made lowercase. - text22 = models.CharField(db_column='Text22', max_length=128, blank=True, null=True) # Field name made lowercase. - text23 = models.CharField(db_column='Text23', max_length=128, blank=True, null=True) # Field name made lowercase. - text24 = models.CharField(db_column='Text24', max_length=128, blank=True, null=True) # Field name made lowercase. - text25 = models.CharField(db_column='Text25', max_length=128, blank=True, null=True) # Field name made lowercase. - text26 = models.CharField(db_column='Text26', max_length=128, blank=True, null=True) # Field name made lowercase. - text27 = models.CharField(db_column='Text27', max_length=256, blank=True, null=True) # Field name made lowercase. - text28 = models.CharField(db_column='Text28', max_length=256, blank=True, null=True) # Field name made lowercase. - text29 = models.CharField(db_column='Text29', max_length=256, blank=True, null=True) # Field name made lowercase. - text3 = models.CharField(db_column='Text3', max_length=128, blank=True, null=True) # Field name made lowercase. - text30 = models.CharField(db_column='Text30', max_length=256, blank=True, null=True) # Field name made lowercase. - text31 = models.CharField(db_column='Text31', max_length=256, blank=True, null=True) # Field name made lowercase. - text32 = models.CharField(db_column='Text32', max_length=256, blank=True, null=True) # Field name made lowercase. - text33 = models.CharField(db_column='Text33', max_length=256, blank=True, null=True) # Field name made lowercase. - text34 = models.CharField(db_column='Text34', max_length=256, blank=True, null=True) # Field name made lowercase. - text35 = models.CharField(db_column='Text35', max_length=256, blank=True, null=True) # Field name made lowercase. - text36 = models.CharField(db_column='Text36', max_length=256, blank=True, null=True) # Field name made lowercase. - text37 = models.CharField(db_column='Text37', max_length=256, blank=True, null=True) # Field name made lowercase. - text38 = models.CharField(db_column='Text38', max_length=256, blank=True, null=True) # Field name made lowercase. - text39 = models.CharField(db_column='Text39', max_length=256, blank=True, null=True) # Field name made lowercase. - text4 = models.CharField(db_column='Text4', max_length=128, blank=True, null=True) # Field name made lowercase. - text40 = models.CharField(db_column='Text40', max_length=256, blank=True, null=True) # Field name made lowercase. - text41 = models.CharField(db_column='Text41', max_length=256, blank=True, null=True) # Field name made lowercase. - text42 = models.CharField(db_column='Text42', max_length=256, blank=True, null=True) # Field name made lowercase. - text43 = models.CharField(db_column='Text43', max_length=256, blank=True, null=True) # Field name made lowercase. - text44 = models.CharField(db_column='Text44', max_length=256, blank=True, null=True) # Field name made lowercase. - text45 = models.CharField(db_column='Text45', max_length=256, blank=True, null=True) # Field name made lowercase. - text46 = models.CharField(db_column='Text46', max_length=256, blank=True, null=True) # Field name made lowercase. - text47 = models.CharField(db_column='Text47', max_length=256, blank=True, null=True) # Field name made lowercase. - text48 = models.CharField(db_column='Text48', max_length=256, blank=True, null=True) # Field name made lowercase. - text49 = models.TextField(db_column='Text49', blank=True, null=True) # Field name made lowercase. - text5 = models.CharField(db_column='Text5', max_length=128, blank=True, null=True) # Field name made lowercase. - text50 = models.TextField(db_column='Text50', blank=True, null=True) # Field name made lowercase. - text51 = models.TextField(db_column='Text51', blank=True, null=True) # Field name made lowercase. - text52 = models.TextField(db_column='Text52', blank=True, null=True) # Field name made lowercase. - text53 = models.TextField(db_column='Text53', blank=True, null=True) # Field name made lowercase. - text54 = models.TextField(db_column='Text54', blank=True, null=True) # Field name made lowercase. - text55 = models.TextField(db_column='Text55', blank=True, null=True) # Field name made lowercase. - text56 = models.TextField(db_column='Text56', blank=True, null=True) # Field name made lowercase. - text57 = models.TextField(db_column='Text57', blank=True, null=True) # Field name made lowercase. - text58 = models.TextField(db_column='Text58', blank=True, null=True) # Field name made lowercase. - text6 = models.CharField(db_column='Text6', max_length=128, blank=True, null=True) # Field name made lowercase. - text7 = models.CharField(db_column='Text7', max_length=128, blank=True, null=True) # Field name made lowercase. - text8 = models.CharField(db_column='Text8', max_length=128, blank=True, null=True) # Field name made lowercase. - text9 = models.CharField(db_column='Text9', max_length=128, blank=True, null=True) # Field name made lowercase. - yesno1 = models.BooleanField(db_column='YesNo1', blank=True, null=True) # Field name made lowercase. - yesno10 = models.BooleanField(db_column='YesNo10', blank=True, null=True) # Field name made lowercase. - yesno11 = models.BooleanField(db_column='YesNo11', blank=True, null=True) # Field name made lowercase. - yesno12 = models.BooleanField(db_column='YesNo12', blank=True, null=True) # Field name made lowercase. - yesno13 = models.BooleanField(db_column='YesNo13', blank=True, null=True) # Field name made lowercase. - yesno14 = models.BooleanField(db_column='YesNo14', blank=True, null=True) # Field name made lowercase. - yesno15 = models.BooleanField(db_column='YesNo15', blank=True, null=True) # Field name made lowercase. - yesno16 = models.BooleanField(db_column='YesNo16', blank=True, null=True) # Field name made lowercase. - yesno17 = models.BooleanField(db_column='YesNo17', blank=True, null=True) # Field name made lowercase. - yesno18 = models.BooleanField(db_column='YesNo18', blank=True, null=True) # Field name made lowercase. - yesno19 = models.BooleanField(db_column='YesNo19', blank=True, null=True) # Field name made lowercase. - yesno2 = models.BooleanField(db_column='YesNo2', blank=True, null=True) # Field name made lowercase. - yesno20 = models.BooleanField(db_column='YesNo20', blank=True, null=True) # Field name made lowercase. - yesno21 = models.BooleanField(db_column='YesNo21', blank=True, null=True) # Field name made lowercase. - yesno22 = models.BooleanField(db_column='YesNo22', blank=True, null=True) # Field name made lowercase. - yesno23 = models.BooleanField(db_column='YesNo23', blank=True, null=True) # Field name made lowercase. - yesno24 = models.BooleanField(db_column='YesNo24', blank=True, null=True) # Field name made lowercase. - yesno25 = models.BooleanField(db_column='YesNo25', blank=True, null=True) # Field name made lowercase. - yesno26 = models.BooleanField(db_column='YesNo26', blank=True, null=True) # Field name made lowercase. - yesno27 = models.BooleanField(db_column='YesNo27', blank=True, null=True) # Field name made lowercase. - yesno28 = models.BooleanField(db_column='YesNo28', blank=True, null=True) # Field name made lowercase. - yesno29 = models.BooleanField(db_column='YesNo29', blank=True, null=True) # Field name made lowercase. - yesno3 = models.BooleanField(db_column='YesNo3', blank=True, null=True) # Field name made lowercase. - yesno30 = models.BooleanField(db_column='YesNo30', blank=True, null=True) # Field name made lowercase. - yesno31 = models.BooleanField(db_column='YesNo31', blank=True, null=True) # Field name made lowercase. - yesno32 = models.BooleanField(db_column='YesNo32', blank=True, null=True) # Field name made lowercase. - yesno33 = models.BooleanField(db_column='YesNo33', blank=True, null=True) # Field name made lowercase. - yesno34 = models.BooleanField(db_column='YesNo34', blank=True, null=True) # Field name made lowercase. - yesno35 = models.BooleanField(db_column='YesNo35', blank=True, null=True) # Field name made lowercase. - yesno36 = models.BooleanField(db_column='YesNo36', blank=True, null=True) # Field name made lowercase. - yesno37 = models.BooleanField(db_column='YesNo37', blank=True, null=True) # Field name made lowercase. - yesno38 = models.BooleanField(db_column='YesNo38', blank=True, null=True) # Field name made lowercase. - yesno39 = models.BooleanField(db_column='YesNo39', blank=True, null=True) # Field name made lowercase. - yesno4 = models.BooleanField(db_column='YesNo4', blank=True, null=True) # Field name made lowercase. - yesno40 = models.BooleanField(db_column='YesNo40', blank=True, null=True) # Field name made lowercase. - yesno41 = models.BooleanField(db_column='YesNo41', blank=True, null=True) # Field name made lowercase. - yesno42 = models.BooleanField(db_column='YesNo42', blank=True, null=True) # Field name made lowercase. - yesno43 = models.BooleanField(db_column='YesNo43', blank=True, null=True) # Field name made lowercase. - yesno44 = models.BooleanField(db_column='YesNo44', blank=True, null=True) # Field name made lowercase. - yesno45 = models.BooleanField(db_column='YesNo45', blank=True, null=True) # Field name made lowercase. - yesno46 = models.BooleanField(db_column='YesNo46', blank=True, null=True) # Field name made lowercase. - yesno47 = models.BooleanField(db_column='YesNo47', blank=True, null=True) # Field name made lowercase. - yesno48 = models.BooleanField(db_column='YesNo48', blank=True, null=True) # Field name made lowercase. - yesno49 = models.BooleanField(db_column='YesNo49', blank=True, null=True) # Field name made lowercase. - yesno5 = models.BooleanField(db_column='YesNo5', blank=True, null=True) # Field name made lowercase. - yesno50 = models.BooleanField(db_column='YesNo50', blank=True, null=True) # Field name made lowercase. - yesno51 = models.BooleanField(db_column='YesNo51', blank=True, null=True) # Field name made lowercase. - yesno52 = models.BooleanField(db_column='YesNo52', blank=True, null=True) # Field name made lowercase. - yesno53 = models.BooleanField(db_column='YesNo53', blank=True, null=True) # Field name made lowercase. - yesno54 = models.BooleanField(db_column='YesNo54', blank=True, null=True) # Field name made lowercase. - yesno55 = models.BooleanField(db_column='YesNo55', blank=True, null=True) # Field name made lowercase. - yesno56 = models.BooleanField(db_column='YesNo56', blank=True, null=True) # Field name made lowercase. - yesno57 = models.BooleanField(db_column='YesNo57', blank=True, null=True) # Field name made lowercase. - yesno58 = models.BooleanField(db_column='YesNo58', blank=True, null=True) # Field name made lowercase. - yesno59 = models.BooleanField(db_column='YesNo59', blank=True, null=True) # Field name made lowercase. - yesno6 = models.BooleanField(db_column='YesNo6', blank=True, null=True) # Field name made lowercase. - yesno60 = models.BooleanField(db_column='YesNo60', blank=True, null=True) # Field name made lowercase. - yesno61 = models.BooleanField(db_column='YesNo61', blank=True, null=True) # Field name made lowercase. - yesno62 = models.BooleanField(db_column='YesNo62', blank=True, null=True) # Field name made lowercase. - yesno63 = models.BooleanField(db_column='YesNo63', blank=True, null=True) # Field name made lowercase. - yesno64 = models.BooleanField(db_column='YesNo64', blank=True, null=True) # Field name made lowercase. - yesno65 = models.BooleanField(db_column='YesNo65', blank=True, null=True) # Field name made lowercase. - yesno66 = models.BooleanField(db_column='YesNo66', blank=True, null=True) # Field name made lowercase. - yesno67 = models.BooleanField(db_column='YesNo67', blank=True, null=True) # Field name made lowercase. - yesno68 = models.BooleanField(db_column='YesNo68', blank=True, null=True) # Field name made lowercase. - yesno69 = models.BooleanField(db_column='YesNo69', blank=True, null=True) # Field name made lowercase. - yesno7 = models.BooleanField(db_column='YesNo7', blank=True, null=True) # Field name made lowercase. - yesno70 = models.BooleanField(db_column='YesNo70', blank=True, null=True) # Field name made lowercase. - yesno71 = models.BooleanField(db_column='YesNo71', blank=True, null=True) # Field name made lowercase. - yesno72 = models.BooleanField(db_column='YesNo72', blank=True, null=True) # Field name made lowercase. - yesno73 = models.BooleanField(db_column='YesNo73', blank=True, null=True) # Field name made lowercase. - yesno74 = models.BooleanField(db_column='YesNo74', blank=True, null=True) # Field name made lowercase. - yesno75 = models.BooleanField(db_column='YesNo75', blank=True, null=True) # Field name made lowercase. - yesno76 = models.BooleanField(db_column='YesNo76', blank=True, null=True) # Field name made lowercase. - yesno77 = models.BooleanField(db_column='YesNo77', blank=True, null=True) # Field name made lowercase. - yesno78 = models.BooleanField(db_column='YesNo78', blank=True, null=True) # Field name made lowercase. - yesno79 = models.BooleanField(db_column='YesNo79', blank=True, null=True) # Field name made lowercase. - yesno8 = models.BooleanField(db_column='YesNo8', blank=True, null=True) # Field name made lowercase. - yesno80 = models.BooleanField(db_column='YesNo80', blank=True, null=True) # Field name made lowercase. - yesno81 = models.BooleanField(db_column='YesNo81', blank=True, null=True) # Field name made lowercase. - yesno82 = models.BooleanField(db_column='YesNo82', blank=True, null=True) # Field name made lowercase. - yesno9 = models.BooleanField(db_column='YesNo9', blank=True, null=True) # Field name made lowercase. - agent1id = models.ForeignKey(Agent, models.DO_NOTHING, db_column='Agent1ID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'taxonattribute' - - -class Taxoncitation(models.Model): - taxoncitationid = models.AutoField(db_column='TaxonCitationID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - number1 = models.DecimalField(db_column='Number1', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number2 = models.DecimalField(db_column='Number2', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - text1 = models.TextField(db_column='Text1', blank=True, null=True) # Field name made lowercase. - text2 = models.TextField(db_column='Text2', blank=True, null=True) # Field name made lowercase. - yesno1 = models.BooleanField(db_column='YesNo1', blank=True, null=True) # Field name made lowercase. - yesno2 = models.BooleanField(db_column='YesNo2', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - referenceworkid = models.ForeignKey(Referencework, models.DO_NOTHING, db_column='ReferenceWorkID') # Field name made lowercase. - taxonid = models.ForeignKey(Taxon, models.DO_NOTHING, db_column='TaxonID') # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - figurenumber = models.CharField(db_column='FigureNumber', max_length=50, blank=True, null=True) # Field name made lowercase. - isfigured = models.BooleanField(db_column='IsFigured', blank=True, null=True) # Field name made lowercase. - pagenumber = models.CharField(db_column='PageNumber', max_length=50, blank=True, null=True) # Field name made lowercase. - platenumber = models.CharField(db_column='PlateNumber', max_length=50, blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'taxoncitation' - - -class Taxontreedef(models.Model): - taxontreedefid = models.AutoField(db_column='TaxonTreeDefID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - fullnamedirection = models.IntegerField(db_column='FullNameDirection', blank=True, null=True) # Field name made lowercase. - name = models.CharField(db_column='Name', max_length=64) # Field name made lowercase. - remarks = models.CharField(db_column='Remarks', max_length=255, blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'taxontreedef' - - -class Taxontreedefitem(models.Model): - taxontreedefitemid = models.AutoField(db_column='TaxonTreeDefItemID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - formattoken = models.CharField(db_column='FormatToken', max_length=32, blank=True, null=True) # Field name made lowercase. - fullnameseparator = models.CharField(db_column='FullNameSeparator', max_length=32, blank=True, null=True) # Field name made lowercase. - isenforced = models.BooleanField(db_column='IsEnforced', blank=True, null=True) # Field name made lowercase. - isinfullname = models.BooleanField(db_column='IsInFullName', blank=True, null=True) # Field name made lowercase. - name = models.CharField(db_column='Name', max_length=64) # Field name made lowercase. - rankid = models.IntegerField(db_column='RankID') # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - textafter = models.CharField(db_column='TextAfter', max_length=64, blank=True, null=True) # Field name made lowercase. - textbefore = models.CharField(db_column='TextBefore', max_length=64, blank=True, null=True) # Field name made lowercase. - title = models.CharField(db_column='Title', max_length=64, blank=True, null=True) # Field name made lowercase. - parentitemid = models.ForeignKey('self', models.DO_NOTHING, db_column='ParentItemID', blank=True, null=True) # Field name made lowercase. - taxontreedefid = models.ForeignKey(Taxontreedef, models.DO_NOTHING, db_column='TaxonTreeDefID') # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'taxontreedefitem' - - -class Treatmentevent(models.Model): - treatmenteventid = models.AutoField(db_column='TreatmentEventID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - dateboxed = models.DateField(db_column='DateBoxed', blank=True, null=True) # Field name made lowercase. - datecleaned = models.DateField(db_column='DateCleaned', blank=True, null=True) # Field name made lowercase. - datecompleted = models.DateField(db_column='DateCompleted', blank=True, null=True) # Field name made lowercase. - datereceived = models.DateField(db_column='DateReceived', blank=True, null=True) # Field name made lowercase. - datetoisolation = models.DateField(db_column='DateToIsolation', blank=True, null=True) # Field name made lowercase. - datetreatmentended = models.DateField(db_column='DateTreatmentEnded', blank=True, null=True) # Field name made lowercase. - datetreatmentstarted = models.DateField(db_column='DateTreatmentStarted', blank=True, null=True) # Field name made lowercase. - fieldnumber = models.CharField(db_column='FieldNumber', max_length=50, blank=True, null=True) # Field name made lowercase. - storage = models.CharField(db_column='Storage', max_length=64, blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - treatmentnumber = models.CharField(db_column='TreatmentNumber', max_length=32, blank=True, null=True) # Field name made lowercase. - type = models.CharField(db_column='Type', max_length=128, blank=True, null=True) # Field name made lowercase. - divisionid = models.ForeignKey(Division, models.DO_NOTHING, db_column='DivisionID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - collectionobjectid = models.ForeignKey(Collectionobject, models.DO_NOTHING, db_column='CollectionObjectID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - accessionid = models.ForeignKey(Accession, models.DO_NOTHING, db_column='AccessionID', blank=True, null=True) # Field name made lowercase. - number1 = models.IntegerField(db_column='Number1', blank=True, null=True) # Field name made lowercase. - number2 = models.IntegerField(db_column='Number2', blank=True, null=True) # Field name made lowercase. - number3 = models.DecimalField(db_column='Number3', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number4 = models.DecimalField(db_column='Number4', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number5 = models.DecimalField(db_column='Number5', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - text1 = models.TextField(db_column='Text1', blank=True, null=True) # Field name made lowercase. - text2 = models.TextField(db_column='Text2', blank=True, null=True) # Field name made lowercase. - text3 = models.TextField(db_column='Text3', blank=True, null=True) # Field name made lowercase. - text4 = models.TextField(db_column='Text4', blank=True, null=True) # Field name made lowercase. - text5 = models.TextField(db_column='Text5', blank=True, null=True) # Field name made lowercase. - yesno1 = models.BooleanField(db_column='YesNo1', blank=True, null=True) # Field name made lowercase. - yesno2 = models.BooleanField(db_column='YesNo2', blank=True, null=True) # Field name made lowercase. - yesno3 = models.BooleanField(db_column='YesNo3', blank=True, null=True) # Field name made lowercase. - performedbyid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='PerformedByID', blank=True, null=True) # Field name made lowercase. - authorizedbyid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='AuthorizedByID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'treatmentevent' - - -class Treatmenteventattachment(models.Model): - treatmenteventattachmentid = models.AutoField(db_column='TreatmentEventAttachmentID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - ordinal = models.IntegerField(db_column='Ordinal') # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - attachmentid = models.ForeignKey(Attachment, models.DO_NOTHING, db_column='AttachmentID') # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - treatmenteventid = models.ForeignKey(Treatmentevent, models.DO_NOTHING, db_column='TreatmentEventID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'treatmenteventattachment' - - -class Uniquenessrule(models.Model): - uniquenessruleid = models.AutoField(primary_key=True) - isdatabaseconstraint = models.IntegerField(db_column='isDatabaseConstraint') # Field name made lowercase. - modelname = models.CharField(db_column='modelName', max_length=256) # Field name made lowercase. - disciplineid = models.ForeignKey(Discipline, models.DO_NOTHING, db_column='DisciplineID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'uniquenessrule' - - -class UniquenessruleFields(models.Model): - uniquenessrule_fieldid = models.AutoField(primary_key=True) - fieldpath = models.TextField(db_column='fieldPath', blank=True, null=True) # Field name made lowercase. - isscope = models.IntegerField(db_column='isScope') # Field name made lowercase. - uniquenessruleid = models.ForeignKey(Uniquenessrule, models.DO_NOTHING, db_column='uniquenessruleid') - - class Meta: - managed = False - db_table = 'uniquenessrule_fields' - - -class Voucherrelationship(models.Model): - voucherrelationshipid = models.AutoField(db_column='VoucherRelationshipID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - collectionmemberid = models.IntegerField(db_column='CollectionMemberID') # Field name made lowercase. - collectioncode = models.CharField(db_column='CollectionCode', max_length=64, blank=True, null=True) # Field name made lowercase. - institutioncode = models.CharField(db_column='InstitutionCode', max_length=64, blank=True, null=True) # Field name made lowercase. - integer1 = models.IntegerField(db_column='Integer1', blank=True, null=True) # Field name made lowercase. - integer2 = models.IntegerField(db_column='Integer2', blank=True, null=True) # Field name made lowercase. - integer3 = models.IntegerField(db_column='Integer3', blank=True, null=True) # Field name made lowercase. - number1 = models.DecimalField(db_column='Number1', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number2 = models.DecimalField(db_column='Number2', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - number3 = models.DecimalField(db_column='Number3', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - text1 = models.TextField(db_column='Text1', blank=True, null=True) # Field name made lowercase. - text2 = models.TextField(db_column='Text2', blank=True, null=True) # Field name made lowercase. - text3 = models.TextField(db_column='Text3', blank=True, null=True) # Field name made lowercase. - urllink = models.CharField(db_column='UrlLink', max_length=1024, blank=True, null=True) # Field name made lowercase. - vouchernumber = models.CharField(db_column='VoucherNumber', max_length=256, blank=True, null=True) # Field name made lowercase. - yesno1 = models.BooleanField(db_column='YesNo1', blank=True, null=True) # Field name made lowercase. - yesno2 = models.BooleanField(db_column='YesNo2', blank=True, null=True) # Field name made lowercase. - yesno3 = models.BooleanField(db_column='YesNo3', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - collectionobjectid = models.ForeignKey(Collectionobject, models.DO_NOTHING, db_column='CollectionObjectID') # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'voucherrelationship' - - -class Workbench(models.Model): - workbenchid = models.AutoField(db_column='WorkbenchID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - allpermissionlevel = models.IntegerField(db_column='AllPermissionLevel', blank=True, null=True) # Field name made lowercase. - tableid = models.IntegerField(db_column='TableID', blank=True, null=True) # Field name made lowercase. - exportinstitutionname = models.CharField(db_column='ExportInstitutionName', max_length=128, blank=True, null=True) # Field name made lowercase. - exportedfromtablename = models.CharField(db_column='ExportedFromTableName', max_length=128, blank=True, null=True) # Field name made lowercase. - formid = models.IntegerField(db_column='FormId', blank=True, null=True) # Field name made lowercase. - grouppermissionlevel = models.IntegerField(db_column='GroupPermissionLevel', blank=True, null=True) # Field name made lowercase. - lockedbyusername = models.CharField(db_column='LockedByUserName', max_length=64, blank=True, null=True) # Field name made lowercase. - name = models.CharField(db_column='Name', max_length=256, blank=True, null=True) # Field name made lowercase. - ownerpermissionlevel = models.IntegerField(db_column='OwnerPermissionLevel', blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - srcfilepath = models.CharField(db_column='SrcFilePath', max_length=255, blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - workbenchtemplateid = models.ForeignKey('Workbenchtemplate', models.DO_NOTHING, db_column='WorkbenchTemplateID') # Field name made lowercase. - spprincipalid = models.ForeignKey(Spprincipal, models.DO_NOTHING, db_column='SpPrincipalID', blank=True, null=True) # Field name made lowercase. - specifyuserid = models.ForeignKey(Specifyuser, models.DO_NOTHING, db_column='SpecifyUserID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'workbench' - - -class Workbenchdataitem(models.Model): - workbenchdataitemid = models.AutoField(db_column='WorkbenchDataItemID', primary_key=True) # Field name made lowercase. - celldata = models.TextField(db_column='CellData', blank=True, null=True) # Field name made lowercase. - rownumber = models.SmallIntegerField(db_column='RowNumber', blank=True, null=True) # Field name made lowercase. - validationstatus = models.SmallIntegerField(db_column='ValidationStatus', blank=True, null=True) # Field name made lowercase. - workbenchrowid = models.ForeignKey('Workbenchrow', models.DO_NOTHING, db_column='WorkbenchRowID') # Field name made lowercase. - workbenchtemplatemappingitemid = models.ForeignKey('Workbenchtemplatemappingitem', models.DO_NOTHING, db_column='WorkbenchTemplateMappingItemID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'workbenchdataitem' - - -class Workbenchrow(models.Model): - workbenchrowid = models.AutoField(db_column='WorkbenchRowID', primary_key=True) # Field name made lowercase. - biogeomancerresults = models.TextField(db_column='BioGeomancerResults', blank=True, null=True) # Field name made lowercase. - cardimagedata = models.TextField(db_column='CardImageData', blank=True, null=True) # Field name made lowercase. - cardimagefullpath = models.CharField(db_column='CardImageFullPath', max_length=255, blank=True, null=True) # Field name made lowercase. - lat1text = models.CharField(db_column='Lat1Text', max_length=50, blank=True, null=True) # Field name made lowercase. - lat2text = models.CharField(db_column='Lat2Text', max_length=50, blank=True, null=True) # Field name made lowercase. - long1text = models.CharField(db_column='Long1Text', max_length=50, blank=True, null=True) # Field name made lowercase. - long2text = models.CharField(db_column='Long2Text', max_length=50, blank=True, null=True) # Field name made lowercase. - recordid = models.IntegerField(db_column='RecordID', blank=True, null=True) # Field name made lowercase. - rownumber = models.SmallIntegerField(db_column='RowNumber', blank=True, null=True) # Field name made lowercase. - sgrstatus = models.IntegerField(db_column='SGRStatus', blank=True, null=True) # Field name made lowercase. - uploadstatus = models.IntegerField(db_column='UploadStatus', blank=True, null=True) # Field name made lowercase. - workbenchid = models.ForeignKey(Workbench, models.DO_NOTHING, db_column='WorkbenchID') # Field name made lowercase. - errorestimate = models.DecimalField(db_column='ErrorEstimate', max_digits=20, decimal_places=10, blank=True, null=True) # Field name made lowercase. - errorpolygon = models.TextField(db_column='ErrorPolygon', blank=True, null=True) # Field name made lowercase. - - class Meta: - managed = False - db_table = 'workbenchrow' - - -class Workbenchrowexportedrelationship(models.Model): - workbenchrowexportedrelationshipid = models.AutoField(db_column='WorkbenchRowExportedRelationshipID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - recordid = models.IntegerField(db_column='RecordID', blank=True, null=True) # Field name made lowercase. - relationshipname = models.CharField(db_column='RelationshipName', max_length=120, blank=True, null=True) # Field name made lowercase. - sequence = models.IntegerField(db_column='Sequence', blank=True, null=True) # Field name made lowercase. - tablename = models.CharField(db_column='TableName', max_length=120, blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - workbenchrowid = models.ForeignKey(Workbenchrow, models.DO_NOTHING, db_column='WorkbenchRowID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'workbenchrowexportedrelationship' - - -class Workbenchrowimage(models.Model): - workbenchrowimageid = models.AutoField(db_column='WorkbenchRowImageID', primary_key=True) # Field name made lowercase. - attachtotablename = models.CharField(db_column='AttachToTableName', max_length=64, blank=True, null=True) # Field name made lowercase. - cardimagedata = models.TextField(db_column='CardImageData', blank=True, null=True) # Field name made lowercase. - cardimagefullpath = models.CharField(db_column='CardImageFullPath', max_length=255, blank=True, null=True) # Field name made lowercase. - imageorder = models.IntegerField(db_column='ImageOrder', blank=True, null=True) # Field name made lowercase. - workbenchrowid = models.ForeignKey(Workbenchrow, models.DO_NOTHING, db_column='WorkbenchRowID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'workbenchrowimage' - - -class Workbenchtemplate(models.Model): - workbenchtemplateid = models.AutoField(db_column='WorkbenchTemplateID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - name = models.CharField(db_column='Name', max_length=256, blank=True, null=True) # Field name made lowercase. - remarks = models.TextField(db_column='Remarks', blank=True, null=True) # Field name made lowercase. - srcfilepath = models.CharField(db_column='SrcFilePath', max_length=255, blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - specifyuserid = models.ForeignKey(Specifyuser, models.DO_NOTHING, db_column='SpecifyUserID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'workbenchtemplate' - - -class Workbenchtemplatemappingitem(models.Model): - workbenchtemplatemappingitemid = models.AutoField(db_column='WorkbenchTemplateMappingItemID', primary_key=True) # Field name made lowercase. - timestampcreated = models.DateTimeField(db_column='TimestampCreated') # Field name made lowercase. - timestampmodified = models.DateTimeField(db_column='TimestampModified', blank=True, null=True) # Field name made lowercase. - version = models.IntegerField(db_column='Version', blank=True, null=True) # Field name made lowercase. - xcoord = models.SmallIntegerField(db_column='XCoord', blank=True, null=True) # Field name made lowercase. - ycoord = models.SmallIntegerField(db_column='YCoord', blank=True, null=True) # Field name made lowercase. - caption = models.CharField(db_column='Caption', max_length=64, blank=True, null=True) # Field name made lowercase. - carryforward = models.BooleanField(db_column='CarryForward', blank=True, null=True) # Field name made lowercase. - datafieldlength = models.SmallIntegerField(db_column='DataFieldLength', blank=True, null=True) # Field name made lowercase. - fieldname = models.CharField(db_column='FieldName', max_length=255, blank=True, null=True) # Field name made lowercase. - fieldtype = models.SmallIntegerField(db_column='FieldType', blank=True, null=True) # Field name made lowercase. - importedcolname = models.CharField(db_column='ImportedColName', max_length=255, blank=True, null=True) # Field name made lowercase. - iseditable = models.BooleanField(db_column='IsEditable', blank=True, null=True) # Field name made lowercase. - isexportabletocontent = models.BooleanField(db_column='IsExportableToContent', blank=True, null=True) # Field name made lowercase. - isincludedintitle = models.BooleanField(db_column='IsIncludedInTitle', blank=True, null=True) # Field name made lowercase. - isrequired = models.BooleanField(db_column='IsRequired', blank=True, null=True) # Field name made lowercase. - metadata = models.CharField(db_column='MetaData', max_length=128, blank=True, null=True) # Field name made lowercase. - datacolumnindex = models.SmallIntegerField(db_column='DataColumnIndex', blank=True, null=True) # Field name made lowercase. - tableid = models.IntegerField(db_column='TableId', blank=True, null=True) # Field name made lowercase. - tablename = models.CharField(db_column='TableName', max_length=64, blank=True, null=True) # Field name made lowercase. - vieworder = models.SmallIntegerField(db_column='ViewOrder', blank=True, null=True) # Field name made lowercase. - createdbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='CreatedByAgentID', blank=True, null=True) # Field name made lowercase. - modifiedbyagentid = models.ForeignKey(Agent, models.DO_NOTHING, db_column='ModifiedByAgentID', blank=True, null=True) # Field name made lowercase. - workbenchtemplateid = models.ForeignKey(Workbenchtemplate, models.DO_NOTHING, db_column='WorkbenchTemplateID') # Field name made lowercase. - - class Meta: - managed = False - db_table = 'workbenchtemplatemappingitem' From cbbcc03bf5ddd23ba031cf174bc14773e1db68e2 Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Wed, 17 Jun 2026 09:37:58 +0200 Subject: [PATCH 087/113] Revert yml chnages --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0a89dbf6d1b..8565522320d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -159,7 +159,7 @@ jobs: # mysql -h 127.0.0.1 -P $PORT -u MasterUser -p'MasterPassword' -e 'DROP DATABASE IF EXISTS test_SpecifyDB;'; # mysql -h 127.0.0.1 -P $PORT -u MasterUser -p'MasterPassword' -e 'SHOW DATABASES;' - name: Run test suite - run: PYTHONPATH=$PYTHONPATH:$GITHUB_WORKSPACE ./ve/bin/python manage.py test --verbosity=3 --keepdb + run: ./ve/bin/python manage.py test --verbosity=3 --keepdb # run: ./ve/bin/python manage.py test --verbosity=3 --noinput test-front-end: From 4c752ccfc03ea575502df85b99e742ad58c50d7e Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Wed, 17 Jun 2026 10:56:27 +0200 Subject: [PATCH 088/113] Revert --- .env | 64 ++++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 51 insertions(+), 13 deletions(-) diff --git a/.env b/.env index 99709bb1e0e..2ecc3162430 100644 --- a/.env +++ b/.env @@ -1,32 +1,70 @@ DATABASE_HOST=mariadb DATABASE_PORT=3306 -MYSQL_ROOT_PASSWORD=root -DATABASE_NAME=ciscollections_2025_09_19 +MYSQL_ROOT_PASSWORD=password +DATABASE_NAME=specify +# The following are database users with specific roles and privileges. +# If the migrator and app user are not defined, the system will use the master user credentials. +# See documenation https://discourse.specifysoftware.org/t/new-blank-database-creation-database-user-levels/3023 -# When running Specify 7 for the first time or during updates that -# require migrations, ensure that the MASTER_NAME and MASTER_PASSWORD -# are set to the root username and password. This will ensure proper -# execution of Django migrations during the ixnitial setup. -# After launching Specify and verifying the update is complete, you can -# safely replace these credentials with the master SQL user name and password. +# MASTER Database User +# Full database administrator, used for initial setup and migrations requiring elevated privileges. +# This user should already be setup before running Specify. MASTER_NAME=root -MASTER_PASSWORD=root +MASTER_PASSWORD=password +MASTER_HOST=% + +# MIGRATOR Database User +# User with elevated privileges to perform migrations (create/drop/modify tables, etc.), for Django migration steps. +# Make sure that the user is unique to just one database, otherwise use master. +MIGRATOR_NAME=specify_migrator +MIGRATOR_PASSWORD=specify_migrator +MIGRATOR_HOST=% + +# APP Database User +# Normal runtime database user that performs application-level operations. +# Make sure that the user is unique to just one database, otherwise use master. +APP_USER_NAME=specify_user +APP_USER_PASSWORD=specify_user +APP_HOST=% + +# Enabling this option allows administrators with access to the +# backend Specify instance to log in as any user for support +# purposes without knowing their password. +# https://discourse.specifysoftware.org/t/allow-support-login-documentation/2838 +ALLOW_SUPPORT_LOGIN=false +# The amount of time in seconds each token is valid for +SUPPORT_LOGIN_TTL = 180 # Make sure to set the `SECRET_KEY` to a unique value SECRET_KEY=change_this_to_some_unique_random_string ASSET_SERVER_URL=http://host.docker.internal/web_asset_store.xml - # Make sure to set the `ASSET_SERVER_KEY` to a unique value ASSET_SERVER_KEY=your_asset_server_access_key +# Information to connect to a Redis database +# Specify will use this database as a process broker and storage for temporary +# values +REDIS_HOST=redis +REDIS_PORT=6379 +REDIS_DB_INDEX=0 + REPORT_RUNNER_HOST=report-runner REPORT_RUNNER_PORT=8080 CELERY_BROKER_URL=redis://redis/0 CELERY_RESULT_BACKEND=redis://redis/1 +# Local time zone for this installation. Choices can be found here: +# https://en.wikipedia.org/wiki/List_of_tz_zones_by_name +# although not all choices may be available on all operating systems. +# On Unix systems, a value of None will cause Django to use the same +# timezone as the operating system. +# If running in a Windows environment this must be set to the same as your +# system time zone. +TIME_ZONE = America/Chicago + # This variable controls the Specify 7 logging level. Possible values # are: # * DEBUG: Low level system information for debugging purposes. @@ -37,7 +75,7 @@ CELERY_RESULT_BACKEND=redis://redis/1 LOG_LEVEL=WARNING # Set this variable to `true` to run Specify 7 in debug mode. This -# should only be used during development and troubleshooting and not -# during general use. Django applications leak memory when operated +# should only be used during development and troubleshooting and not +# during general use. Django applications leak memory when operated # continuously in debug mode. -SP7_DEBUG=true +SP7_DEBUG=true \ No newline at end of file From a81195aa7136e028d9d7115f9a919e05972fc18e Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Wed, 17 Jun 2026 17:10:12 +0200 Subject: [PATCH 089/113] fix: deduplication.py case sensitivity --- .../migration_utils/{Deduplication.py => deduplication.py} | 1 + 1 file changed, 1 insertion(+) rename specifyweb/specify/migration_utils/{Deduplication.py => deduplication.py} (99%) diff --git a/specifyweb/specify/migration_utils/Deduplication.py b/specifyweb/specify/migration_utils/deduplication.py similarity index 99% rename from specifyweb/specify/migration_utils/Deduplication.py rename to specifyweb/specify/migration_utils/deduplication.py index 1086f65b167..b1d509a6f30 100644 --- a/specifyweb/specify/migration_utils/Deduplication.py +++ b/specifyweb/specify/migration_utils/deduplication.py @@ -6,6 +6,7 @@ logger = logging.getLogger(__name__) + def deduplicate_schema_config_sql(apps=None): dedupe_sql = ''' /* From e4ae06ed2553ee67670ab9aab75c0133928f56c4 Mon Sep 17 00:00:00 2001 From: "Caroline D." <108160931+CarolineDenis@users.noreply.github.com> Date: Wed, 17 Jun 2026 21:40:20 +0200 Subject: [PATCH 090/113] Ensure SP7_DEBUG variable is set correctly --- .env | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.env b/.env index 2ecc3162430..71fe3b0c430 100644 --- a/.env +++ b/.env @@ -78,4 +78,4 @@ LOG_LEVEL=WARNING # should only be used during development and troubleshooting and not # during general use. Django applications leak memory when operated # continuously in debug mode. -SP7_DEBUG=true \ No newline at end of file +SP7_DEBUG=true From 2eb531c0f15787a3ac30b1022d14f22d6dba4247 Mon Sep 17 00:00:00 2001 From: melton-jason Date: Wed, 17 Jun 2026 16:19:16 -0500 Subject: [PATCH 091/113] fix: imports in update_schema_config file --- .../migration_helpers/__init__.py | 19 ++++++++++++++++++- .../migration_utils/update_schema_config.py | 12 +++++------- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/specifyweb/specify/migration_utils/migration_helpers/__init__.py b/specifyweb/specify/migration_utils/migration_helpers/__init__.py index 0ea0a5a1f0c..f6a08eeff89 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/__init__.py +++ b/specifyweb/specify/migration_utils/migration_helpers/__init__.py @@ -1 +1,18 @@ -# Package initialization file \ No newline at end of file +from .helper_0002_schema_config_update import MIGRATION_0002_TABLES +from .helper_0004_stratigraphy_age import MIGRATION_0004_FIELDS, MIGRATION_0004_TABLES +from .helper_0007_schema_config_update import MIGRATION_0007_FIELDS +from .helper_0008_schema_config_update import MIGRATION_0008_FIELDS +from .helper_0012_add_cojo_to_schema_config import MIGRATION_0012_FIELDS +from .helper_0013_collectionobjectgroup_parentcog import MIGRATION_0013_FIELDS +from .helper_0020_add_tectonicunit_to_pc_in_schema_config import MIGRATION_0020_FIELDS +from .helper_0021_update_hidden_geo_tables import MIGRATION_0021_FIELDS +from .helper_0023_update_schema_config_text import MIGRATION_0023_FIELDS_BIS, MIGRATION_0023_FIELDS +from .helper_0024_add_uniqueIdentifier_storage import MIGRATION_0024_FIELDS +from .helper_0027_CO_children import MIGRATION_0027_FIELDS, MIGRATION_0027_UPDATE_FIELDS +from .helper_0029_remove_collectionobject_parentco import MIGRATION_0029_FIELDS, MIGRATION_0029_UPDATE_FIELDS +from .helper_0032_add_quantities_gift import MIGRATION_0032_FIELDS, MIGRATION_0032_UPDATE_FIELDS +from .helper_0033_update_paleo_desc import MIGRATION_0033_TABLES +from .helper_0034_accession_date_fields import MIGRATION_0034_FIELDS, MIGRATION_0034_UPDATE_FIELDS +from .helper_0035_version_required import MIGRATION_0035_FIELDS +from .helper_0039_agent_fields_for_loan_and_gift import MIGRATION_0039_FIELDS +from .helper_0040_components import MIGRATION_0040_TABLES, MIGRATION_0040_FIELDS, MIGRATION_0040_UPDATE_FIELDS, MIGRATION_0040_HIDDEN_FIELDS diff --git a/specifyweb/specify/migration_utils/update_schema_config.py b/specifyweb/specify/migration_utils/update_schema_config.py index de0b493dba7..a8bddf1f73d 100644 --- a/specifyweb/specify/migration_utils/update_schema_config.py +++ b/specifyweb/specify/migration_utils/update_schema_config.py @@ -19,10 +19,8 @@ from specifyweb.specify.models_utils.load_datamodel import FieldDoesNotExistError from specifyweb.specify.models_utils.model_extras import GEOLOGY_DISCIPLINES, PALEO_DISCIPLINES -from specifyweb.specify.models import ( - datamodel, -) -from specifyweb.specify.migration_utils.sp7_schemaconfig import ( +from specifyweb.specify.models import datamodel +from specifyweb.specify.migration_utils.migration_helpers import ( MIGRATION_0002_TABLES, MIGRATION_0004_FIELDS, MIGRATION_0004_TABLES, @@ -45,7 +43,7 @@ MIGRATION_0034_FIELDS, MIGRATION_0034_UPDATE_FIELDS, MIGRATION_0035_FIELDS, - MIGRATION_0038_FIELDS, + MIGRATION_0039_FIELDS, MIGRATION_0040_TABLES, MIGRATION_0040_FIELDS, MIGRATION_0040_UPDATE_FIELDS, @@ -1977,12 +1975,12 @@ def update_loan_and_gift_agent_fields(apps): "ishidden": True } for discipline in Discipline.objects.all(): - for table, fields in MIGRATION_0038_FIELDS.items(): + for table, fields in MIGRATION_0039_FIELDS.items(): for field_name in fields: update_table_field_schema_config_with_defaults(table, discipline.id, field_name, apps, defaults=field_defaults) def revert_loan_and_gift_agent_fields(apps): - for table, fields in MIGRATION_0038_FIELDS.items(): + for table, fields in MIGRATION_0039_FIELDS.items(): for field_name in fields: revert_table_field_schema_config(table, field_name, apps) From af06fed43817e3d36b77d06387b131e6e8163bb2 Mon Sep 17 00:00:00 2001 From: melton-jason Date: Wed, 17 Jun 2026 16:28:01 -0500 Subject: [PATCH 092/113] fix: remove extra update_schema_config file --- .../helper_0042_discipline_type_picklist.py | 13 +- .../migration_utils/update_schema_config.py | 2220 ----------------- 2 files changed, 11 insertions(+), 2222 deletions(-) delete mode 100644 specifyweb/specify/migration_utils/update_schema_config.py diff --git a/specifyweb/specify/migration_utils/migration_helpers/helper_0042_discipline_type_picklist.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0042_discipline_type_picklist.py index ccf8fed40d1..32a66f7e6c4 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/helper_0042_discipline_type_picklist.py +++ b/specifyweb/specify/migration_utils/migration_helpers/helper_0042_discipline_type_picklist.py @@ -2,6 +2,10 @@ # ########################################## # Used in 0042_discipline_type_picklist.py # ########################################## +from typing import Iterable +from itertools import islice + +from django.db.models import Exists, OuterRef from specifyweb.backend.context.app_resource import DISCIPLINE_NAMES @@ -89,7 +93,10 @@ def update_discipline_type_splocalecontaineritem(apps): container__name="discipline", container__schematype=0, name="type", - ).update(picklistname=DISCIPLINE_TYPE_PICKLIST_NAME, isrequired=True) + ).update( + picklistname=DISCIPLINE_TYPE_PICKLIST_NAME, + isrequired=True + ) def revert_discipline_type_splocalecontaineritem(apps): Splocalecontaineritem = apps.get_model("specify", "Splocalecontaineritem") @@ -99,4 +106,6 @@ def revert_discipline_type_splocalecontaineritem(apps): picklistname=DISCIPLINE_TYPE_PICKLIST_NAME, container__schematype=0, name="type", - ).update(picklistname=None) \ No newline at end of file + ).update( + picklistname=None + ) diff --git a/specifyweb/specify/migration_utils/update_schema_config.py b/specifyweb/specify/migration_utils/update_schema_config.py deleted file mode 100644 index a8bddf1f73d..00000000000 --- a/specifyweb/specify/migration_utils/update_schema_config.py +++ /dev/null @@ -1,2220 +0,0 @@ -import re -import json - -from typing import NamedTuple, Tuple, TypedDict, NotRequired, Iterable -import logging -from collections import defaultdict -from functools import lru_cache -from itertools import islice -from pathlib import Path - - -from django.db.models import Q, Count, Window, F, Exists, OuterRef -from django.conf import settings -from django.apps import apps as global_apps -from django.db import connection, transaction -from django.db.models.functions import RowNumber - -from specifyweb.specify.models_utils.load_datamodel import FieldDoesNotExistError - -from specifyweb.specify.models_utils.load_datamodel import FieldDoesNotExistError -from specifyweb.specify.models_utils.model_extras import GEOLOGY_DISCIPLINES, PALEO_DISCIPLINES -from specifyweb.specify.models import datamodel -from specifyweb.specify.migration_utils.migration_helpers import ( - MIGRATION_0002_TABLES, - MIGRATION_0004_FIELDS, - MIGRATION_0004_TABLES, - MIGRATION_0007_FIELDS, - MIGRATION_0008_FIELDS, - MIGRATION_0012_FIELDS, - MIGRATION_0013_FIELDS, - MIGRATION_0020_FIELDS, - MIGRATION_0021_FIELDS, - MIGRATION_0023_FIELDS, - MIGRATION_0023_FIELDS_BIS, - MIGRATION_0024_FIELDS, - MIGRATION_0027_FIELDS, - MIGRATION_0027_UPDATE_FIELDS, - MIGRATION_0029_FIELDS, - MIGRATION_0029_UPDATE_FIELDS, - MIGRATION_0032_FIELDS, - MIGRATION_0032_UPDATE_FIELDS, - MIGRATION_0033_TABLES, - MIGRATION_0034_FIELDS, - MIGRATION_0034_UPDATE_FIELDS, - MIGRATION_0035_FIELDS, - MIGRATION_0039_FIELDS, - MIGRATION_0040_TABLES, - MIGRATION_0040_FIELDS, - MIGRATION_0040_UPDATE_FIELDS, - MIGRATION_0040_HIDDEN_FIELDS, -) - -logger = logging.getLogger(__name__) - -HIDDEN_FIELDS = [ - "timestampcreated", "timestampmodified", "version", "createdbyagent", "modifiedbyagent" -] - -def _has_explicit_hidden_override(field_config: dict) -> bool: - return any(key.lower() == "ishidden" for key in field_config.keys()) - -@lru_cache(maxsize=None) -def _schema_override_hidden_values_for_discipline( - discipline_type: str, -) -> dict[str, dict[str, bool]]: - """ - Return a mapping of {table_name -> {field_name -> ishidden_value}} for fields - that have an - explicit `ishidden` override in config//schema_overrides.json. - """ - normalized_discipline = (discipline_type or "").lower() - if not normalized_discipline: - return {} - - schema_overrides_path = ( - Path(settings.SPECIFY_CONFIG_DIR) / normalized_discipline / "schema_overrides.json" - ) - if not schema_overrides_path.exists(): - return {} - - try: - with schema_overrides_path.open("r", encoding="utf-8") as schema_overrides_file: - overrides = json.load(schema_overrides_file) - except (OSError, json.JSONDecodeError) as exc: - logger.warning( - "Unable to read schema overrides for discipline '%s' at %s: %s", - normalized_discipline, - schema_overrides_path, - exc, - ) - return {} - - if not isinstance(overrides, dict): - return {} - - hidden_override_values_by_table: dict[str, dict[str, bool]] = {} - for table_name, table_config in overrides.items(): - if not isinstance(table_config, dict): - continue - - explicit_hidden_override_values: dict[str, bool] = {} - items = table_config.get("items", []) - if not isinstance(items, list): - continue - - for item in items: - if not isinstance(item, dict): - continue - - for field_name, field_config in item.items(): - if not isinstance(field_config, dict): - continue - if not _has_explicit_hidden_override(field_config): - continue - for key, value in field_config.items(): - if key.lower() == "ishidden": - explicit_hidden_override_values[field_name.lower()] = bool(value) - break - - if explicit_hidden_override_values: - hidden_override_values_by_table[table_name.lower()] = explicit_hidden_override_values - - return hidden_override_values_by_table - -@lru_cache(maxsize=None) -def _schema_override_hidden_fields_for_discipline(discipline_type: str) -> dict[str, set[str]]: - hidden_override_values = _schema_override_hidden_values_for_discipline(discipline_type) - return { - table_name: set(table_values.keys()) - for table_name, table_values in hidden_override_values.items() - } - -def _fields_without_explicit_hidden_override( - table_name: str, - field_names: list[str], - discipline_type: str, -) -> list[str]: - table_hidden_overrides = _schema_override_hidden_fields_for_discipline( - discipline_type - ).get(table_name.lower(), set()) - return [ - field_name - for field_name in field_names - if field_name.lower() not in table_hidden_overrides - ] - -def datamodel_type_to_schematype(datamodel_type: str) -> str: - """ - Converts a string like `many-to-one` to `ManyToOne` by: - - Splitting on hyphens - - e.g., ['many', 'to', 'one'] - - Lowering then capitilizing each string in the split - - e.g., ['Many', 'To', 'One'] - - Joining the split strings back together - - e.g., 'ManyToOne' - """ - return "".join(map(lambda type_part: type_part.lower().capitalize(), datamodel_type.split('-'))) - -def camel_to_spaced_title_case(camel_case: str) -> str: - """ - Given a camel case string, convert it to title case and add spaces - - - `catalogNumber` -> `Catalog Number` - - `modifiedByAgent` -> `Modified By Agent` - - `yesNo6` -> `Yes No6` - - `cojo` -> `Cojo` - """ - return re.sub(r"(? str: - return string.lower() if len(string) <= 1 else string[0].lower() + string[1:] - -def bulk_create_splocaleitemstr_idempotent(Splocaleitemstr, rows: list[dict]) -> int: - if not rows: - return 0 - - fk_fields = ("itemname", "itemdesc", "containername", "containerdesc") - groups: dict[str, list[dict]] = defaultdict(list) - for r in rows: - present = [f for f in fk_fields if r.get(f) is not None] - if len(present) != 1: - raise ValueError(f"Each row must set exactly one FK among {fk_fields}. Got: {present}") - groups[present[0]].append(r) - - total_created = 0 - - for fk_field, group_rows in groups.items(): - fk_ids: set[int] = set() - languages: set[str] = set() - - for r in group_rows: - fk_ids.add(r[fk_field].pk) - languages.add(r["language"]) - - existing_rows = list( - Splocaleitemstr.objects.filter( - **{ - f"{fk_field}_id__in": fk_ids, - "language__in": languages, - } - ) - .filter( - Q(country__isnull=True) | Q(country=""), - Q(variant__isnull=True) | Q(variant=""), - ) - .order_by("id") - ) - - existing_by_key: dict[Tuple[str, int], list] = defaultdict(list) - fk_field_id = f"{fk_field}_id" - for existing_row in existing_rows: - key = (existing_row.language, getattr(existing_row, fk_field_id)) - existing_by_key[key].append(existing_row) - - desired_by_key: dict[Tuple[str, int], dict] = {} - for r in group_rows: - key = (r["language"], r[fk_field].pk) - desired_by_key[key] = r - - ids_to_delete: set[int] = set() - to_create = [] - for key, desired_row in desired_by_key.items(): - existing_for_key = existing_by_key.get(key, []) - - if not existing_for_key: - to_create.append(Splocaleitemstr(**desired_row)) - continue - - for duplicate in existing_for_key[1:]: - ids_to_delete.add(duplicate.id) - - if ids_to_delete: - Splocaleitemstr.objects.filter(id__in=ids_to_delete).delete() - - if to_create: - Splocaleitemstr.objects.bulk_create(to_create) - total_created += len(to_create) - - return total_created - -class TableDefaults(TypedDict): - name: NotRequired[str] - desc: NotRequired[str] - items: "NotRequired[dict[str, FieldDefaults]]" - -def update_table_schema_config_with_defaults( - table_name, - discipline_id: int, - description: str | None = None, - apps = global_apps, - defaults: TableDefaults | None = None, - pending_itemstr_rows: list[dict] | None = None, -): - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') - - table = datamodel.get_table(table_name) - - # BUG: The splocalecontainer related tables can still exist in the database, - # and this will result in skipping any operation if the table/field is - # removed, renamed, etc. - if table is None: - logger.warning( - f"Table does not exist in latest state of the datamodel, skipping Schema Config entry for: {table_name}" - ) - return - - flush_itemstr_at_end = pending_itemstr_rows is None - if flush_itemstr_at_end: - pending_itemstr_rows = [] - - try: - table_defaults = defaults if defaults is not None else TableDefaults() - table_name_str = table_defaults.get('name', camel_to_spaced_title_case(uncapitilize(table.name))) - table_desc_str = table_defaults.get('desc', camel_to_spaced_title_case(uncapitilize(table.name))) - - table_config = TableSchemaConfig( - name=table.name, - discipline_id=discipline_id, - schema_type=0, - description=table_desc_str if description is None else description, - language="en", - ) - - container_attrs = { - "name": table_config.name.lower(), - "discipline_id": discipline_id, - "schematype": table_config.schema_type - } - - fetched_sp_locale_container = Splocalecontainer.objects.filter(**container_attrs).order_by("id").first() - - if fetched_sp_locale_container is None: - sp_local_container = Splocalecontainer.objects.create(**{ - **container_attrs, - "ishidden": False, - "issystem": table.system, - "version": 0, - }) - else: - sp_local_container = fetched_sp_locale_container - - if Splocalecontaineritem.objects.filter( - container=sp_local_container, - name=table_config.name.lower(), - ).exists(): - return - - item_str_rows = [] - for k, text in { - "containername": table_name_str, - "containerdesc": table_desc_str, - }.items(): - item_str_rows.append( - { - "text": text, - "language": "en", - "version": 0, - k: sp_local_container, - } - ) - - pending_itemstr_rows.extend(item_str_rows) - - 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()) - - update_table_field_schema_config_with_defaults( - table_name, - discipline_id, - field.name, - apps, - defaults=field_defaults, - pending_itemstr_rows=pending_itemstr_rows, - ) - - finally: - if flush_itemstr_at_end and pending_itemstr_rows: - bulk_create_splocaleitemstr_idempotent(Splocaleitemstr, pending_itemstr_rows) - -def revert_table_schema_config(table_name, apps=global_apps): - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - - containers = Splocalecontainer.objects.filter(name=table_name) - items = Splocalecontaineritem.objects.filter(container__in=containers) - Splocaleitemstr.objects.filter( - Q(itemname__in=items) | - Q(itemdesc__in=items) | - Q(containername__in=containers) | - Q(containerdesc__in=containers) - ).delete() - items.delete() - containers.delete() - -class FieldDefaults(TypedDict): - name: NotRequired[str] - desc: NotRequired[str] - ishidden: NotRequired[bool] - isrequired: NotRequired[bool] - picklistname: NotRequired[str] - -def update_table_field_schema_config_with_defaults( - table_name, - discipline_id: int, - field_name: str, - apps = global_apps, - defaults: FieldDefaults | None = None, - pending_itemstr_rows: list[dict] | None = None, -): - table = datamodel.get_table(table_name) - - # BUG: The splocalecontainer related tables can still exist in the database, - # and this will result in skipping any operation if the table/field is - # removed, renamed, etc. - if table is None: - logger.warning(f"Table does not exist in latest state of the datamodel, skipping Schema Config entry for: {table_name}") - return - - table_name = table.name - table_config = TableSchemaConfig( - name=table_name.lower(), - discipline_id=discipline_id, - schema_type=0, - language="en" - ) - - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - - sp_local_container = ( - Splocalecontainer.objects.filter( - name=table.name.lower(), - discipline_id=discipline_id, - schematype=table_config.schema_type, - ) - .order_by('id') - .first() - ) - - if sp_local_container is None: - sp_local_container = Splocalecontainer.objects.create( - name=table.name.lower(), - discipline_id=discipline_id, - schematype=table_config.schema_type, - ishidden=False, - issystem=table.system, - version=0, - ) - - try: - field = table.get_field_strict(field_name) - except FieldDoesNotExistError: - if field_name in {'parentCog', 'parentCO', 'children', 'componentParent', 'components'}: - return - logger.warning( - f"Field does not exist in latest state of the datamodel, skipping Schema Config entry for: {table_name} -> {field_name}" - ) - return - except AttributeError: - logger.warning( - f"Field does not exist in latest state of the datamodel, skipping Schema Config entry for: {table_name} -> {field_name}" - ) - return - - # Apply defaults if provided - field_name_str = camel_to_spaced_title_case(field.name) - field_desc_str = camel_to_spaced_title_case(field.name) - field_hidden = field_name.lower() in HIDDEN_FIELDS - field_required = field.required - picklist_name = None - if defaults is not None: - field_name_str = defaults.get('name', field_name_str) - field_desc_str = defaults.get('desc', field_desc_str) - field_hidden = defaults.get('ishidden', field_hidden) - field_required = defaults.get('isrequired', field_required) - picklist_name = defaults.get('picklistname', picklist_name) - - field_config = FieldSchemaConfig( - name=field_name, - column=field.column, - java_type=datamodel_type_to_schematype(field.type) if field.is_relationship else field.type, - description=field_desc_str, - language="en" - ) - - container_item_attrs = { - "name": field_config.name, - "container": sp_local_container - } - - fetched_sp_locale_container_item = Splocalecontaineritem.objects.filter(**container_item_attrs).order_by("id").first() - - if fetched_sp_locale_container_item is None: - sp_locale_container_item = Splocalecontaineritem.objects.create(**{ - **container_item_attrs, - "type": field_config.java_type, - "ishidden": field_hidden, - "isrequired": field_required, - "issystem": table.system, - "version": 0, - "picklistname": picklist_name - } - ) - else: - sp_locale_container_item = fetched_sp_locale_container_item - - itm_str_rows = [] - for k, text in { - "itemname": field_name_str, - "itemdesc": field_desc_str, - }.items(): - row = { - "text": text, - "language": "en", - "version": 0, - k: sp_locale_container_item, - } - itm_str_rows.append(row) - - if pending_itemstr_rows is None: - bulk_create_splocaleitemstr_idempotent(Splocaleitemstr, itm_str_rows) - else: - pending_itemstr_rows.extend(itm_str_rows) - -def revert_table_field_schema_config(table_name, field_name, apps=global_apps): - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - - containers = Splocalecontainer.objects.filter(name=table_name) - items = Splocalecontaineritem.objects.filter(container__in=containers, name=field_name) - Splocaleitemstr.objects.filter( - Q(itemname__in=items) | - Q(itemdesc__in=items) - ).delete() - items.delete() - -def update_table_field_schema_config_params( - table_name, - discipline_id: int, - field_name: str, - update_params: dict, - apps = global_apps -): - table = datamodel.get_table(table_name) - - if table is None: - logger.warning(f"Table does not exist in latest state of the datamodel, skipping Schema Config entry for: {table_name}") - return - - table_name = table.name - table_config = TableSchemaConfig( - name=table_name.lower(), - discipline_id=discipline_id, - schema_type=0, - language="en" - ) - - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - - sp_local_container = ( - Splocalecontainer.objects.filter( - name=table.name.lower(), - discipline_id=discipline_id, - schematype=table_config.schema_type, - ) - .order_by('id') - .first() - ) - - if sp_local_container is None: - sp_local_container = Splocalecontainer.objects.create( - name=table.name.lower(), - discipline_id=discipline_id, - schematype=table_config.schema_type, - ishidden=False, - issystem=table.system, - version=0, - ) - - try: - field = table.get_field_strict(field_name) - except FieldDoesNotExistError: - logger.warning( - f"Field does not exist in latest state of the datamodel, skipping Schema Config entry for: {table_name} -> {field_name}" - ) - return - except AttributeError: - logger.warning( - f"Field does not exist in latest state of the datamodel, skipping Schema Config entry for: {table_name} -> {field_name}" - ) - return - - field_config = FieldSchemaConfig( - name=field_name, - column=field.column, - java_type=datamodel_type_to_schematype(field.type) if field.is_relationship else field.type, - description=camel_to_spaced_title_case(field.name), - language="en" - ) - - qs = Splocalecontaineritem.objects.filter( - name=field_config.name, - container=sp_local_container, - type=field_config.java_type, # maybe remove from filter - ) - count = qs.count() - - if count == 0: - # logger.warning(f"Splocalecontaineritem does not exist for: {table_name} -> {field_name}, skipping update") - return - - if count > 1: - updated = qs.update(**update_params) - logger.info(f"Updated {updated} duplicate Splocalecontaineritem rows for {table_name}.{field_name}") - return - - sp_local_container_item = qs.first() - for k, v in update_params.items(): - setattr(sp_local_container_item, k, v) - sp_local_container_item.save(update_fields=list(update_params.keys())) - -def find_missing_schema_config_fields(discipline_id: int, apps=global_apps): - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - - missing_tables: list[str] = [] - missing_fields: dict[str, list[str]] = {} - - containers = Splocalecontainer.objects.filter( - discipline_id=discipline_id, - schematype=0, - ) - container_names = set( - containers.values_list('name', flat=True) - ) - - existing_fields_by_table: dict[str, set[str]] = defaultdict(set) - for table_name, field_name in Splocalecontaineritem.objects.filter( - container__in=containers - ).values_list('container__name', 'name'): - if table_name and field_name: - existing_fields_by_table[table_name].add(field_name.lower()) - - for table in datamodel.tables: - table_name = table.name - table_name_lower = table_name.lower() - 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(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(exclude_id_field=True) - if field.name and field.name.lower() not in existing_fields - ) - - if missing_in_table: - missing_fields[table_name] = missing_in_table - - return missing_tables, missing_fields - - -def create_missing_schema_config_fields(discipline_id: int, apps=global_apps, stdout=None): - missing_tables, missing_fields = find_missing_schema_config_fields(discipline_id, apps=apps) - missing_table_set = set(missing_tables) - - for table_name in missing_tables: - if stdout is not None: - stdout(f"Creating schema config table container for {table_name}...") - update_table_schema_config_with_defaults(table_name, discipline_id, apps=apps) - - for table_name, fields in missing_fields.items(): - if table_name in missing_table_set: - continue - for field_name in fields: - if stdout is not None: - stdout(f"Creating schema config field {table_name}.{field_name}...") - update_table_field_schema_config_with_defaults(table_name, discipline_id, field_name, apps=apps) - - return missing_tables, missing_fields - -def deduplicate_schema_config_sql(apps=None): - dedupe_sql = ''' - /* - - This script removes duplicate entries in the `splocalecontaineritem` table. - - The safe dedupe key is the concrete container row plus the item name: - `SpLocaleContainerID` + `Name`. - - Why this matters: - - Schema config containers can share the same logical table name inside a - discipline while still being distinct rows. - - Grouping by discipline + table name + field name can collapse valid rows - from different containers that merely happen to share the same name. - - Keeping the first row for a specific container/name pair preserves real - schema config entries and only removes true duplicates. - - Any duplicate rows are deleted together with their dependent string rows. - - */ - - - -- 1. Identify all duplicate Container Item IDs - -- We group by the concrete container row and the field name. - -- Only schema-type 0 containers are eligible for this cleanup. - -- We keep the record with the lowest ID (rn = 1) and mark the rest (rn > 1) - CREATE TEMPORARY TABLE container_items_to_delete AS - SELECT - sub.SpLocaleContainerItemID - FROM ( - SELECT - slci.SpLocaleContainerItemID, - ROW_NUMBER() OVER ( - PARTITION BY slci.SpLocaleContainerID, slci.Name - ORDER BY slci.SpLocaleContainerItemID ASC - ) as rn - FROM splocalecontaineritem slci - JOIN splocalecontainer slc ON slci.SpLocaleContainerID = slc.SpLocaleContainerID - WHERE slc.SchemaType = 0 - ) sub - WHERE sub.rn > 1; - - -- 2. Delete the dependent strings first to satisfy Foreign Key constraints - -- This handles strings linked as either 'Name' or 'Description' - DELETE FROM splocaleitemstr - WHERE SpLocaleContainerItemNameID IN (SELECT SpLocaleContainerItemID FROM container_items_to_delete) - OR SpLocaleContainerItemDescID IN (SELECT SpLocaleContainerItemID FROM container_items_to_delete); - - -- 3. Delete the duplicate Container Items - DELETE FROM splocalecontaineritem - WHERE SpLocaleContainerItemID IN (SELECT SpLocaleContainerItemID FROM container_items_to_delete); - - -- 4. Clean up the temporary table - DROP TEMPORARY TABLE container_items_to_delete; - ''' - cursor = connection.cursor() - cursor.execute(dedupe_sql) - cursor.close() - -def deduplicate_splocalecontainers(apps): - Container = apps.get_model('specify', 'SpLocaleContainer') - ContainerItem = apps.get_model('specify', 'SpLocaleContainerItem') - ItemStr = apps.get_model('specify', 'SpLocaleItemStr') - - with transaction.atomic(): - # Find duplicate SpLocaleContainers - # A duplicate should be in the same discipline and have the same name - # and schematype - # For this query we consider the oldest SpLocaleContainer as the - # "cannonical" record, and all later records as the duplicates - # We could be a little smarter about this and also check the associated - # container items and strings, but this should be minimally sufficient - # without sacrificing complexity and speed - # See #7988 - duplicate_containers = Container.objects.filter(schematype=0).annotate( - earlier_exists=Exists( - Container.objects.filter( - discipline_id=OuterRef('discipline_id'), - schematype=0, - name=OuterRef('name'), - timestampcreated__lt=OuterRef('timestampcreated') - ) - ) - ).filter(earlier_exists=True) - - # Remove the items and strings shouldn't be strictly neccesary as they - # should both cascade if we call duplicate_containers.delete() - # But this is the safer option for any edge cases with historical - # models in migrations and if we ever decide to change the delete - # behavior later down the line - # Plus, I don't think the performance impact should be **that** - # significantly different... - duplicate_items = ContainerItem.objects.filter(container__in=duplicate_containers) - ItemStr.objects.filter(itemname__in=duplicate_items).delete() - ItemStr.objects.filter(itemdesc__in=duplicate_items).delete() - duplicate_items.delete() - - ItemStr.objects.filter(containername__in=duplicate_containers).delete() - ItemStr.objects.filter(containerdesc__in=duplicate_containers).delete() - duplicate_containers.delete() - - -def deduplicate_containeritems_and_strings(apps): - ContainerItem = apps.get_model('specify', 'SpLocaleContainerItem') - ItemStr = apps.get_model('specify', 'SpLocaleItemStr') - with transaction.atomic(): - # Identify duplicate container items using a Window function. - # Partition by container_id + item name only. - # Only schema type 0 containers (standard schema) are eligible for this cleanup. - # The schema type 1 refers to the WorkBench Schema from Specify 6, which has - # a different structure and should not be modified by this cleanup. - # - # Why this key: - # - Rows are only true duplicates when they refer to the same concrete - # container row and the same field name. - # - Earlier broad grouping by discipline/container-name/field-name could - # collapse valid rows from different containers that happened to share - # names, causing missing Schema Config fields after dedupe. - # - This narrower key preserves legitimate rows and only removes - # duplicates that are semantically equivalent. - qs = ContainerItem.objects.filter( - container__schematype=0, - ).annotate( - rn=Window( - expression=RowNumber(), - partition_by=[ - F('container_id'), - F('name') - ], - order_by=F('id').asc() - ) - ) - - # Extract the IDs of the duplicates, keep the first and delete the rest - ids_to_delete = [item.id for item in qs if item.rn > 1] - - if ids_to_delete: - # Delete dependent strings using corrected field names - ItemStr.objects.filter(itemname_id__in=ids_to_delete).delete() - ItemStr.objects.filter(itemdesc_id__in=ids_to_delete).delete() - - # Delete the duplicate Container Items - ContainerItem.objects.filter(id__in=ids_to_delete).delete() - - print(f"Successfully deleted {len(ids_to_delete)} duplicate schema items.") - else: - print("No duplicates found.") - -def deduplicate_schema_config_orm(apps, schema_editor=None): - with transaction.atomic(): - deduplicate_splocalecontainers(apps) - deduplicate_containeritems_and_strings(apps) - -# ############################################################################## -# Migration schema config helper functions -# ############################################################################## - -def update_all_table_schema_config_with_defaults(apps): - Discipline = apps.get_model('specify', 'Discipline') - for discipline in Discipline.objects.all(): - for table in datamodel.tables: - update_table_schema_config_with_defaults(table.name, discipline.id, None, apps) - -# ########################################## -# Used in 0002_schema_config_update.py -# ########################################## - -DEFAULT_COG_TYPES = [ - 'Discrete', - 'Consolidated', - 'Drill Core', -] - -def create_geo_table_schema_config_with_defaults(apps): - Discipline = apps.get_model('specify', 'Discipline') - for discipline in Discipline.objects.all(): - for table, desc in MIGRATION_0002_TABLES: - update_table_schema_config_with_defaults(table, discipline.id, desc, apps) - -# ########################################## -# Used in 0003_cotype_picklist.py -# ########################################## - -COT_PICKLIST_NAME = 'CollectionObjectType' -COT_FIELD_NAME = 'collectionObjectType' -COT_TEXT = 'Collection Object Type' - -# FEAT: Replace this implementation with -# update_table_field_schema_config_with_defaults -def create_cotype_splocalecontaineritem(apps): - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') - - # Create a Splocalecontaineritem record for each CollectionObject Splocalecontainer - # NOTE: Each discipline has its own CollectionObject Splocalecontainer - for container in Splocalecontainer.objects.filter(name='collectionobject', schematype=0): - container_item_attrs = { - "name": COT_FIELD_NAME, - "container": container - } - container_item = Splocalecontaineritem.objects.filter(**container_item_attrs).order_by("id").first() - if container_item is None: - resolved_item = Splocalecontaineritem.objects.create( - **container_item_attrs, - picklistname=COT_PICKLIST_NAME, - type="ManyToOne", - isrequired=True - ) - else: - resolved_item = container_item - - field_label_attrs = { - "language": "en", - "itemname":resolved_item - } - - field_label = Splocaleitemstr.objects.filter(**field_label_attrs).order_by("id").first() - - if field_label is None: - Splocaleitemstr.objects.create(**field_label_attrs, text=COT_TEXT) - - field_desc_attrs = { - "language": "en", - "itemdesc":resolved_item - } - - field_desc = Splocaleitemstr.objects.filter(**field_desc_attrs).order_by("id").first() - - if field_desc is None: - Splocaleitemstr.objects.create(**field_desc_attrs, text=COT_TEXT) - -# ########################################## -# Used in 0004_stratigraphy_age.py -# ########################################## - -AGETYPE_PICKLIST_NAME = 'AgeType' -DEFAULT_AGE_TYPES = [ - 'Sedimentation', - 'Metamorphism', - 'Erosion', - 'Diagenetic', -] - -def create_agetype_picklist(apps): - Collection = apps.get_model('specify', 'Collection') - Picklist = apps.get_model('specify', 'Picklist') - PicklistItem = apps.get_model('specify', 'Picklistitem') - - for collection in Collection.objects.all(): - age_type_picklist, created = Picklist.objects.get_or_create( - name=AGETYPE_PICKLIST_NAME, - type=0, - collection_id=collection.id, - defaults={ - "issystem": False, - "readonly": False, - "sizelimit": -1, - "sorttype": 1, - } - ) - if created: - for age_type in DEFAULT_AGE_TYPES: - PicklistItem.objects.get_or_create( - title=age_type, - value=age_type, - picklist=age_type_picklist - ) - -def create_strat_table_schema_config_with_defaults(apps): - Discipline = apps.get_model('specify', 'Discipline') - for discipline in Discipline.objects.all(): - for table, desc in MIGRATION_0004_TABLES: # NOTE: lots of Nones, getting skips - update_table_schema_config_with_defaults(table, discipline.id, desc, apps) - - for table, fields in MIGRATION_0004_FIELDS.items(): - for field in fields: - update_table_field_schema_config_with_defaults(table, discipline.id, field, apps) - -def revert_strat_table_schema_config_with_defaults(apps): - for table, _ in MIGRATION_0004_TABLES: - revert_table_schema_config(table, apps) - for table, fields in MIGRATION_0004_FIELDS.items(): - for field in fields: - revert_table_field_schema_config(table, field, apps) - -# ########################################## -# Used in 0007_schema_config_update.py -# ########################################## - -COG_PICKLIST_NAME = 'COGTypes' -COGTYPE_FIELD_NAME = 'cogType' -SYSTEM_COGTYPE_PICKLIST_NAME = "SystemCOGTypes" - -def update_cog_type_fields(apps): - Discipline = apps.get_model('specify', 'Discipline') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') - - # Revert COG -> children before adding to avoid duplicates - revert_table_field_schema_config('CollectionObjectGroup', 'children', apps) - # Add StorageTreeDef -> institution and COG -> children - for discipline in Discipline.objects.all(): - for table, fields in MIGRATION_0007_FIELDS.items(): - for field in fields: - update_table_field_schema_config_with_defaults(table, discipline.id, field, apps) - - # Remove COG -> cojo - revert_table_field_schema_config('CollectionObjectGroup', 'cojo', apps) - - # Remove duplicate CollectionObject -> collectionObjectType - container_items = Splocalecontaineritem.objects.filter( - name="collectionObjectType", - picklistname=None, - container__name="collectionobject", - ) - for container_item in container_items: - Splocaleitemstr.objects.filter(itemname=container_item).delete() - Splocaleitemstr.objects.filter(itemdesc=container_item).delete() - container_items.delete() - -# NOTE: The reverse function will not re-add the duplicate CO -> coType or COG -> cojo as its unnecessary -def revert_cog_type_fields(apps): - # Remove StorageTreeDef -> institution and COG -> children - for table, fields in MIGRATION_0007_FIELDS.items(): - for field in fields: - revert_table_field_schema_config(table, field, apps) - -def create_cogtype_picklist(apps): - Collection = apps.get_model('specify', 'Collection') - Picklist = apps.get_model('specify', 'Picklist') - - # Create a cogtype picklist for each collection - for collection in Collection.objects.all(): - Picklist.objects.update_or_create( - collection=collection, - name=COG_PICKLIST_NAME, - defaults={ - "type": 1, - "tablename": "collectionobjectgrouptype", - "issystem": True, - "readonly": True, - "sizelimit": -1, - "sorttype": 1, - "formatter": "CollectionObjectGroupType", - }, - ) - -def revert_cogtype_picklist(apps): - Picklist = apps.get_model('specify', 'Picklist') - - Picklist.objects.filter(name=COG_PICKLIST_NAME).delete() - - -# Updates COG -> cogtype to use the type 1 picklist created above -def update_cogtype_splocalecontaineritem(apps): - Splocalecontaineritem = apps.get_model("specify", "Splocalecontaineritem") - - Splocalecontaineritem.objects.filter( - container__name="collectionobjectgroup", - container__schematype=0, - name=COGTYPE_FIELD_NAME, - ).update(picklistname=COG_PICKLIST_NAME, type="ManyToOne", isrequired=True) - - -def revert_cogtype_splocalecontaineritem(apps): - Splocalecontaineritem = apps.get_model("specify", "Splocalecontaineritem") - - Splocalecontaineritem.objects.filter( - container__name="collectionobjectgroup", - container__schematype=0, - name=COGTYPE_FIELD_NAME, - ).update(picklistname=None, type=None, isrequired=None) - - -def update_systemcogtypes_picklist(apps): - Picklist = apps.get_model('specify', 'Picklist') - - Picklist.objects.filter(name='Default Collection Object Group Types').update( - name=SYSTEM_COGTYPE_PICKLIST_NAME, - type=0, - issystem=True, - readonly=True, - sizelimit=3, - tablename=None - ) - -def revert_systemcogtypes_picklist(apps): - Picklist = apps.get_model('specify', 'Picklist') - - # revert only changes the name and not the other attributes as those were incorrect - Picklist.objects.filter(name=SYSTEM_COGTYPE_PICKLIST_NAME).update( - name='Default Collection Object Group Types', - ) - - -# Updates cogtype -> type to use the Default COGType picklist (Drill Core, Discrete, Consolidated) -def update_cogtype_type_splocalecontaineritem(apps): - Splocalecontaineritem = apps.get_model("specify", "Splocalecontaineritem") - - Splocalecontaineritem.objects.filter( - container__name="collectionobjectgrouptype", - container__schematype=0, - name="type", - ).update(picklistname=SYSTEM_COGTYPE_PICKLIST_NAME, isrequired=True) - - -def revert_cogtype_type_splocalecontaineritem(apps): - Splocalecontaineritem = apps.get_model("specify", "Splocalecontaineritem") - - Splocalecontaineritem.objects.filter( - container__name="collectionobjectgrouptype", - container__schematype=0, - name="type", - ).update(picklistname=None, isrequired=None) - -# ########################################## -# Used in 0008_schema_config_update.py -# ########################################## - -def update_relative_age_fields(apps): - Discipline = apps.get_model('specify', 'Discipline') - - # Add absoluteAgeCitation -> absoluteAge & Add relativeAgeCitation -> relativeAge - for discipline in Discipline.objects.all(): - for table, fields in MIGRATION_0008_FIELDS.items(): - for field in fields: - update_table_field_schema_config_with_defaults(table, discipline.id, field, apps) - -def revert_relative_age_fields(apps): - # Remove absoluteAgeCitation -> absoluteAge and relativeAgeCitation -> relativeAge - for table, fields in MIGRATION_0008_FIELDS.items(): - for field in fields: - revert_table_field_schema_config(table, field, apps) - -# ########################################## -# Used in 0012_add_cojo_to_schema_config.py -# ########################################## - -def add_cojo_to_schema_config(apps): - Discipline = apps.get_model('specify', 'Discipline') - for discipline in Discipline.objects.all(): - for table, fields in MIGRATION_0012_FIELDS.items(): - for field in fields: - update_table_field_schema_config_with_defaults( - table, discipline.id, field, apps) - - -def remove_cojo_from_schema_config(apps): - for table, fields in MIGRATION_0012_FIELDS.items(): - for field in fields: - revert_table_field_schema_config(table, field, apps) - - -# ########################################## -# Used in 0013_collectionobjectgroup_parentcog.py -# ########################################## - -def update_cog_schema_config(apps): - revert_table_field_schema_config( - 'CollectionObjectGroup', 'parentCojo', apps) - revert_table_field_schema_config( - 'CollectionObjectGroup', 'parentCog', apps) - - Discipline = apps.get_model('specify', 'Discipline') - for discipline in Discipline.objects.all(): - for table, fields in MIGRATION_0013_FIELDS.items(): - for field in fields: - update_table_field_schema_config_with_defaults( - table, discipline.id, field, apps) - - -def revert_update_cog_schema_config(apps): - for table, fields in MIGRATION_0013_FIELDS.items(): - for field in fields: - revert_table_field_schema_config(table, field, apps) - - Discipline = apps.get_model('specify', 'Discipline') - for discipline in Discipline.objects.all(): - update_table_field_schema_config_with_defaults( - 'CollectionObjectGroup', discipline.id, 'parentCojo', apps) - -# ########################################## -# Used in 0015_add_version_to_ages.py -# ########################################## - -def update_age_schema_config(apps): - # Revert before adding to avoid duplicates - # BUG: This will delete people's potentially modified Schema Config items - # If we want to avoid duplicates, we should check the creation code and - # prevent duplicates being created there - # revert_update_age_schema_config(apps) - - Discipline = apps.get_model('specify', 'Discipline') - for discipline in Discipline.objects.all(): - update_table_field_schema_config_with_defaults('AbsoluteAge', discipline.id, 'version', apps) - update_table_field_schema_config_with_defaults('RelativeAge', discipline.id, 'version', apps) - -def revert_update_age_schema_config(apps): - revert_table_field_schema_config('AbsoluteAge', 'version', apps) - revert_table_field_schema_config('RelativeAge', 'version', apps) - -# ########################################## -# Used in 0017_schemaconfig_fixes.py -# ########################################## - -CONTAINER_MIGRATIONS = [MIGRATION_0002_TABLES, MIGRATION_0004_TABLES] - -CONTAINER_ITEM_MIGRATIONS = [ - MIGRATION_0004_FIELDS, - MIGRATION_0007_FIELDS, - MIGRATION_0008_FIELDS, - MIGRATION_0012_FIELDS, - MIGRATION_0013_FIELDS, -] - -def fix_table_captions(apps): - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') - - for migration in CONTAINER_MIGRATIONS: - for table_name, table_desc in migration: - table = datamodel.get_table(table_name) - - # BUG: The splocalecontainer related tables can still exist in the - # database, and this will result in skipping any operation if the - # table/field is removed, renamed, etc. - if table is None: - logger.warning(f"Table does not exist in latest state of the datamodel, skipping Schema Config update for: {table_name}") - continue - containers = Splocalecontainer.objects.filter( - name=table_name.lower(), schematype=0) - - # If needed, correct the label of the table in the schema config - if table_desc is not None: - Splocaleitemstr.objects.filter( - containername__in=containers, text=table_desc - ).update(text=camel_to_spaced_title_case(uncapitilize(table.name))) - - # Update the types for the fields in the table - items = Splocalecontaineritem.objects.filter( - container__in=containers) - for item in items: - datamodel_field = table.get_field(item.name) - if not datamodel_field: - continue - - item.type = datamodel_type_to_schematype( - datamodel_field.type) if datamodel_field.is_relationship else datamodel_field.type - item.isrequired = datamodel_field.required if item.isrequired is None else item.isrequired - - item.save() - - -def fix_item_types(apps): - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - - for migration in CONTAINER_ITEM_MIGRATIONS: - for table_name, fields in migration.items(): - table = datamodel.get_table(table_name) - # BUG: The splocalecontainer related tables can still exist in the - # database, and this will result in skipping any operation if the - # table/field is removed, renamed, etc. - if table is None: - logger.warning(f"Table does not exist in latest state of the datamodel, skipping Schema Config entry for: {table_name}") - continue - items = Splocalecontaineritem.objects.filter( - container__name=table_name.lower(), container__schematype=0, name__in=fields) - - for item in items: - datamodel_field = table.get_field(item.name) - if not datamodel_field: - continue - - item.type = datamodel_type_to_schematype( - datamodel_field.type) if datamodel_field.is_relationship else datamodel_field.type - item.isrequired = datamodel_field.required if item.isrequired is None else item.isrequired - - item.save() - - -def schemaconfig_fixes(apps, schema_editor=None): - fix_table_captions(apps) - fix_item_types(apps) - -# ########################################## -# Used in 0018_cot_catnum_schema.py -# ########################################## - -def add_cot_catnum_to_schema(apps, schema_editor=None): - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') - - CollectionObjectType_Table = datamodel.get_table_strict( - 'collectionobjecttype') - catalognumber_format_field = CollectionObjectType_Table.get_field_strict( - 'catalogNumberFormatName') - - for container in Splocalecontainer.objects.filter(name='collectionobjecttype', schematype=0): - schema_item, created = Splocalecontaineritem.objects.get_or_create( - name=catalognumber_format_field.name, type=catalognumber_format_field.type, container=container) - if created: - schema_item.version = 0 - - schema_item.isrequired = ( - catalognumber_format_field.required - if schema_item.isrequired is None - else schema_item.isrequired - ) - - schema_item.save() - - schema_name = camel_to_spaced_title_case( - catalognumber_format_field.name) - Splocaleitemstr.objects.get_or_create( - language='en', text=schema_name, itemname=schema_item) - Splocaleitemstr.objects.get_or_create( - language='en', text=schema_name, itemdesc=schema_item) - -def remove_cot_catnum_from_schema(apps, schema_editor=None): - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') - - CollectionObjectType_Table = datamodel.get_table_strict( - 'collectionobjecttype') - catalognumber_format_field = CollectionObjectType_Table.get_field_strict( - 'catalogNumberFormatName') - - containers = Splocalecontainer.objects.filter( - name='collectionobjecttype', schematype=0) - items = Splocalecontaineritem.objects.filter( - name='catalogNumberFormatName', container__in=containers) - - schema_name = camel_to_spaced_title_case(catalognumber_format_field.name) - filters = Q(language='en', text=schema_name) & ( - Q(itemname__in=items) | Q(itemdesc__in=items)) - locale_strings = Splocaleitemstr.objects.filter(filters) - - locale_strings.delete() - items.delete() - -# ########################################## -# Used in 0020_add_tectonicunit_to_pc_in_schema_config.py -# ########################################## - -def add_tectonicunit_to_pc_in_schema_config(apps): - Discipline = apps.get_model('specify', 'Discipline') - for discipline in Discipline.objects.all(): - for table, fields in MIGRATION_0020_FIELDS.items(): - for field in fields: - update_table_field_schema_config_with_defaults( - table, discipline.id, field, apps) - -def remove_tectonicunit_from_pc_schema_config(apps): - for table, fields in MIGRATION_0020_FIELDS.items(): - for field in fields: - revert_table_field_schema_config(table, field, apps) - -# ########################################## -# Used in 0021_update_hidden_geo_tables.py -# ########################################## - -def fix_hidden_geo_prop(apps, schema_editor=None): - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - Discipline = apps.get_model('specify', 'Discipline') - - excluded_disciplines = PALEO_DISCIPLINES | GEOLOGY_DISCIPLINES - - filtered_disciplines = Discipline.objects.exclude(type__in=excluded_disciplines) - - for discipline in filtered_disciplines: - for table, fields in MIGRATION_0021_FIELDS.items(): - containers = Splocalecontainer.objects.filter( - name=table.lower(), - discipline_id=discipline.id, - ) - for container in containers: - # BUG: What if the user wants the field unhidden? - Splocalecontaineritem.objects.filter( - container=container, - name__in=tuple(map(lambda field_name: field_name.lower(), fields)) - ).update(ishidden=True) - -def reverse_fix_hidden_geo_prop(apps, schema_editor=None): - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - Discipline = apps.get_model('specify', 'Discipline') - - excluded_disciplines = PALEO_DISCIPLINES | GEOLOGY_DISCIPLINES - - filtered_disciplines = Discipline.objects.exclude(type__in=excluded_disciplines) - - for discipline in filtered_disciplines: - for table, fields in MIGRATION_0021_FIELDS.items(): - containers = Splocalecontainer.objects.filter( - name=table.lower(), - discipline_id=discipline.id, - ) - for container in containers: - # BUG: What if the user wants the field hidden? - Splocalecontaineritem.objects.filter( - container=container, - name__in=tuple(map(lambda field_name: field_name.lower(), fields)) - ).update(ishidden=False) - -# ########################################## -# Used in 0023_update_schema_config_text.py -# ########################################## - -def update_schema_config_field_desc(apps, schema_editor=None): - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') - - for table, fields in MIGRATION_0023_FIELDS.items(): - #i.e: Collection Object - containers = Splocalecontainer.objects.filter( - name=table.lower(), - ) - - for container in containers: - for field_name, new_name, new_desc in fields: - #i.e: COType - items = Splocalecontaineritem.objects.filter( - container=container, - name__iexact=field_name - ) - - for item in items: - localized_items_desc = Splocaleitemstr.objects.filter(itemdesc_id=item.id).first() - localized_items_name = Splocaleitemstr.objects.filter(itemname_id=item.id).first() - - if localized_items_desc is None or localized_items_name is None: - continue - - localized_items_desc.text = new_desc - localized_items_desc.save() - - localized_items_name.text = new_name - localized_items_name.save() - -def update_hidden_prop(apps, schema_editor=None): - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') - Discipline = apps.get_model('specify', 'Discipline') - discipline_types_by_id = dict(Discipline.objects.values_list("id", "type")) - - for table, fields in MIGRATION_0023_FIELDS_BIS.items(): - field_names = [field_name.lower() for field_name in fields] - field_name_set = set(field_names) - containers = Splocalecontainer.objects.filter( - name=table.lower(), - schematype=0 - ) - for container in containers: - discipline_type = discipline_types_by_id.get(container.discipline_id, "") - explicit_hidden_overrides = { - field_name: ishidden - for field_name, ishidden in _schema_override_hidden_values_for_discipline( - discipline_type - ).get(table.lower(), {}).items() - if field_name in field_name_set - } - explicit_fields_to_hide = [ - field_name - for field_name, ishidden in explicit_hidden_overrides.items() - if ishidden - ] - explicit_fields_to_show = [ - field_name - for field_name, ishidden in explicit_hidden_overrides.items() - if not ishidden - ] - - if explicit_fields_to_hide: - Splocalecontaineritem.objects.filter( - container=container, - ishidden=False, - name__in=explicit_fields_to_hide, - ).update(ishidden=True) - - if explicit_fields_to_show: - Splocalecontaineritem.objects.filter( - container=container, - ishidden=True, - name__in=explicit_fields_to_show, - ).update(ishidden=False) - - fields_to_hide = _fields_without_explicit_hidden_override( - table, - field_names, - discipline_type, - ) - if not fields_to_hide: - continue - - items_updated = Splocalecontaineritem.objects.filter( - container=container, - ishidden=False, - name__in=fields_to_hide - ).update(ishidden=True) - if items_updated > 0: - logger.info(f"Hid {items_updated} items for table {table} and container {container.id}") - - duplicates = ( - Splocalecontaineritem.objects.values("container", "name") - .annotate(count=Count("id")) - .filter(count__gt=1) - ) - for duplicate in duplicates: - container_id = duplicate['container'] - name = duplicate['name'] - duplicate_items = Splocalecontaineritem.objects.filter(container_id=container_id, name=name) - item_to_keep = duplicate_items.first() - items_to_delete = duplicate_items.exclude(id=item_to_keep.id) - - Splocaleitemstr.objects.filter(itemdesc_id__in=items_to_delete).update(itemdesc_id=item_to_keep.id) - Splocaleitemstr.objects.filter(itemname_id__in=items_to_delete).update(itemname_id=item_to_keep.id) - items_to_delete.delete() - -def reverse_update_hidden_prop(apps, schema_editor=None): - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - Discipline = apps.get_model('specify', 'Discipline') - discipline_types_by_id = dict(Discipline.objects.values_list("id", "type")) - - for table, fields in MIGRATION_0023_FIELDS_BIS.items(): - field_names = [field_name.lower() for field_name in fields] - containers = Splocalecontainer.objects.filter( - name=table.lower(), - ) - for container in containers: - discipline_type = discipline_types_by_id.get(container.discipline_id, "") - fields_to_unhide = _fields_without_explicit_hidden_override( - table, - field_names, - discipline_type, - ) - if not fields_to_unhide: - continue - - items = Splocalecontaineritem.objects.filter( - container=container, - name__in=fields_to_unhide - ) - logger.info(f"Reverting {items.count()} items for table {table} and container {container.id}") - items.update(ishidden=False) - -def reverse_update_schema_config_field_desc(apps, schema_editor=None): - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') - - for table, fields in MIGRATION_0023_FIELDS.items(): - containers = Splocalecontainer.objects.filter( - name=table.lower(), - ) - - for container in containers: - for field_name, new_name, new_desc in fields: - items = Splocalecontaineritem.objects.filter( - container=container, - name=field_name.lower() - ) - - for item in items: - localized_items_desc = Splocaleitemstr.objects.filter(itemdesc_id=item.id).first() - localized_items_name = Splocaleitemstr.objects.filter(itemname_id=item.id).first() - - if localized_items_desc is None or localized_items_name is None: - continue - - localized_items_desc.text = item.name - localized_items_desc.save() - - localized_items_name.text = item.name - localized_items_name.save() - -# ########################################## -# Used in 0024_add_uniqueIdentifier_storage.py -# ########################################## - -def update_storage_unique_id_fields(apps): - Discipline = apps.get_model('specify', 'Discipline') - - # Add uniqueIdentifier -> storage - for discipline in Discipline.objects.all(): - for table, fields in MIGRATION_0024_FIELDS.items(): - for field in fields: - update_table_field_schema_config_with_defaults(table, discipline.id, field, apps) - -def revert_storage_unique_id_fields(apps): - # Remove uniqueIdentifier -> storage - for table, fields in MIGRATION_0024_FIELDS.items(): - for field in fields: - revert_table_field_schema_config(table, field, apps) - -# ########################################## -# Used in 0027_CO_children.py -# ########################################## - -def update_co_children_fields(apps): - def update_discipline_fields(apps): - Discipline = apps.get_model('specify', 'Discipline') - - for discipline in Discipline.objects.all(): - for table, fields in MIGRATION_0027_FIELDS.items(): - for field in fields: - update_table_field_schema_config_with_defaults(table, discipline.id, field, apps) - - def update_schema_config_field_desc(apps): - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') - - for table, fields in MIGRATION_0027_UPDATE_FIELDS.items(): - #i.e: Collection Object - containers = Splocalecontainer.objects.filter( - name=table.lower(), - ) - - for container in containers: - for field_name, new_name, new_desc in fields: - #i.e: COType - items = Splocalecontaineritem.objects.filter( - container=container, - name__iexact=field_name - ) - - for item in items: - localized_items_desc = Splocaleitemstr.objects.filter(itemdesc_id=item.id).first() - localized_items_name = Splocaleitemstr.objects.filter(itemname_id=item.id).first() - - if localized_items_desc is None or localized_items_name is None: - continue - - localized_items_desc.text = new_desc - localized_items_desc.save() - - localized_items_name.text = new_name - localized_items_name.save() - - update_discipline_fields(apps) - update_schema_config_field_desc(apps) - -def revert_co_children_fields(apps): - def revert_update_fields(apps): - for table, fields in MIGRATION_0027_FIELDS.items(): - for field in fields: - revert_table_field_schema_config(table, field, apps) - - def revert_update_schema_field(apps): - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - - for table, fields in MIGRATION_0027_UPDATE_FIELDS.items(): - containers = Splocalecontainer.objects.filter( - name=table.lower(), - ) - for container in containers: - for field_name in fields: - items = Splocalecontaineritem.objects.filter( - container=container, - name=field_name - ) - - for item in items: - item.ishidden = False - item.save() - - revert_update_fields(apps) - revert_update_schema_field(apps) - -# ########################################## -# Used in 0029_remove_collectionobject_parentco.py -# ########################################## - -def remove_collectionobject_parentco(apps): - def update_fields(apps): - Discipline = apps.get_model('specify', 'Discipline') - - for discipline in Discipline.objects.all(): - for table, fields in MIGRATION_0029_FIELDS.items(): - for field in fields: - update_table_field_schema_config_with_defaults(table, discipline.id, field, apps) - - def update_schema_config_field_desc(apps): - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') - - for table, fields in MIGRATION_0029_UPDATE_FIELDS.items(): - #i.e: Collection Object - containers = Splocalecontainer.objects.filter( - name=table.lower(), - ) - - for container in containers: - for field_name, new_name, new_desc in fields: - #i.e: COType - items = Splocalecontaineritem.objects.filter( - container=container, - name__iexact=field_name - ) - - for item in items: - localized_items_desc = Splocaleitemstr.objects.filter(itemdesc_id=item.id).first() - localized_items_name = Splocaleitemstr.objects.filter(itemname_id=item.id).first() - - if localized_items_desc is None or localized_items_name is None: - continue - - localized_items_desc.text = new_desc - localized_items_desc.save() - - localized_items_name.text = new_name - localized_items_name.save() - - def hide_co_component(apps): - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - Discipline = apps.get_model('specify', 'Discipline') - - disciplines = Discipline.objects.all() - - for discipline in disciplines: - for table, fields in MIGRATION_0029_UPDATE_FIELDS.items(): - containers = Splocalecontainer.objects.filter( - name=table.lower(), - discipline_id=discipline.id, - ) - for container in containers: - for field_name, _, _ in fields: - items = Splocalecontaineritem.objects.filter( - container=container, - name=field_name.lower() - ) - - for item in items: - item.ishidden = True - item.save() - - update_fields(apps) - update_schema_config_field_desc(apps) - hide_co_component(apps) - -def revert_remove_collectionobject_parentco(apps): - def revert_update_fields(apps): - for table, fields in MIGRATION_0029_FIELDS.items(): - for field in fields: - revert_table_field_schema_config(table, field, apps) - - def revert_update_schema_field(apps): - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - - for table, fields in MIGRATION_0029_UPDATE_FIELDS.items(): - containers = Splocalecontainer.objects.filter( - name=table.lower(), - ) - for container in containers: - for field_name in fields: - items = Splocalecontaineritem.objects.filter( - container=container, - name=field_name - ) - - for item in items: - item.ishidden = False - item.save() - - def reverse_hide_co_component(apps): - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - Discipline = apps.get_model('specify', 'Discipline') - - disciplines = Discipline.objects.all() - - for discipline in disciplines: - for table, fields in MIGRATION_0029_UPDATE_FIELDS.items(): - containers = Splocalecontainer.objects.filter( - name=table.lower(), - discipline_id=discipline.id, - ) - for container in containers: - for field_name, _, _ in fields: - items = Splocalecontaineritem.objects.filter( - container=container, - name=field_name.lower() - ) - - for item in items: - item.ishidden = False - item.save() - - revert_update_fields(apps) - revert_update_schema_field(apps) - reverse_hide_co_component(apps) - -# ########################################## -# Used in 0032_add_quantities_gift.py -# ########################################## - -def add_quantities_gift(apps): - def update_fields(apps): - Discipline = apps.get_model('specify', 'Discipline') - - for discipline in Discipline.objects.all(): - for table, fields in MIGRATION_0032_FIELDS.items(): - for field in fields: - update_table_field_schema_config_with_defaults(table, discipline.id, field, apps) - - def update_schema_config_field_desc(apps): - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') - - for table, fields in MIGRATION_0032_UPDATE_FIELDS.items(): - #i.e: Collection Object - containers = Splocalecontainer.objects.filter( - name=table.lower(), - ) - - for container in containers: - for field_name, new_name, new_desc in fields: - #i.e: COType - items = Splocalecontaineritem.objects.filter( - container=container, - name__iexact=field_name - ) - - for item in items: - localized_items_desc = Splocaleitemstr.objects.filter(itemdesc_id=item.id).first() - localized_items_name = Splocaleitemstr.objects.filter(itemname_id=item.id).first() - - if localized_items_desc is None or localized_items_name is None: - continue - - localized_items_desc.text = new_desc - localized_items_desc.save() - - localized_items_name.text = new_name - localized_items_name.save() - - update_fields(apps) - update_schema_config_field_desc(apps) - -def revert_add_quantities_gift(apps): - def revert_update_fields(apps): - for table, fields in MIGRATION_0032_FIELDS.items(): - for field in fields: - revert_table_field_schema_config(table, field, apps) - - def revert_update_schema_field(apps): - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - - for table, fields in MIGRATION_0032_UPDATE_FIELDS.items(): - containers = Splocalecontainer.objects.filter( - name=table.lower(), - ) - for container in containers: - for field_name in fields: - items = Splocalecontaineritem.objects.filter( - container=container, - name=field_name - ) - - for item in items: - item.ishidden = False - item.save() - - revert_update_fields(apps) - revert_update_schema_field(apps) - -# ########################################## -# Used in 0033_update_paleo_desc.py -# ########################################## - -def update_paleo_desc(apps): - def fix_table_description(apps): - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') - - for table_name, table_desc in MIGRATION_0033_TABLES: - containers = Splocalecontainer.objects.filter(name=table_name.lower(), schematype=0) - Splocaleitemstr.objects.filter(containerdesc__in=containers).update(text=table_desc) - - fix_table_description(apps) - -# ########################################## -# Used in 0034_accession_date_fields.py -# ########################################## - -def update_accession_date_fields(apps): - def update_0034_fields(apps): - """ - Update table-field schema entries for plain field names - (e.g., MIGRATION_0034_FIELDS). - """ - Discipline = apps.get_model('specify', 'Discipline') - for discipline in Discipline.objects.all(): - for table, fields in MIGRATION_0034_FIELDS.items(): - for field_name in fields: - update_table_field_schema_config_with_defaults(table, discipline.id, field_name, apps) - - def update_0034_schema_config_field_desc(apps): - """ - Update field descriptions and display names using MIGRATION_0034_UPDATE_FIELDS - (tuple: (fieldName, newLabel, newDesc)). - """ - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') - - for table, fields in MIGRATION_0034_UPDATE_FIELDS.items(): - containers = Splocalecontainer.objects.filter(name=table.lower()) - for container in containers: - for (field_name, new_name, new_desc) in fields: - items = Splocalecontaineritem.objects.filter( - container=container, - name__iexact=field_name - ) - for item in items: - item.ishidden = True - item.save() - desc_str = Splocaleitemstr.objects.filter(itemdesc_id=item.id).first() - name_str = Splocaleitemstr.objects.filter(itemname_id=item.id).first() - if desc_str is not None: - desc_str.text = new_desc - desc_str.save() - if name_str is not None: - name_str.text = new_name - name_str.save() - - update_0034_fields(apps) - update_0034_schema_config_field_desc(apps) - -def revert_update_accession_date_fields(apps): - def revert_0034_fields(apps): - """ - Revert table-field entries for plain field names. - """ - for table, fields in MIGRATION_0034_FIELDS.items(): - for field_name in fields: - revert_table_field_schema_config(table, field_name, apps) - - def revert_0034_schema_config_field_desc(apps): - """ - Revert the field name/description updates. - """ - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - - for table, fields in MIGRATION_0034_UPDATE_FIELDS.items(): - containers = Splocalecontainer.objects.filter(name=table.lower()) - for container in containers: - for (field_name, _, _) in fields: - items = Splocalecontaineritem.objects.filter( - container=container, - name__iexact=field_name - ) - # If needed, reset ishidden or revert text - - revert_0034_fields(apps) - revert_0034_schema_config_field_desc(apps) - -# ########################################## -# Used in 0035_version_required.py -# ########################################## - -def update_version_required(apps): - Discipline = apps.get_model('specify', 'Discipline') - updated_config_params = { - 'isrequired': False, - } - - # Update the schema config for each discipline with the version isHidden change - for discipline in Discipline.objects.all(): - for table, fields in MIGRATION_0035_FIELDS.items(): - for field in fields: - update_table_field_schema_config_params(table, discipline.id, field, updated_config_params, apps) - -def revert_version_required(apps): - Discipline = apps.get_model('specify', 'Discipline') - updated_config_params = { - 'isrequired': True, - } - - # Revert the schema config for each discipline with the version isHidden change - for discipline in Discipline.objects.all(): - for table, fields in MIGRATION_0035_FIELDS.items(): - for field in fields: - update_table_field_schema_config_params(table, discipline.id, field, updated_config_params, apps) - -# ########################################## -# Used in 0039_agent_fields_for_loan_and_gift.py -# ########################################## - -def update_loan_and_gift_agent_fields(apps): - Discipline = apps.get_model('specify', 'Discipline') - field_defaults = { - "ishidden": True - } - for discipline in Discipline.objects.all(): - for table, fields in MIGRATION_0039_FIELDS.items(): - for field_name in fields: - update_table_field_schema_config_with_defaults(table, discipline.id, field_name, apps, defaults=field_defaults) - -def revert_loan_and_gift_agent_fields(apps): - for table, fields in MIGRATION_0039_FIELDS.items(): - for field_name in fields: - revert_table_field_schema_config(table, field_name, apps) - -# ########################################## -# Used in 0040_components.py -# ########################################## - -def remove_componentparent_item(apps): - revert_table_field_schema_config("CollectionObject", "componentParent", apps) - -def remove_0029_schema_config_fields(apps, schema_editor=None): - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') - - FIELDS_TO_REMOVE = MIGRATION_0029_UPDATE_FIELDS - for table, fields in FIELDS_TO_REMOVE.items(): - items = Splocalecontaineritem.objects.filter( - container__name=table.lower(), - container__schematype=0, - # we only need the field name from the tuple of Schema Config information - name__in=list(map(lambda f: f[0].lower(), fields)) - ) - - # Delete field labels (captions) and descriptions (Splocaleitemstr) associated with the fields - Splocaleitemstr.objects.filter( - Q(itemdesc__in=items) | Q(itemname__in=items) - ).delete() - - items.delete() - -def create_table_schema_config_with_defaults(apps, schema_editor=None): - Discipline = apps.get_model('specify', 'Discipline') - for discipline in Discipline.objects.all(): - for table, desc in MIGRATION_0040_TABLES: - update_table_schema_config_with_defaults(table, discipline.id, desc, apps) - - for table, fields in MIGRATION_0040_FIELDS.items(): - for field in fields: - update_table_field_schema_config_with_defaults(table, discipline.id, field, apps) - -def update_schema_config_field_desc_for_components(apps, schema_editor=None): - Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') - - for table, fields in MIGRATION_0040_UPDATE_FIELDS.items(): - for field_name, new_name, new_desc in fields: - - Splocaleitemstr.objects.filter( - itemdesc__container__name=table.lower(), - itemdesc__container__schematype=0, - itemdesc__name=field_name.lower(), - language="en", - ).update(text=new_desc) - - Splocaleitemstr.objects.filter( - itemname__container__name=table.lower(), - itemname__container__schematype=0, - itemname__name=field_name.lower(), - language="en", - ).update(text=new_name) - -def update_hidden_prop_for_compoenents(apps, schema_editor=None): - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - - for table, fields in MIGRATION_0040_FIELDS.items(): - Splocalecontaineritem.objects.filter( - container__name=table.lower(), - container__schematype=0, - name__in=list(map(lambda f: f.lower(), fields)) - ).update(ishidden=True) - -def create_cotype_splocalecontaineritem_for_components(apps): - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - PICKLIST_NAME = 'CollectionObjectType' - FIELD_NAME = 'type' - - # Create a Splocalecontaineritem record for each Component Splocalecontainer - # NOTE: Each discipline has its own Component Splocalecontainer - Splocalecontaineritem.objects.filter( - container__name='component', - container__schematype=0, - name=FIELD_NAME - ).update( - picklistname=PICKLIST_NAME, - isrequired=True, - type='ManyToOne', - ) - -def hide_component_fields(apps, schema_editor=None): - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - - for table, fields in MIGRATION_0040_HIDDEN_FIELDS.items(): - Splocalecontaineritem.objects.filter( - container__name=table.lower(), - container__schematype=0, - name__in=list(map(lambda f: f.lower(), fields)) - ).update(ishidden=True) - -def restore_0029_schema_config_fields(apps, schema_editor=None): - Discipline = apps.get_model('specify', 'Discipline') - FIELDS_TO_REMOVE = MIGRATION_0029_UPDATE_FIELDS - for discipline in Discipline.objects.all(): - for table, fields in FIELDS_TO_REMOVE.items(): - for field_name, _, _ in fields: - update_table_field_schema_config_with_defaults(table, discipline.id, field_name, apps) - -def revert_table_schema_config_with_defaults(apps, schema_editor=None): - for table, _ in MIGRATION_0040_TABLES: - revert_table_schema_config(table, apps) - for table, fields in MIGRATION_0040_FIELDS.items(): - for field in fields: - revert_table_field_schema_config(table, field, apps) - -def reverse_hide_component_fields(apps, schema_editor=None): - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - Discipline = apps.get_model('specify', 'Discipline') - - for discipline in Discipline.objects.all(): - for table, fields in MIGRATION_0040_HIDDEN_FIELDS.items(): - containers = Splocalecontainer.objects.filter( - name=table.lower(), - discipline_id=discipline.id, - ) - for container in containers: - for field_name in fields: - items = Splocalecontaineritem.objects.filter( - container=container, - name=field_name.lower() - ) - items.update(ishidden=False) - -# ########################################## -# Used in 0042_discipline_type_picklist.py -# ########################################## - -from specifyweb.backend.context.app_resource import DISCIPLINE_NAMES - -DISCIPLINE_TYPE_PICKLIST_NAME = 'DisciplineType' - -def create_discipline_type_picklist(apps): - Collection = apps.get_model('specify', 'Collection') - Picklist = apps.get_model('specify', 'Picklist') - Picklistitem = apps.get_model('specify', 'Picklistitem') - - def batch_iterable[T](iterable: Iterable[T], batch_size: int): - """ - A generator that takes any Iterable and yields tuples containing up to - batch_size elements until the iterable is exhausted. - - This is useful when you want to perform some operation over all - elements in the iterable, but the operation is memory intensive and can - be batched. - - Example: - ```py - example = [1, 2, 3] - for batched in batch_iterable(example, 2): - print(batched) - # prints (1, 2) then (3,) - ``` - """ - iterator = iter(iterable) - while batch := tuple(islice(iterator, batch_size)): - yield batch - - collections_missing_picklist = Collection.objects.annotate( - has_existing_picklist=Exists( - Picklist.objects.filter( - collection=OuterRef("pk"), - name=DISCIPLINE_TYPE_PICKLIST_NAME, - type=0 - ) - ) - ).filter( - has_existing_picklist=False - ).values_list("pk", flat=True).iterator(chunk_size=1000) - - COLLECTION_BATCH_SIZE=200 - - for collection_ids in batch_iterable(collections_missing_picklist, COLLECTION_BATCH_SIZE): - created_picklists = Picklist.objects.bulk_create( - [ - Picklist( - collection_id=collection_id, - name=DISCIPLINE_TYPE_PICKLIST_NAME, - type=0, - issystem=True, - readonly=True, - sizelimit=-1, - sorttype=1 - ) - for collection_id in collection_ids - ], - batch_size=COLLECTION_BATCH_SIZE - ) - - Picklistitem.objects.bulk_create( - [ - Picklistitem( - picklist=picklist, - value=value, - title=title, - ordinal=ordinal - ) - for ordinal, (value, title) in enumerate(DISCIPLINE_NAMES.items(), start=1) - for picklist in created_picklists - ] - ) - -def revert_discipline_type_picklist(apps): - Picklist = apps.get_model('specify', 'Picklist') - - Picklist.objects.filter(name=DISCIPLINE_TYPE_PICKLIST_NAME).delete() - -def update_discipline_type_splocalecontaineritem(apps): - Splocalecontaineritem = apps.get_model("specify", "Splocalecontaineritem") - - Splocalecontaineritem.objects.filter( - container__name="discipline", - container__schematype=0, - name="type", - ).update( - picklistname=DISCIPLINE_TYPE_PICKLIST_NAME, - isrequired=True - ) - -def revert_discipline_type_splocalecontaineritem(apps): - Splocalecontaineritem = apps.get_model("specify", "Splocalecontaineritem") - - Splocalecontaineritem.objects.filter( - container__name="discipline", - picklistname=DISCIPLINE_TYPE_PICKLIST_NAME, - container__schematype=0, - name="type", - ).update( - picklistname=None - ) From 4a208b18d71fa68ece52987e51680a92a6d3c460 Mon Sep 17 00:00:00 2001 From: CarolineDenis Date: Thu, 18 Jun 2026 15:35:38 +0200 Subject: [PATCH 093/113] fix: remove unused file/definition --- .../specify/migration_utils/migration_helpers.py | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 specifyweb/specify/migration_utils/migration_helpers.py diff --git a/specifyweb/specify/migration_utils/migration_helpers.py b/specifyweb/specify/migration_utils/migration_helpers.py deleted file mode 100644 index 1a84f519df6..00000000000 --- a/specifyweb/specify/migration_utils/migration_helpers.py +++ /dev/null @@ -1,16 +0,0 @@ -from specifyweb.specify.migration_utils.schema_writer import ( - update_table_schema_config_with_defaults, -) -from specifyweb.specify.models import datamodel - -#TODO: This is not used, can we remove? -# ############################################################################## -# Migration schema config helper functions -# ############################################################################## - -def update_all_table_schema_config_with_defaults(apps): - Discipline = apps.get_model('specify', 'Discipline') - for discipline in Discipline.objects.all(): - for table in datamodel.tables: - update_table_schema_config_with_defaults(table.name, discipline.id, None, apps) - From 0be0c123acaab76710770a8604cc6c2bc0b01a37 Mon Sep 17 00:00:00 2001 From: melton-jason Date: Thu, 18 Jun 2026 16:39:31 -0500 Subject: [PATCH 094/113] fix: imports and performance for 0004 migration --- .../commands/run_key_migration_functions.py | 1 - .../helper_0003_cotype_picklist.py | 2 +- .../helper_0004_stratigraphy_age.py | 47 ++++++++++----- .../helper_0018_cot_catnum_schema.py | 4 +- .../helper_0042_discipline_type_picklist.py | 33 ++--------- specifyweb/specify/migration_utils/utils.py | 59 +++++++++++++++++++ .../migrations/0004_stratigraphy_age.py | 16 ++--- 7 files changed, 107 insertions(+), 55 deletions(-) create mode 100644 specifyweb/specify/migration_utils/utils.py diff --git a/specifyweb/specify/management/commands/run_key_migration_functions.py b/specifyweb/specify/management/commands/run_key_migration_functions.py index ef281eb29ba..50a60de072d 100644 --- a/specifyweb/specify/management/commands/run_key_migration_functions.py +++ b/specifyweb/specify/management/commands/run_key_migration_functions.py @@ -20,7 +20,6 @@ set_discipline_for_taxon_treedefs ) from specifyweb.backend.permissions.initialize import initialize -from specifyweb.specify.migration_utils import migration_helpers as usc from specifyweb.specify.migration_utils.deduplication import deduplicate_schema_config_orm from specifyweb.specify.migration_utils.migration_helpers.helper_0002_schema_config_update import create_geo_table_schema_config_with_defaults from specifyweb.specify.migration_utils.migration_helpers.helper_0003_cotype_picklist import create_cotype_splocalecontaineritem diff --git a/specifyweb/specify/migration_utils/migration_helpers/helper_0003_cotype_picklist.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0003_cotype_picklist.py index 401c4e26eb9..2ec230b7ceb 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/helper_0003_cotype_picklist.py +++ b/specifyweb/specify/migration_utils/migration_helpers/helper_0003_cotype_picklist.py @@ -50,4 +50,4 @@ def create_cotype_splocalecontaineritem(apps): field_desc = Splocaleitemstr.objects.filter(**field_desc_attrs).order_by("id").first() if field_desc is None: - Splocaleitemstr.objects.create(**field_desc_attrs, text=COT_TEXT) \ No newline at end of file + Splocaleitemstr.objects.create(**field_desc_attrs, text=COT_TEXT) diff --git a/specifyweb/specify/migration_utils/migration_helpers/helper_0004_stratigraphy_age.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0004_stratigraphy_age.py index b2a92034ff2..fb8dd76f3ee 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/helper_0004_stratigraphy_age.py +++ b/specifyweb/specify/migration_utils/migration_helpers/helper_0004_stratigraphy_age.py @@ -1,3 +1,4 @@ +from specifyweb.specify.migration_utils.utils import batch_query from specifyweb.specify.migration_utils.schema_writer import revert_table_field_schema_config, revert_table_schema_config, update_table_field_schema_config_with_defaults, update_table_schema_config_with_defaults # ########################################## @@ -38,25 +39,39 @@ def create_agetype_picklist(apps): Picklist = apps.get_model('specify', 'Picklist') PicklistItem = apps.get_model('specify', 'Picklistitem') - for collection in Collection.objects.all(): - age_type_picklist, created = Picklist.objects.get_or_create( - name=AGETYPE_PICKLIST_NAME, - type=0, - collection_id=collection.id, - defaults={ - "issystem": False, - "readonly": False, - "sizelimit": -1, - "sorttype": 1, - } + collections_missing_picklist = Collection.objects.exclude( + picklists__name=AGETYPE_PICKLIST_NAME, + picklists__type=0 + ).values_list("pk", flat=True) + + for collection_ids in batch_query(collections_missing_picklist): + created_picklists = Picklist.objects.bulk_create( + [ + Picklist( + name=AGETYPE_PICKLIST_NAME, + type=0, + collection_id=collection_id, + issystem=False, + readonly=False, + sizelimit=-1, + sorttype=1 + ) + for collection_id in collection_ids + ] ) - if created: - for age_type in DEFAULT_AGE_TYPES: - PicklistItem.objects.get_or_create( + + PicklistItem.objects.bulk_create( + [ + PicklistItem( title=age_type, value=age_type, - picklist=age_type_picklist + picklist=picklist ) + for age_type in DEFAULT_AGE_TYPES + for picklist in created_picklists + ], + batch_size=1000 + ) def create_strat_table_schema_config_with_defaults(apps): Discipline = apps.get_model('specify', 'Discipline') @@ -73,4 +88,4 @@ def revert_strat_table_schema_config_with_defaults(apps): revert_table_schema_config(table, apps) for table, fields in MIGRATION_0004_FIELDS.items(): for field in fields: - revert_table_field_schema_config(table, field, apps) \ No newline at end of file + revert_table_field_schema_config(table, field, apps) diff --git a/specifyweb/specify/migration_utils/migration_helpers/helper_0018_cot_catnum_schema.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0018_cot_catnum_schema.py index 6814e610afa..39e922bd4a5 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/helper_0018_cot_catnum_schema.py +++ b/specifyweb/specify/migration_utils/migration_helpers/helper_0018_cot_catnum_schema.py @@ -1,3 +1,5 @@ +from django.db.models import Q + from specifyweb.specify.migration_utils.schema_reader import camel_to_spaced_title_case from specifyweb.specify.models import datamodel @@ -57,4 +59,4 @@ def remove_cot_catnum_from_schema(apps, schema_editor=None): locale_strings = Splocaleitemstr.objects.filter(filters) locale_strings.delete() - items.delete() \ No newline at end of file + items.delete() diff --git a/specifyweb/specify/migration_utils/migration_helpers/helper_0042_discipline_type_picklist.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0042_discipline_type_picklist.py index 32a66f7e6c4..063b0919207 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/helper_0042_discipline_type_picklist.py +++ b/specifyweb/specify/migration_utils/migration_helpers/helper_0042_discipline_type_picklist.py @@ -2,11 +2,10 @@ # ########################################## # Used in 0042_discipline_type_picklist.py # ########################################## -from typing import Iterable -from itertools import islice from django.db.models import Exists, OuterRef +from specifyweb.specify.migration_utils.utils import batch_query from specifyweb.backend.context.app_resource import DISCIPLINE_NAMES DISCIPLINE_TYPE_PICKLIST_NAME = 'DisciplineType' @@ -16,27 +15,6 @@ def create_discipline_type_picklist(apps): Picklist = apps.get_model('specify', 'Picklist') Picklistitem = apps.get_model('specify', 'Picklistitem') - def batch_iterable[T](iterable: Iterable[T], batch_size: int): - """ - A generator that takes any Iterable and yields tuples containing up to - batch_size elements until the iterable is exhausted. - - This is useful when you want to perform some operation over all - elements in the iterable, but the operation is memory intensive and can - be batched. - - Example: - ```py - example = [1, 2, 3] - for batched in batch_iterable(example, 2): - print(batched) - # prints (1, 2) then (3,) - ``` - """ - iterator = iter(iterable) - while batch := tuple(islice(iterator, batch_size)): - yield batch - collections_missing_picklist = Collection.objects.annotate( has_existing_picklist=Exists( Picklist.objects.filter( @@ -47,11 +25,9 @@ def batch_iterable[T](iterable: Iterable[T], batch_size: int): ) ).filter( has_existing_picklist=False - ).values_list("pk", flat=True).iterator(chunk_size=1000) + ).values_list("pk", flat=True) - COLLECTION_BATCH_SIZE=200 - - for collection_ids in batch_iterable(collections_missing_picklist, COLLECTION_BATCH_SIZE): + for collection_ids in batch_query(collections_missing_picklist): created_picklists = Picklist.objects.bulk_create( [ Picklist( @@ -64,8 +40,7 @@ def batch_iterable[T](iterable: Iterable[T], batch_size: int): sorttype=1 ) for collection_id in collection_ids - ], - batch_size=COLLECTION_BATCH_SIZE + ] ) Picklistitem.objects.bulk_create( diff --git a/specifyweb/specify/migration_utils/utils.py b/specifyweb/specify/migration_utils/utils.py new file mode 100644 index 00000000000..152340b8e7b --- /dev/null +++ b/specifyweb/specify/migration_utils/utils.py @@ -0,0 +1,59 @@ +from typing import Iterable +from itertools import islice + +def batch_query(queryset, batch_size: int = 200, db_chunk_size: int=1000): + """ + Takes a Django QuerySet and performs two performance optimizations: + 1. Use a Django iterator to pull up to db_chunk_size elements from the + DB at a time + 2. Yields up to batch_size elements from the QuerySet at a time within + tuples + + You can use values_list on the QuerySet to prevent Django from initializing + model instances and further save memory + + Example usage: + ```py + all_taxons = Taxon.objects.all().values_list("pk", flat=True) + + # For the above query, pull 500 at a time from the database and then grab + # 100 of them for each iteration of this loop to use for our own processing + for taxon_ids in batch_query(all_taxons, batch_size=100, db_chunk_size=500): + # In this case, taxon_ids is always a tuple containing up to 100 + # integers (the taxon IDs) + Determination.objects.bulk_create( + # The below list will always have at most 100 elements + # (Determination objects). This limits the amount of upfront memory + # that this list creation will allocate + [ + Determination( + taxon=taxon, + ... + ) + for taxon in taxon_ids + ] + ) + ``` + """ + yield from batch_iterable(queryset.iterator(chunk_size=db_chunk_size), batch_size=batch_size) + +def batch_iterable[T](iterable: Iterable[T], batch_size: int): + """ + A generator that takes any Iterable and yields tuples containing up to + batch_size elements until the iterable is exhausted. + + This is useful when you want to perform some operation over all + elements in the iterable, but the operation is memory intensive and can + be batched. + + Example: + ```py + example = [1, 2, 3] + for batched in batch_iterable(example, 2): + print(batched) + # prints (1, 2) then (3,) + ``` + """ + iterator = iter(iterable) + while batch := tuple(islice(iterator, batch_size)): + yield batch diff --git a/specifyweb/specify/migrations/0004_stratigraphy_age.py b/specifyweb/specify/migrations/0004_stratigraphy_age.py index 468bc3fa25e..c7a450be6c8 100644 --- a/specifyweb/specify/migrations/0004_stratigraphy_age.py +++ b/specifyweb/specify/migrations/0004_stratigraphy_age.py @@ -6,19 +6,21 @@ from specifyweb.specify.migration_utils.migration_helpers.helper_0004_stratigraphy_age import AGETYPE_PICKLIST_NAME, create_agetype_picklist, create_strat_table_schema_config_with_defaults, revert_strat_table_schema_config_with_defaults from specifyweb.specify.models import protect_with_blockers -from specifyweb.specify.migration_utils import migration_helpers as usc def revert_agetype_picklist(apps): - Collection = apps.get_model('specify', 'Collection') Picklist = apps.get_model('specify', 'Picklist') PicklistItem = apps.get_model('specify', 'Picklistitem') - for collection in Collection.objects.all(): - age_type_pick_lists = Picklist.objects.filter(name=AGETYPE_PICKLIST_NAME, collection=collection) + picklists_to_delete = Picklist.objects.filter( + name=AGETYPE_PICKLIST_NAME + ) - for age_type_pick_list in age_type_pick_lists: - PicklistItem.objects.filter(picklist=age_type_pick_list).delete() - age_type_pick_list.delete() + items_to_delete = PicklistItem.objects.filter( + picklist__name=AGETYPE_PICKLIST_NAME + ) + + items_to_delete.delete() + picklists_to_delete.delete() class Migration(migrations.Migration): From 34aaccb8f3924de82c1205c45baa3bd62e8cda2c Mon Sep 17 00:00:00 2001 From: melton-jason Date: Thu, 18 Jun 2026 16:40:25 -0500 Subject: [PATCH 095/113] chore: add bug comment for irrevirsible migration --- .../permissions/migrations/0008_attachment_import_role.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/specifyweb/backend/permissions/migrations/0008_attachment_import_role.py b/specifyweb/backend/permissions/migrations/0008_attachment_import_role.py index a1cabb22429..c5f9aaf1872 100644 --- a/specifyweb/backend/permissions/migrations/0008_attachment_import_role.py +++ b/specifyweb/backend/permissions/migrations/0008_attachment_import_role.py @@ -85,6 +85,7 @@ class Migration(migrations.Migration): dependencies = [ ('permissions', '0007_add_stats_edit_permission') ] + # BUG: Make this reversible operations = [ migrations.RunPython(add_attachment_import_role) - ] \ No newline at end of file + ] From 8093c2a4e23646b34b58a47f2960acd61baead0f Mon Sep 17 00:00:00 2001 From: melton-jason Date: Mon, 22 Jun 2026 12:08:15 -0500 Subject: [PATCH 096/113] chore: reformat helper functions --- .../helper_0007_schema_config_update.py | 2 +- .../helper_0008_schema_config_update.py | 2 +- .../helper_0012_add_cojo_to_schema_config.py | 2 +- .../helper_0013_collectionobjectgroup_parentcog.py | 2 +- .../helper_0015_add_version_to_ages.py | 2 +- .../helper_0017_schemaconfig_fixes.py | 2 +- ..._0020_add_tectonicunit_to_pc_in_schema_config.py | 2 +- .../helper_0021_update_hidden_geo_tables.py | 2 +- .../helper_0023_update_schema_config_text.py | 2 +- .../helper_0024_add_uniqueIdentifier_storage.py | 2 +- .../migration_helpers/helper_0027_CO_children.py | 2 +- .../helper_0029_remove_collectionobject_parentco.py | 2 +- .../helper_0033_update_paleo_desc.py | 13 +++++-------- .../helper_0034_accession_date_fields.py | 2 +- .../helper_0039_agent_fields_for_loan_and_gift.py | 2 +- .../migration_helpers/helper_0040_components.py | 2 +- 16 files changed, 20 insertions(+), 23 deletions(-) diff --git a/specifyweb/specify/migration_utils/migration_helpers/helper_0007_schema_config_update.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0007_schema_config_update.py index 2a307dfc0af..d85e1987c33 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/helper_0007_schema_config_update.py +++ b/specifyweb/specify/migration_utils/migration_helpers/helper_0007_schema_config_update.py @@ -133,4 +133,4 @@ def revert_cogtype_type_splocalecontaineritem(apps): container__name="collectionobjectgrouptype", container__schematype=0, name="type", - ).update(picklistname=None, isrequired=None) \ No newline at end of file + ).update(picklistname=None, isrequired=None) diff --git a/specifyweb/specify/migration_utils/migration_helpers/helper_0008_schema_config_update.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0008_schema_config_update.py index 55b36443ac1..8911171a7d9 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/helper_0008_schema_config_update.py +++ b/specifyweb/specify/migration_utils/migration_helpers/helper_0008_schema_config_update.py @@ -21,4 +21,4 @@ def revert_relative_age_fields(apps): # Remove absoluteAgeCitation -> absoluteAge and relativeAgeCitation -> relativeAge for table, fields in MIGRATION_0008_FIELDS.items(): for field in fields: - revert_table_field_schema_config(table, field, apps) \ No newline at end of file + revert_table_field_schema_config(table, field, apps) diff --git a/specifyweb/specify/migration_utils/migration_helpers/helper_0012_add_cojo_to_schema_config.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0012_add_cojo_to_schema_config.py index 2cc63bfbee2..bda3ea0193b 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/helper_0012_add_cojo_to_schema_config.py +++ b/specifyweb/specify/migration_utils/migration_helpers/helper_0012_add_cojo_to_schema_config.py @@ -21,4 +21,4 @@ def add_cojo_to_schema_config(apps): def remove_cojo_from_schema_config(apps): for table, fields in MIGRATION_0012_FIELDS.items(): for field in fields: - revert_table_field_schema_config(table, field, apps) \ No newline at end of file + revert_table_field_schema_config(table, field, apps) diff --git a/specifyweb/specify/migration_utils/migration_helpers/helper_0013_collectionobjectgroup_parentcog.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0013_collectionobjectgroup_parentcog.py index 71639bdb8c8..a165abe0f3d 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/helper_0013_collectionobjectgroup_parentcog.py +++ b/specifyweb/specify/migration_utils/migration_helpers/helper_0013_collectionobjectgroup_parentcog.py @@ -32,4 +32,4 @@ def revert_update_cog_schema_config(apps): Discipline = apps.get_model('specify', 'Discipline') for discipline in Discipline.objects.all(): update_table_field_schema_config_with_defaults( - 'CollectionObjectGroup', discipline.id, 'parentCojo', apps) \ No newline at end of file + 'CollectionObjectGroup', discipline.id, 'parentCojo', apps) diff --git a/specifyweb/specify/migration_utils/migration_helpers/helper_0015_add_version_to_ages.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0015_add_version_to_ages.py index 768512e14f4..e981f50d91f 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/helper_0015_add_version_to_ages.py +++ b/specifyweb/specify/migration_utils/migration_helpers/helper_0015_add_version_to_ages.py @@ -20,4 +20,4 @@ def update_age_schema_config(apps): def revert_update_age_schema_config(apps): revert_table_field_schema_config('AbsoluteAge', 'version', apps) - revert_table_field_schema_config('RelativeAge', 'version', apps) \ No newline at end of file + revert_table_field_schema_config('RelativeAge', 'version', apps) diff --git a/specifyweb/specify/migration_utils/migration_helpers/helper_0017_schemaconfig_fixes.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0017_schemaconfig_fixes.py index b1ea296ab20..532b889f3e2 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/helper_0017_schemaconfig_fixes.py +++ b/specifyweb/specify/migration_utils/migration_helpers/helper_0017_schemaconfig_fixes.py @@ -94,4 +94,4 @@ def fix_item_types(apps): def schemaconfig_fixes(apps, schema_editor=None): fix_table_captions(apps) - fix_item_types(apps) \ No newline at end of file + fix_item_types(apps) diff --git a/specifyweb/specify/migration_utils/migration_helpers/helper_0020_add_tectonicunit_to_pc_in_schema_config.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0020_add_tectonicunit_to_pc_in_schema_config.py index d149adb601e..6b5bdf69758 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/helper_0020_add_tectonicunit_to_pc_in_schema_config.py +++ b/specifyweb/specify/migration_utils/migration_helpers/helper_0020_add_tectonicunit_to_pc_in_schema_config.py @@ -19,4 +19,4 @@ def add_tectonicunit_to_pc_in_schema_config(apps): def remove_tectonicunit_from_pc_schema_config(apps): for table, fields in MIGRATION_0020_FIELDS.items(): for field in fields: - revert_table_field_schema_config(table, field, apps) \ No newline at end of file + revert_table_field_schema_config(table, field, apps) diff --git a/specifyweb/specify/migration_utils/migration_helpers/helper_0021_update_hidden_geo_tables.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0021_update_hidden_geo_tables.py index 243daee2216..3e0c27e07ed 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/helper_0021_update_hidden_geo_tables.py +++ b/specifyweb/specify/migration_utils/migration_helpers/helper_0021_update_hidden_geo_tables.py @@ -50,4 +50,4 @@ def reverse_fix_hidden_geo_prop(apps, schema_editor=None): Splocalecontaineritem.objects.filter( container=container, name__in=tuple(map(lambda field_name: field_name.lower(), fields)) - ).update(ishidden=False) \ No newline at end of file + ).update(ishidden=False) diff --git a/specifyweb/specify/migration_utils/migration_helpers/helper_0023_update_schema_config_text.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0023_update_schema_config_text.py index e91d40e06ac..b7924f4e739 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/helper_0023_update_schema_config_text.py +++ b/specifyweb/specify/migration_utils/migration_helpers/helper_0023_update_schema_config_text.py @@ -251,4 +251,4 @@ def reverse_update_schema_config_field_desc(apps, schema_editor=None): localized_items_desc.save() localized_items_name.text = item.name - localized_items_name.save() \ No newline at end of file + localized_items_name.save() diff --git a/specifyweb/specify/migration_utils/migration_helpers/helper_0024_add_uniqueIdentifier_storage.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0024_add_uniqueIdentifier_storage.py index d0f956abe82..2caafbb32a0 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/helper_0024_add_uniqueIdentifier_storage.py +++ b/specifyweb/specify/migration_utils/migration_helpers/helper_0024_add_uniqueIdentifier_storage.py @@ -21,4 +21,4 @@ def revert_storage_unique_id_fields(apps): # Remove uniqueIdentifier -> storage for table, fields in MIGRATION_0024_FIELDS.items(): for field in fields: - revert_table_field_schema_config(table, field, apps) \ No newline at end of file + revert_table_field_schema_config(table, field, apps) diff --git a/specifyweb/specify/migration_utils/migration_helpers/helper_0027_CO_children.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0027_CO_children.py index 139476f66d9..e26e946077c 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/helper_0027_CO_children.py +++ b/specifyweb/specify/migration_utils/migration_helpers/helper_0027_CO_children.py @@ -83,4 +83,4 @@ def revert_update_schema_field(apps): item.save() revert_update_fields(apps) - revert_update_schema_field(apps) \ No newline at end of file + revert_update_schema_field(apps) diff --git a/specifyweb/specify/migration_utils/migration_helpers/helper_0029_remove_collectionobject_parentco.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0029_remove_collectionobject_parentco.py index 3b675c5c9f5..aae62685727 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/helper_0029_remove_collectionobject_parentco.py +++ b/specifyweb/specify/migration_utils/migration_helpers/helper_0029_remove_collectionobject_parentco.py @@ -135,4 +135,4 @@ def reverse_hide_co_component(apps): revert_update_fields(apps) revert_update_schema_field(apps) - reverse_hide_co_component(apps) \ No newline at end of file + reverse_hide_co_component(apps) diff --git a/specifyweb/specify/migration_utils/migration_helpers/helper_0033_update_paleo_desc.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0033_update_paleo_desc.py index b204daf8276..af0690791a3 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/helper_0033_update_paleo_desc.py +++ b/specifyweb/specify/migration_utils/migration_helpers/helper_0033_update_paleo_desc.py @@ -8,12 +8,9 @@ ] def update_paleo_desc(apps): - def fix_table_description(apps): - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') + Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') + Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') - for table_name, table_desc in MIGRATION_0033_TABLES: - containers = Splocalecontainer.objects.filter(name=table_name.lower(), schematype=0) - Splocaleitemstr.objects.filter(containerdesc__in=containers).update(text=table_desc) - - fix_table_description(apps) \ No newline at end of file + for table_name, table_desc in MIGRATION_0033_TABLES: + containers = Splocalecontainer.objects.filter(name=table_name.lower(), schematype=0) + Splocaleitemstr.objects.filter(containerdesc__in=containers).update(text=table_desc) diff --git a/specifyweb/specify/migration_utils/migration_helpers/helper_0034_accession_date_fields.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0034_accession_date_fields.py index 8c8d1cbb9d8..1d31d6d7328 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/helper_0034_accession_date_fields.py +++ b/specifyweb/specify/migration_utils/migration_helpers/helper_0034_accession_date_fields.py @@ -87,4 +87,4 @@ def revert_0034_schema_config_field_desc(apps): # If needed, reset ishidden or revert text revert_0034_fields(apps) - revert_0034_schema_config_field_desc(apps) \ No newline at end of file + revert_0034_schema_config_field_desc(apps) diff --git a/specifyweb/specify/migration_utils/migration_helpers/helper_0039_agent_fields_for_loan_and_gift.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0039_agent_fields_for_loan_and_gift.py index 720d91c5df7..b720adf1f41 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/helper_0039_agent_fields_for_loan_and_gift.py +++ b/specifyweb/specify/migration_utils/migration_helpers/helper_0039_agent_fields_for_loan_and_gift.py @@ -24,4 +24,4 @@ def update_loan_and_gift_agent_fields(apps): def revert_loan_and_gift_agent_fields(apps): for table, fields in MIGRATION_0039_FIELDS.items(): for field_name in fields: - revert_table_field_schema_config(table, field_name, apps) \ No newline at end of file + revert_table_field_schema_config(table, field_name, apps) diff --git a/specifyweb/specify/migration_utils/migration_helpers/helper_0040_components.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0040_components.py index 9ec2d19f118..f5c0108237d 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/helper_0040_components.py +++ b/specifyweb/specify/migration_utils/migration_helpers/helper_0040_components.py @@ -162,4 +162,4 @@ def reverse_hide_component_fields(apps, schema_editor=None): container=container, name=field_name.lower() ) - items.update(ishidden=False) \ No newline at end of file + items.update(ishidden=False) From 601c0d6b5dea15482dd72f465e18ef39df36d511 Mon Sep 17 00:00:00 2001 From: melton-jason Date: Mon, 22 Jun 2026 12:11:10 -0500 Subject: [PATCH 097/113] chore: correct migration helper names for clarity --- .../migrations/0039_agent_fields_for_loan_and_gift.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/specifyweb/specify/migrations/0039_agent_fields_for_loan_and_gift.py b/specifyweb/specify/migrations/0039_agent_fields_for_loan_and_gift.py index cde3ac1a6ce..23c9908eef4 100644 --- a/specifyweb/specify/migrations/0039_agent_fields_for_loan_and_gift.py +++ b/specifyweb/specify/migrations/0039_agent_fields_for_loan_and_gift.py @@ -5,10 +5,10 @@ from specifyweb.specify.migration_utils.migration_helpers.helper_0039_agent_fields_for_loan_and_gift import revert_loan_and_gift_agent_fields, update_loan_and_gift_agent_fields from specifyweb.specify.models import protect_with_blockers -def consolidated_0038_forward(apps, schema_editor): +def consolidated_0039_forward(apps, schema_editor): update_loan_and_gift_agent_fields(apps) -def consolidated_0038_backward(apps, schema_editor): +def consolidated_0039_backward(apps, schema_editor): revert_loan_and_gift_agent_fields(apps) class Migration(migrations.Migration): @@ -69,8 +69,8 @@ class Migration(migrations.Migration): field=models.ForeignKey(db_column='Agent5ID', null=True, on_delete=protect_with_blockers, related_name='+', to='specify.agent'), ), migrations.RunPython( - consolidated_0038_forward, - consolidated_0038_backward, + consolidated_0039_forward, + consolidated_0039_backward, atomic=True, ), ] \ No newline at end of file From 0399624ae05524e14b4d7b23b951e415af4a12fa Mon Sep 17 00:00:00 2001 From: melton-jason Date: Mon, 22 Jun 2026 14:43:54 -0500 Subject: [PATCH 098/113] fix: create SpLocaleItemStr records when creating Schema Config records for tables --- .../specify/migration_utils/schema_writer.py | 120 +++++++++++------- 1 file changed, 76 insertions(+), 44 deletions(-) diff --git a/specifyweb/specify/migration_utils/schema_writer.py b/specifyweb/specify/migration_utils/schema_writer.py index d33b5d87b30..e729ba1f251 100644 --- a/specifyweb/specify/migration_utils/schema_writer.py +++ b/specifyweb/specify/migration_utils/schema_writer.py @@ -1,6 +1,5 @@ -from typing import TypedDict, NotRequired import logging -from typing import NamedTuple, TypedDict, NotRequired +from typing import NamedTuple, TypedDict, Required, NotRequired, Unpack from django.db.models import Q from django.apps import apps as global_apps @@ -30,6 +29,70 @@ class TableSchemaConfig(NamedTuple): description: str = "TBD" language: str = "en" +class ContainerAttrs(TypedDict): + name: Required[str] + discipline_id: Required[int] + schematype: NotRequired[int] + ishidden: NotRequired[bool] + issystem: NotRequired[bool] + version: NotRequired[int] + +def get_or_create_splocalecontainer(Splocalecontainer, Splocaleitemstr, table_label: str | None = None, table_description: str | None = None, **container_attrs: Unpack[ContainerAttrs]): + if "name" not in container_attrs.keys(): + raise ValueError("Trying to create a SpLocaleContainer without a name!") + + if "discipline_id" not in container_attrs.keys(): + raise ValueError("Trying to create a SpLocaleContianer without a Discipline") + + resolved_container_attrs: ContainerAttrs = { + "ishidden": False, + "issystem": False, + "schematype": 0, + "version": 0, + # The order of this unpacking matters + # If the defaults were specified in container_attrs, make sure to prioritize them over the defaults + **container_attrs + } + + resolved_container_attrs['name'] = resolved_container_attrs['name'].lower() + + sp_local_container = ( + Splocalecontainer.objects.filter( + name=resolved_container_attrs['name'], + discipline_id=resolved_container_attrs['discipline_id'], + schematype=resolved_container_attrs['schematype'] + ) + .order_by('id') + .first() + ) + + if sp_local_container is not None: + # BUG?: Not sure if we want to handle also checking for and (if needed) + # creating the container strings here + return sp_local_container + + sp_local_container = Splocalecontainer.objects.create(**resolved_container_attrs) + + common_string_attrs = { + "language": "en", + "version": 0 + } + container_string_rows = [ + { + **common_string_attrs, + "containername": sp_local_container, + "text": table_label or camel_to_spaced_title_case(uncapitilize(resolved_container_attrs["name"])) + }, + { + **common_string_attrs, + "containerdesc": sp_local_container, + "text": table_description or camel_to_spaced_title_case(uncapitilize(resolved_container_attrs["name"])) + } + ] + + bulk_create_splocaleitemstr_idempotent(Splocaleitemstr, container_string_rows) + return sp_local_container + def update_table_schema_config_with_defaults( table_name, discipline_id: int, @@ -172,35 +235,16 @@ def update_table_field_schema_config_with_defaults( return table_name = table.name - table_config = TableSchemaConfig( - name=table_name.lower(), - discipline_id=discipline_id, - schema_type=0, - language="en" - ) Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - sp_local_container = ( - Splocalecontainer.objects.filter( - name=table.name.lower(), - discipline_id=discipline_id, - schematype=table_config.schema_type, - ) - .order_by('id') - .first() - ) - - if sp_local_container is None: - sp_local_container = Splocalecontainer.objects.create( - name=table.name.lower(), - discipline_id=discipline_id, - schematype=table_config.schema_type, - ishidden=False, - issystem=table.system, - version=0, + sp_local_container = get_or_create_splocalecontainer( + Splocalecontainer, + Splocaleitemstr, + name=table.name.lower(), + discipline_id=discipline_id ) try: @@ -320,25 +364,13 @@ def update_table_field_schema_config_params( Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') + Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') - sp_local_container = ( - Splocalecontainer.objects.filter( - name=table.name.lower(), - discipline_id=discipline_id, - schematype=table_config.schema_type, - ) - .order_by('id') - .first() - ) - - if sp_local_container is None: - sp_local_container = Splocalecontainer.objects.create( - name=table.name.lower(), - discipline_id=discipline_id, - schematype=table_config.schema_type, - ishidden=False, - issystem=table.system, - version=0, + sp_local_container = get_or_create_splocalecontainer( + Splocalecontainer, + Splocaleitemstr, + discipline_id=discipline_id, + name=table.name.lower() ) try: From 7f9a8e2af1a7085115e89ca17073c57061f73127 Mon Sep 17 00:00:00 2001 From: melton-jason Date: Tue, 23 Jun 2026 10:59:53 -0500 Subject: [PATCH 099/113] chore: remove redundant objects and further compartmentalize --- .../commands/run_key_migration_functions.py | 10 +- .../specify/migration_utils/default_cots.py | 103 +----------------- .../helper_0002_schema_config_update.py | 84 +++++++++++++- .../helper_0003_cotype_picklist.py | 20 ++++ .../helper_0007_schema_config_update.py | 10 +- specifyweb/specify/migrations/0002_geo.py | 11 +- .../migrations/0003_cotype_picklist.py | 5 +- 7 files changed, 118 insertions(+), 125 deletions(-) diff --git a/specifyweb/specify/management/commands/run_key_migration_functions.py b/specifyweb/specify/management/commands/run_key_migration_functions.py index 50a60de072d..0d45633bd51 100644 --- a/specifyweb/specify/management/commands/run_key_migration_functions.py +++ b/specifyweb/specify/management/commands/run_key_migration_functions.py @@ -4,7 +4,7 @@ from django.core.management.base import BaseCommand from django.apps import apps from django.db import transaction -from django.db.models import Exists, OuterRef, Q +from django.db.models import Exists, OuterRef from specifyweb.backend.businessrules.migration_utils import catnum_rule_editable from specifyweb.backend.businessrules.uniqueness_rules import ( apply_default_uniqueness_rules, @@ -12,17 +12,13 @@ ) from specifyweb.permissions.migration_utils.edit_permissions import add_permission, add_stats_edit_permission from specifyweb.specify.migration_utils.default_cots import ( - create_cogtype_type_picklist, - create_cotype_picklist, create_default_collection_types, - create_default_discipline_for_tree_defs, fix_taxon_treedef_discipline_links, - set_discipline_for_taxon_treedefs ) from specifyweb.backend.permissions.initialize import initialize from specifyweb.specify.migration_utils.deduplication import deduplicate_schema_config_orm -from specifyweb.specify.migration_utils.migration_helpers.helper_0002_schema_config_update import create_geo_table_schema_config_with_defaults -from specifyweb.specify.migration_utils.migration_helpers.helper_0003_cotype_picklist import create_cotype_splocalecontaineritem +from specifyweb.specify.migration_utils.migration_helpers.helper_0002_schema_config_update import create_geo_table_schema_config_with_defaults, create_cogtype_type_picklist, create_default_discipline_for_tree_defs, set_discipline_for_taxon_treedefs +from specifyweb.specify.migration_utils.migration_helpers.helper_0003_cotype_picklist import create_cotype_splocalecontaineritem, create_cotype_picklist from specifyweb.specify.migration_utils.migration_helpers.helper_0004_stratigraphy_age import create_agetype_picklist, create_strat_table_schema_config_with_defaults from specifyweb.specify.migration_utils.migration_helpers.helper_0007_schema_config_update import create_cogtype_picklist from specifyweb.specify.migration_utils.migration_helpers.helper_0008_schema_config_update import update_relative_age_fields diff --git a/specifyweb/specify/migration_utils/default_cots.py b/specifyweb/specify/migration_utils/default_cots.py index b46098a5714..c6065c61bb3 100644 --- a/specifyweb/specify/migration_utils/default_cots.py +++ b/specifyweb/specify/migration_utils/default_cots.py @@ -1,14 +1,11 @@ import logging -from django.db.models import F, OuterRef, Subquery +from django.db.models import OuterRef, Subquery logger = logging.getLogger(__name__) -DEFAULT_COG_TYPES = [ - 'Discrete', - 'Consolidated', - 'Drill Core', -] - +# REFACTOR: Combine this with create_default_collection_types in +# specifyweb.specify.api.utils.py: +# https://github.com/specify/specify7/blob/3d13255b21afcd27fa891a38858661ad6e1914e7/specifyweb/specify/api/utils.py#L32-L75 def create_default_collection_types(apps): Collection = apps.get_model('specify', 'Collection') Collectionobject = apps.get_model('specify', 'Collectionobject') @@ -30,98 +27,6 @@ def create_default_collection_types(apps): collection.collectionobjecttype = cot collection.save() -def create_default_discipline_for_tree_defs(apps): - Discipline = apps.get_model('specify', 'Discipline') - Institution = apps.get_model('specify', 'Institution') - - # Use the specified DB alias for all queries - for discipline in Discipline.objects.all(): - geography_tree_def = discipline.geographytreedef - if geography_tree_def and geography_tree_def.discipline_id is None: - geography_tree_def.discipline = discipline - geography_tree_def.save() - - geologic_time_period_tree_def = discipline.geologictimeperiodtreedef - if geologic_time_period_tree_def and geologic_time_period_tree_def.discipline_id is None: - geologic_time_period_tree_def.discipline = discipline - geologic_time_period_tree_def.save() - - lithostrat_tree_def = discipline.lithostrattreedef - if lithostrat_tree_def and lithostrat_tree_def.discipline_id is None: - lithostrat_tree_def.discipline = discipline - lithostrat_tree_def.save() - - taxon_tree_def = discipline.taxontreedef - if taxon_tree_def and taxon_tree_def.discipline_id is None: - taxon_tree_def.discipline = discipline - taxon_tree_def.save() - - for institution in Institution.objects.all(): - storage_tree_def = institution.storagetreedef - if storage_tree_def and storage_tree_def.institution_id is None: - storage_tree_def.institution = institution - storage_tree_def.save() - -def create_cogtype_type_picklist(apps): - Collection = apps.get_model('specify', 'Collection') - Picklist = apps.get_model('specify', 'Picklist') - Picklistitem = apps.get_model('specify', 'Picklistitem') - - for collection in Collection.objects.all(): - cog_type_picklist, picklist_created = Picklist.objects.get_or_create( - name='SystemCOGTypes', # Default Collection Object Group Types - type=0, - collection=collection, - defaults={ - "issystem": False, - "readonly": False, - } - ) - if picklist_created: - for cog_type in DEFAULT_COG_TYPES: - Picklistitem.objects.get_or_create( - title=cog_type, - value=cog_type, - picklist=cog_type_picklist - ) - -COTYPE_PICKLIST_NAME = 'CollectionObjectType' -FIELD_NAME = 'collectionObjectType' -COTYPE_TEXT = 'Collection Object Type' - -def create_cotype_picklist(apps): - Collection = apps.get_model('specify', 'Collection') - Picklist = apps.get_model('specify', 'Picklist') - # Create a cotype picklist for each collection - for collection in Collection.objects.all(): - Picklist.objects.get_or_create( - name=COTYPE_PICKLIST_NAME, - type=1, - tablename='collectionobjecttype', - collection=collection, - defaults={ - "issystem": True, - "readonly": True, - "sizelimit": -1, - "sorttype": 1, - "formatter": COTYPE_PICKLIST_NAME, - } - ) - -def set_discipline_for_taxon_treedefs(apps): - Collectionobjecttype = apps.get_model('specify', 'Collectionobjecttype') - Taxontreedef = apps.get_model('specify', 'Taxontreedef') - - Taxontreedef.objects.filter( - discipline__isnull=True - ).update( - discipline=Subquery( - Collectionobjecttype.objects.filter( - taxontreedef=OuterRef("pk") - ).order_by("pk").values("collection__discipline")[:1] - ) - ) - def fix_taxon_treedef_discipline_links(apps): Discipline = apps.get_model('specify', 'Discipline') Taxontreedef = apps.get_model('specify', 'Taxontreedef') diff --git a/specifyweb/specify/migration_utils/migration_helpers/helper_0002_schema_config_update.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0002_schema_config_update.py index c308dd7bc50..3373d192780 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/helper_0002_schema_config_update.py +++ b/specifyweb/specify/migration_utils/migration_helpers/helper_0002_schema_config_update.py @@ -1,3 +1,7 @@ +from django.db.models import OuterRef, Subquery + +from specifyweb.specify.migration_utils.schema_writer import update_table_schema_config_with_defaults + # ########################################## # Used in 0002_schema_config_update.py @@ -23,15 +27,89 @@ ('SpDataSet', 'Stores Specify Data Sets created during bulk import using the WorkBench, typically through spreadsheet uploads.') ] -from specifyweb.specify.migration_utils.schema_writer import update_table_schema_config_with_defaults - - DEFAULT_COG_TYPES = [ 'Discrete', 'Consolidated', 'Drill Core', ] +# We could use SYSTEM_COGTYPES_PICKLIST from cogtype_rules, but keeping this +# separate for now just in case the PickList name changes +HISTORICAL_COGTYPES_PICKLIST = "SystemCOGTypes" + +# BUG: Do the same for TectonicUnit? +def create_default_discipline_for_tree_defs(apps): + Discipline = apps.get_model('specify', 'Discipline') + Institution = apps.get_model('specify', 'Institution') + + # Use the specified DB alias for all queries + for discipline in Discipline.objects.all(): + geography_tree_def = discipline.geographytreedef + if geography_tree_def and geography_tree_def.discipline_id is None: + geography_tree_def.discipline = discipline + geography_tree_def.save() + + geologic_time_period_tree_def = discipline.geologictimeperiodtreedef + if geologic_time_period_tree_def and geologic_time_period_tree_def.discipline_id is None: + geologic_time_period_tree_def.discipline = discipline + geologic_time_period_tree_def.save() + + lithostrat_tree_def = discipline.lithostrattreedef + if lithostrat_tree_def and lithostrat_tree_def.discipline_id is None: + lithostrat_tree_def.discipline = discipline + lithostrat_tree_def.save() + + taxon_tree_def = discipline.taxontreedef + if taxon_tree_def and taxon_tree_def.discipline_id is None: + taxon_tree_def.discipline = discipline + taxon_tree_def.save() + + for institution in Institution.objects.all(): + storage_tree_def = institution.storagetreedef + if storage_tree_def and storage_tree_def.institution_id is None: + storage_tree_def.institution = institution + storage_tree_def.save() + + +# REFACTOR: Optimize +def create_cogtype_type_picklist(apps): + Collection = apps.get_model('specify', 'Collection') + Picklist = apps.get_model('specify', 'Picklist') + Picklistitem = apps.get_model('specify', 'Picklistitem') + + for collection in Collection.objects.all(): + cog_type_picklist, picklist_created = Picklist.objects.get_or_create( + # the name used to be "Default Collection Object Group Types" + name=HISTORICAL_COGTYPES_PICKLIST, + type=0, + collection=collection, + defaults={ + "issystem": False, + "readonly": False, + } + ) + if picklist_created: + for cog_type in DEFAULT_COG_TYPES: + Picklistitem.objects.get_or_create( + title=cog_type, + value=cog_type, + picklist=cog_type_picklist + ) + +def set_discipline_for_taxon_treedefs(apps): + Collectionobjecttype = apps.get_model('specify', 'Collectionobjecttype') + Taxontreedef = apps.get_model('specify', 'Taxontreedef') + + Taxontreedef.objects.filter( + discipline__isnull=True + ).update( + discipline=Subquery( + Collectionobjecttype.objects.filter( + taxontreedef=OuterRef("pk") + ).order_by("pk").values("collection__discipline")[:1] + ) + ) + def create_geo_table_schema_config_with_defaults(apps): Discipline = apps.get_model('specify', 'Discipline') for discipline in Discipline.objects.all(): diff --git a/specifyweb/specify/migration_utils/migration_helpers/helper_0003_cotype_picklist.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0003_cotype_picklist.py index 2ec230b7ceb..f24704aa305 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/helper_0003_cotype_picklist.py +++ b/specifyweb/specify/migration_utils/migration_helpers/helper_0003_cotype_picklist.py @@ -7,6 +7,26 @@ COT_FIELD_NAME = 'collectionObjectType' COT_TEXT = 'Collection Object Type' +# REFACTOR: optimize +def create_cotype_picklist(apps): + Collection = apps.get_model('specify', 'Collection') + Picklist = apps.get_model('specify', 'Picklist') + # Create a cotype picklist for each collection + for collection in Collection.objects.all(): + Picklist.objects.get_or_create( + name=COT_PICKLIST_NAME, + type=1, + tablename='collectionobjecttype', + collection=collection, + defaults={ + "issystem": True, + "readonly": True, + "sizelimit": -1, + "sorttype": 1, + "formatter": COT_PICKLIST_NAME, + } + ) + # FEAT: Replace this implementation with # update_table_field_schema_config_with_defaults def create_cotype_splocalecontaineritem(apps): diff --git a/specifyweb/specify/migration_utils/migration_helpers/helper_0007_schema_config_update.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0007_schema_config_update.py index d85e1987c33..98530acba9b 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/helper_0007_schema_config_update.py +++ b/specifyweb/specify/migration_utils/migration_helpers/helper_0007_schema_config_update.py @@ -1,5 +1,7 @@ from specifyweb.specify.migration_utils.schema_writer import revert_table_field_schema_config, update_table_field_schema_config_with_defaults +from specifyweb.specify.migration_utils.migration_helpers.helper_0002_schema_config_update import HISTORICAL_COGTYPES_PICKLIST + # ########################################## # Used in 0007_schema_config_update.py # ########################################## @@ -11,7 +13,6 @@ COG_PICKLIST_NAME = 'COGTypes' COGTYPE_FIELD_NAME = 'cogType' -SYSTEM_COGTYPE_PICKLIST_NAME = "SystemCOGTypes" def update_cog_type_fields(apps): Discipline = apps.get_model('specify', 'Discipline') @@ -98,7 +99,7 @@ def update_systemcogtypes_picklist(apps): Picklist = apps.get_model('specify', 'Picklist') Picklist.objects.filter(name='Default Collection Object Group Types').update( - name=SYSTEM_COGTYPE_PICKLIST_NAME, + name=HISTORICAL_COGTYPES_PICKLIST, type=0, issystem=True, readonly=True, @@ -110,7 +111,7 @@ def revert_systemcogtypes_picklist(apps): Picklist = apps.get_model('specify', 'Picklist') # revert only changes the name and not the other attributes as those were incorrect - Picklist.objects.filter(name=SYSTEM_COGTYPE_PICKLIST_NAME).update( + Picklist.objects.filter(name=HISTORICAL_COGTYPES_PICKLIST).update( name='Default Collection Object Group Types', ) @@ -123,7 +124,7 @@ def update_cogtype_type_splocalecontaineritem(apps): container__name="collectionobjectgrouptype", container__schematype=0, name="type", - ).update(picklistname=SYSTEM_COGTYPE_PICKLIST_NAME, isrequired=True) + ).update(picklistname=HISTORICAL_COGTYPES_PICKLIST, isrequired=True) def revert_cogtype_type_splocalecontaineritem(apps): @@ -134,3 +135,4 @@ def revert_cogtype_type_splocalecontaineritem(apps): container__schematype=0, name="type", ).update(picklistname=None, isrequired=None) + diff --git a/specifyweb/specify/migrations/0002_geo.py b/specifyweb/specify/migrations/0002_geo.py index 380f1344aae..b2cf643d768 100644 --- a/specifyweb/specify/migrations/0002_geo.py +++ b/specifyweb/specify/migrations/0002_geo.py @@ -3,20 +3,13 @@ import logging from django.db import migrations, models -# from django.db.models import F import django.utils.timezone -from specifyweb.specify.migration_utils.migration_helpers.helper_0002_schema_config_update import MIGRATION_0002_TABLES, create_geo_table_schema_config_with_defaults +from specifyweb.specify.migration_utils.migration_helpers.helper_0002_schema_config_update import MIGRATION_0002_TABLES, create_geo_table_schema_config_with_defaults, create_default_discipline_for_tree_defs, set_discipline_for_taxon_treedefs, create_cogtype_type_picklist from specifyweb.specify.migration_utils.schema_writer import revert_table_schema_config from specifyweb.specify.models import ( protect_with_blockers ) -from specifyweb.specify.migration_utils import migration_helpers as usc -from specifyweb.specify.migration_utils.default_cots import ( - create_cogtype_type_picklist, - create_default_collection_types, - create_default_discipline_for_tree_defs, - set_discipline_for_taxon_treedefs, -) +from specifyweb.specify.migration_utils.default_cots import create_default_collection_types logger = logging.getLogger(__name__) diff --git a/specifyweb/specify/migrations/0003_cotype_picklist.py b/specifyweb/specify/migrations/0003_cotype_picklist.py index a7c465bf31d..2f26c2c3d1a 100644 --- a/specifyweb/specify/migrations/0003_cotype_picklist.py +++ b/specifyweb/specify/migrations/0003_cotype_picklist.py @@ -1,9 +1,8 @@ from django.db import migrations -from specifyweb.specify.migration_utils.default_cots import create_cotype_picklist, COTYPE_PICKLIST_NAME -from specifyweb.specify.migration_utils.migration_helpers.helper_0003_cotype_picklist import COT_FIELD_NAME, COT_TEXT, create_cotype_splocalecontaineritem +from specifyweb.specify.migration_utils.migration_helpers.helper_0003_cotype_picklist import COT_PICKLIST_NAME, COT_FIELD_NAME, COT_TEXT, create_cotype_splocalecontaineritem, create_cotype_picklist def revert_cotype_picklist(apps): Picklist = apps.get_model('specify', 'Picklist') - Picklist.objects.filter(name=COTYPE_PICKLIST_NAME).delete() + Picklist.objects.filter(name=COT_PICKLIST_NAME).delete() def revert_cotype_splocalecontaineritem(apps): Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') From f4b66566658c7b78f04667abe7f3e81aa82ad4a9 Mon Sep 17 00:00:00 2001 From: melton-jason Date: Tue, 23 Jun 2026 11:32:48 -0500 Subject: [PATCH 100/113] fix: typo in UserRole description --- .../migration_helpers/helper_0002_schema_config_update.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specifyweb/specify/migration_utils/migration_helpers/helper_0002_schema_config_update.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0002_schema_config_update.py index 3373d192780..7fefb7fc6f6 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/helper_0002_schema_config_update.py +++ b/specifyweb/specify/migration_utils/migration_helpers/helper_0002_schema_config_update.py @@ -19,7 +19,7 @@ ('Message', 'Stores user notifications.'), ('SpMerging', 'Tracks record and task IDs of records being merged.'), ('UserPolicy', 'Records permissions for a user within a collection.'), - ('UserRole', 'Records roles associated with ecify users.'), + ('UserRole', 'Records roles associated with Specify users.'), ('Role', 'Stores names, descriptions, and collection information for user-created roles.'), ('RolePolicy', 'Stores resource and action permissions for user-created roles within a collection.'), ('LibraryRole', 'Stores names and descriptions of default roles that can be added to any collection.'), From 170b732ae9129a59173353e1b7e5d419cc236068 Mon Sep 17 00:00:00 2001 From: melton-jason Date: Tue, 23 Jun 2026 11:34:11 -0500 Subject: [PATCH 101/113] chore: fix indentation of comment --- .../migration_helpers/helper_0008_schema_config_update.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specifyweb/specify/migration_utils/migration_helpers/helper_0008_schema_config_update.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0008_schema_config_update.py index 8911171a7d9..8ec4eb13cdd 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/helper_0008_schema_config_update.py +++ b/specifyweb/specify/migration_utils/migration_helpers/helper_0008_schema_config_update.py @@ -18,7 +18,7 @@ def update_relative_age_fields(apps): update_table_field_schema_config_with_defaults(table, discipline.id, field, apps) def revert_relative_age_fields(apps): - # Remove absoluteAgeCitation -> absoluteAge and relativeAgeCitation -> relativeAge + # Remove absoluteAgeCitation -> absoluteAge and relativeAgeCitation -> relativeAge for table, fields in MIGRATION_0008_FIELDS.items(): for field in fields: revert_table_field_schema_config(table, field, apps) From ddb8a78c05782c970ad37cd0317103972f7e07aa Mon Sep 17 00:00:00 2001 From: melton-jason Date: Tue, 23 Jun 2026 11:36:12 -0500 Subject: [PATCH 102/113] fix: typo in field name for 0023 --- .../migration_helpers/helper_0023_update_schema_config_text.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specifyweb/specify/migration_utils/migration_helpers/helper_0023_update_schema_config_text.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0023_update_schema_config_text.py index b7924f4e739..16c82580a84 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/helper_0023_update_schema_config_text.py +++ b/specifyweb/specify/migration_utils/migration_helpers/helper_0023_update_schema_config_text.py @@ -69,7 +69,7 @@ } MIGRATION_0023_FIELDS_BIS = { - 'CollectionObjectGroup': ['guid', ' text3', 'decimal2', 'igsn', 'text2', 'collection', 'description', 'text1', 'cojo', 'decimal1', 'yesno3', 'integer3', 'yesno2', 'collectionObjectGroupId', 'integer2', 'yesno1', 'integer1', 'decimal3', ], + 'CollectionObjectGroup': ['guid', 'text3', 'decimal2', 'igsn', 'text2', 'collection', 'description', 'text1', 'cojo', 'decimal1', 'yesno3', 'integer3', 'yesno2', 'collectionObjectGroupId', 'integer2', 'yesno1', 'integer1', 'decimal3', ], 'CollectionObjectGroupJoin' : ['yesno2', 'text1', 'yesno1', 'integer3', 'integer2', 'integer1', 'text3', 'yesno3', 'precedence', 'text2'], 'CollectionObjectGroupType' : ['collection'], 'CollectionObjectType': ['text3', 'collectionObjectTypeId', 'text2', 'text1', 'collection'], From cd84f91590f272c392196b601db62931b08d8b69 Mon Sep 17 00:00:00 2001 From: melton-jason Date: Tue, 23 Jun 2026 11:49:31 -0500 Subject: [PATCH 103/113] fix: specify 'en' language in 0033 migration and optimize --- .../migration_helpers/helper_0033_update_paleo_desc.py | 10 +++++++--- .../helper_0042_discipline_type_picklist.py | 2 +- .../0029_remove_collectionobject_parentco.py | 1 - 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/specifyweb/specify/migration_utils/migration_helpers/helper_0033_update_paleo_desc.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0033_update_paleo_desc.py index af0690791a3..3873bfc334b 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/helper_0033_update_paleo_desc.py +++ b/specifyweb/specify/migration_utils/migration_helpers/helper_0033_update_paleo_desc.py @@ -8,9 +8,13 @@ ] def update_paleo_desc(apps): - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') for table_name, table_desc in MIGRATION_0033_TABLES: - containers = Splocalecontainer.objects.filter(name=table_name.lower(), schematype=0) - Splocaleitemstr.objects.filter(containerdesc__in=containers).update(text=table_desc) + Splocaleitemstr.objects.filter( + containerdesc__name=table_name.lower(), + containerdesc__schematype=0, + language="en" + ).update( + text=table_desc + ) diff --git a/specifyweb/specify/migration_utils/migration_helpers/helper_0042_discipline_type_picklist.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0042_discipline_type_picklist.py index 063b0919207..e994b47deb2 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/helper_0042_discipline_type_picklist.py +++ b/specifyweb/specify/migration_utils/migration_helpers/helper_0042_discipline_type_picklist.py @@ -18,7 +18,7 @@ def create_discipline_type_picklist(apps): collections_missing_picklist = Collection.objects.annotate( has_existing_picklist=Exists( Picklist.objects.filter( - collection=OuterRef("pk"), + collection_id=OuterRef("pk"), name=DISCIPLINE_TYPE_PICKLIST_NAME, type=0 ) diff --git a/specifyweb/specify/migrations/0029_remove_collectionobject_parentco.py b/specifyweb/specify/migrations/0029_remove_collectionobject_parentco.py index 758648f1e99..4060d5c03ec 100644 --- a/specifyweb/specify/migrations/0029_remove_collectionobject_parentco.py +++ b/specifyweb/specify/migrations/0029_remove_collectionobject_parentco.py @@ -3,7 +3,6 @@ from django.db import migrations, models import django.db.models.deletion -from specifyweb.specify.migration_utils import migration_helpers as usc from specifyweb.specify.migration_utils.migration_helpers.helper_0029_remove_collectionobject_parentco import remove_collectionobject_parentco, revert_remove_collectionobject_parentco class Migration(migrations.Migration): From 92ab2bf7f9778c3f4ce33d361f1684625555b339 Mon Sep 17 00:00:00 2001 From: melton-jason Date: Tue, 23 Jun 2026 12:03:33 -0500 Subject: [PATCH 104/113] fix: only consider non-workbench schema items in 0023 reverse --- .../migration_helpers/helper_0023_update_schema_config_text.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/specifyweb/specify/migration_utils/migration_helpers/helper_0023_update_schema_config_text.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0023_update_schema_config_text.py index 16c82580a84..da0af79b456 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/helper_0023_update_schema_config_text.py +++ b/specifyweb/specify/migration_utils/migration_helpers/helper_0023_update_schema_config_text.py @@ -201,10 +201,12 @@ def reverse_update_hidden_prop(apps, schema_editor=None): Discipline = apps.get_model('specify', 'Discipline') discipline_types_by_id = dict(Discipline.objects.values_list("id", "type")) + # REFACTOR: optimize for table, fields in MIGRATION_0023_FIELDS_BIS.items(): field_names = [field_name.lower() for field_name in fields] containers = Splocalecontainer.objects.filter( name=table.lower(), + schematype=0 ) for container in containers: discipline_type = discipline_types_by_id.get(container.discipline_id, "") From b7518fff3c174a8b52e873ab9c19afbfe59daab2 Mon Sep 17 00:00:00 2001 From: melton-jason Date: Tue, 23 Jun 2026 12:28:13 -0500 Subject: [PATCH 105/113] fix: 0027 revert not matching fields (also optimize) --- .../helper_0027_CO_children.py | 21 +++++++------------ 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/specifyweb/specify/migration_utils/migration_helpers/helper_0027_CO_children.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0027_CO_children.py index e26e946077c..6244077b44d 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/helper_0027_CO_children.py +++ b/specifyweb/specify/migration_utils/migration_helpers/helper_0027_CO_children.py @@ -64,23 +64,16 @@ def revert_update_fields(apps): revert_table_field_schema_config(table, field, apps) def revert_update_schema_field(apps): - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') - for table, fields in MIGRATION_0027_UPDATE_FIELDS.items(): - containers = Splocalecontainer.objects.filter( - name=table.lower(), + for table, fields in MIGRATION_0027_FIELDS.items(): + Splocalecontaineritem.objects.filter( + container__name=table.lower(), + container__schematype=0, + name__in=list(map(lambda field: field.lower(), fields)) + ).update( + ishidden=False ) - for container in containers: - for field_name in fields: - items = Splocalecontaineritem.objects.filter( - container=container, - name=field_name - ) - - for item in items: - item.ishidden = False - item.save() revert_update_fields(apps) revert_update_schema_field(apps) From 374d5cfbc97135a36448af1ae6fc44f93826d5ac Mon Sep 17 00:00:00 2001 From: melton-jason Date: Tue, 23 Jun 2026 12:35:29 -0500 Subject: [PATCH 106/113] fix: only modify en locale strings and optimize 0027 --- .../helper_0027_CO_children.py | 44 +++++++------------ 1 file changed, 17 insertions(+), 27 deletions(-) diff --git a/specifyweb/specify/migration_utils/migration_helpers/helper_0027_CO_children.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0027_CO_children.py index 6244077b44d..22b1f84673e 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/helper_0027_CO_children.py +++ b/specifyweb/specify/migration_utils/migration_helpers/helper_0027_CO_children.py @@ -23,36 +23,26 @@ def update_discipline_fields(apps): update_table_field_schema_config_with_defaults(table, discipline.id, field, apps) def update_schema_config_field_desc(apps): - Splocalecontainer = apps.get_model('specify', 'Splocalecontainer') - Splocalecontaineritem = apps.get_model('specify', 'Splocalecontaineritem') Splocaleitemstr = apps.get_model('specify', 'Splocaleitemstr') for table, fields in MIGRATION_0027_UPDATE_FIELDS.items(): - #i.e: Collection Object - containers = Splocalecontainer.objects.filter( - name=table.lower(), - ) - - for container in containers: - for field_name, new_name, new_desc in fields: - #i.e: COType - items = Splocalecontaineritem.objects.filter( - container=container, - name__iexact=field_name - ) - - for item in items: - localized_items_desc = Splocaleitemstr.objects.filter(itemdesc_id=item.id).first() - localized_items_name = Splocaleitemstr.objects.filter(itemname_id=item.id).first() - - if localized_items_desc is None or localized_items_name is None: - continue - - localized_items_desc.text = new_desc - localized_items_desc.save() - - localized_items_name.text = new_name - localized_items_name.save() + for field_name, new_label, new_desc in fields: + Splocaleitemstr.objects.filter( + itemname__container__name__iexact=table, + itemname__container__schematype=0, + itemname__name__iexact=field_name, + language="en" + ).update( + text=new_label + ) + Splocaleitemstr.objects.filter( + itemdesc__container__name__iexact=table, + itemdesc__container__schematype=0, + itemdesc__name__iexact=field_name, + language="en" + ).update( + text=new_desc + ) update_discipline_fields(apps) update_schema_config_field_desc(apps) From 04392d992f507776b160280b5c005a02ff8ccdfd Mon Sep 17 00:00:00 2001 From: melton-jason Date: Tue, 23 Jun 2026 12:50:47 -0500 Subject: [PATCH 107/113] refactor: simplify 0027 revert schema config changes --- .../migration_helpers/helper_0027_CO_children.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specifyweb/specify/migration_utils/migration_helpers/helper_0027_CO_children.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0027_CO_children.py index 22b1f84673e..9aa9694c255 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/helper_0027_CO_children.py +++ b/specifyweb/specify/migration_utils/migration_helpers/helper_0027_CO_children.py @@ -60,7 +60,7 @@ def revert_update_schema_field(apps): Splocalecontaineritem.objects.filter( container__name=table.lower(), container__schematype=0, - name__in=list(map(lambda field: field.lower(), fields)) + name__in=fields ).update( ishidden=False ) From 4f1494ecb22955b6083478c1e04b4bc0b1ded6eb Mon Sep 17 00:00:00 2001 From: melton-jason Date: Tue, 23 Jun 2026 13:28:13 -0500 Subject: [PATCH 108/113] chore: add refactor comments to 0017 for improvement feasability --- .../helper_0017_schemaconfig_fixes.py | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/specifyweb/specify/migration_utils/migration_helpers/helper_0017_schemaconfig_fixes.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0017_schemaconfig_fixes.py index 532b889f3e2..8dd06e45807 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/helper_0017_schemaconfig_fixes.py +++ b/specifyweb/specify/migration_utils/migration_helpers/helper_0017_schemaconfig_fixes.py @@ -51,6 +51,16 @@ def fix_table_captions(apps): ).update(text=camel_to_spaced_title_case(uncapitilize(table.name))) # Update the types for the fields in the table + # REFACTOR: Find some way to optimize this. + # We can easily optimize (perform in bulk) everything except + # determining the type and whether or not the field is a + # relationship or not and whether the field is required. + # For example, we could do something like the following: + # Splocalecontaineritem.objects.filter(...) + # .update(type=CASE(WHEN(..., then=...)), isrequired=CASE(...)) + # See https://docs.djangoproject.com/en/4.2/ref/models/conditional-expressions/ + # e.g., We need to determine whether we can convert as much of the + # logic as possible to utilize database constructs like F objects items = Splocalecontaineritem.objects.filter( container__in=containers) for item in items: @@ -80,6 +90,16 @@ def fix_item_types(apps): items = Splocalecontaineritem.objects.filter( container__name=table_name.lower(), container__schematype=0, name__in=fields) + # REFACTOR: Find some way to optimize this. + # We can easily optimize (perform in bulk) everything except + # determining the type and whether or not the field is a + # relationship or not and whether the field is required. + # For example, we could do something like the following: + # Splocalecontaineritem.objects.filter(...) + # .update(type=CASE(WHEN(..., then=...)), isrequired=CASE(...)) + # See https://docs.djangoproject.com/en/4.2/ref/models/conditional-expressions/ + # e.g., We need to determine whether we can convert as much of the + # logic as possible to utilize database constructs like F objects for item in items: datamodel_field = table.get_field(item.name) if not datamodel_field: From 6b70846a54710648720a377e98a1ac01b39edeab Mon Sep 17 00:00:00 2001 From: melton-jason Date: Tue, 23 Jun 2026 13:36:30 -0500 Subject: [PATCH 109/113] fix: field lists being lowered in 0021 migration --- .../helper_0021_update_hidden_geo_tables.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/specifyweb/specify/migration_utils/migration_helpers/helper_0021_update_hidden_geo_tables.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0021_update_hidden_geo_tables.py index 3e0c27e07ed..d036b248e30 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/helper_0021_update_hidden_geo_tables.py +++ b/specifyweb/specify/migration_utils/migration_helpers/helper_0021_update_hidden_geo_tables.py @@ -20,14 +20,14 @@ def fix_hidden_geo_prop(apps, schema_editor=None): for discipline in filtered_disciplines: for table, fields in MIGRATION_0021_FIELDS.items(): containers = Splocalecontainer.objects.filter( - name=table.lower(), + name__iexact=table, discipline_id=discipline.id, ) for container in containers: # BUG: What if the user wants the field unhidden? Splocalecontaineritem.objects.filter( container=container, - name__in=tuple(map(lambda field_name: field_name.lower(), fields)) + name__in=fields ).update(ishidden=True) def reverse_fix_hidden_geo_prop(apps, schema_editor=None): @@ -49,5 +49,5 @@ def reverse_fix_hidden_geo_prop(apps, schema_editor=None): # BUG: What if the user wants the field hidden? Splocalecontaineritem.objects.filter( container=container, - name__in=tuple(map(lambda field_name: field_name.lower(), fields)) + name__in=fields ).update(ishidden=False) From 63b26930329d705660742327c1e3a5e8bb48247f Mon Sep 17 00:00:00 2001 From: melton-jason Date: Tue, 23 Jun 2026 14:15:36 -0500 Subject: [PATCH 110/113] refactor: optimizations --- .../helper_0007_schema_config_update.py | 52 +++++++++++++------ 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/specifyweb/specify/migration_utils/migration_helpers/helper_0007_schema_config_update.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0007_schema_config_update.py index 98530acba9b..95c4a48db4f 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/helper_0007_schema_config_update.py +++ b/specifyweb/specify/migration_utils/migration_helpers/helper_0007_schema_config_update.py @@ -1,5 +1,7 @@ -from specifyweb.specify.migration_utils.schema_writer import revert_table_field_schema_config, update_table_field_schema_config_with_defaults +from django.db.models import Q, Exists, OuterRef +from specifyweb.specify.migration_utils.schema_writer import revert_table_field_schema_config, update_table_field_schema_config_with_defaults +from specifyweb.specify.migration_utils.utils import batch_query from specifyweb.specify.migration_utils.migration_helpers.helper_0002_schema_config_update import HISTORICAL_COGTYPES_PICKLIST # ########################################## @@ -35,10 +37,12 @@ def update_cog_type_fields(apps): name="collectionObjectType", picklistname=None, container__name="collectionobject", + container__schematype=0 ) - for container_item in container_items: - Splocaleitemstr.objects.filter(itemname=container_item).delete() - Splocaleitemstr.objects.filter(itemdesc=container_item).delete() + Splocaleitemstr.objects.filter( + Q(itemname__in=container_items) | Q(itemdesc__in=container_items), + language="en" + ).delete() container_items.delete() # NOTE: The reverse function will not re-add the duplicate CO -> coType or COG -> cojo as its unnecessary @@ -48,24 +52,38 @@ def revert_cog_type_fields(apps): for field in fields: revert_table_field_schema_config(table, field, apps) + def create_cogtype_picklist(apps): Collection = apps.get_model('specify', 'Collection') Picklist = apps.get_model('specify', 'Picklist') + collections_without_picklists = Collection.objects.annotate( + has_existing_picklist=Exists( + Picklist.objects.filter( + collection_id=OuterRef("pk"), + name=COG_PICKLIST_NAME, + type=0 + ) + ) + ).filter(has_existing_picklist=False).values_list("pk", flat=True) + # Create a cogtype picklist for each collection - for collection in Collection.objects.all(): - Picklist.objects.update_or_create( - collection=collection, - name=COG_PICKLIST_NAME, - defaults={ - "type": 1, - "tablename": "collectionobjectgrouptype", - "issystem": True, - "readonly": True, - "sizelimit": -1, - "sorttype": 1, - "formatter": "CollectionObjectGroupType", - }, + for collection_ids in batch_query(collections_without_picklists): + Picklist.objects.bulk_create( + [ + Picklist( + name=COG_PICKLIST_NAME, + collection_id=collection_id, + type=1, + tablename="collectionobjectgrouptype", + formatter="CollectionObjectGroupType", + issystem=True, + readonly=True, + sizelimit=-1, + sorttype=1 + ) + for collection_id in collection_ids + ] ) def revert_cogtype_picklist(apps): From 0a618d4102fe6fdc366f248850d70a61b09108f1 Mon Sep 17 00:00:00 2001 From: melton-jason Date: Tue, 23 Jun 2026 15:56:02 -0500 Subject: [PATCH 111/113] fix: add 0040 migration updates to SchemaConfig default file --- config/common/schema_localization_en.json | 56 +++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/config/common/schema_localization_en.json b/config/common/schema_localization_en.json index 0e86a2ffb09..b5a29f755c5 100644 --- a/config/common/schema_localization_en.json +++ b/config/common/schema_localization_en.json @@ -10,6 +10,7 @@ "ageuncertainty": {"name": "Age Uncertainty", "desc": "Age Uncertainty", "format": null, "ishidden": false, "isuiformatter": null, "picklistname": null, "type": "java.math.BigDecimal", "isrequired": false, "weblinkname": null}, "collectiondate": {"name": "Collection Date", "desc": "Collection Date", "format": null, "ishidden": true, "isuiformatter": null, "picklistname": null, "type": "java.util.Date", "isrequired": false, "weblinkname": null}, "collectionobject": {"name": "Collection Object", "desc": "Collection Object", "format": null, "ishidden": true, "isuiformatter": null, "picklistname": null, "type": "ManyToOne", "isrequired": true, "weblinkname": null}, + "component": {"name": "Component", "desc": "Component", "format": null, "ishidden": true, "isuiformatter": null, "picklistname": null, "type": "ManyToOne", "isrequired": false, "weblinkname": null}, "createdbyagent": {"name": "Created By Agent", "desc": "Created By Agent", "format": null, "ishidden": true, "isuiformatter": null, "picklistname": null, "type": "ManyToOne", "isrequired": false, "weblinkname": null}, "date1": {"name": "Date1", "desc": "Date1", "format": null, "ishidden": true, "isuiformatter": null, "picklistname": null, "type": "java.util.Date", "isrequired": false, "weblinkname": null}, "date2": {"name": "Date2", "desc": "Date2", "format": null, "ishidden": true, "isuiformatter": null, "picklistname": null, "type": "java.util.Date", "isrequired": false, "weblinkname": null}, @@ -2062,6 +2063,60 @@ "name": "Common Name Tx Citation", "desc": "Common Name Tx Citation" }, + "component": { + "items": { + "absoluteages": {"format": null, "ishidden": true, "isuiformatter": null, "picklistname": null, "type": "OneToMany", "isrequired": false, "weblinkname": null, "name": "Absolute Ages", "desc": "Absolute Ages"}, + "catalognumber": {"format": null, "ishidden": false, "isuiformatter": null, "picklistname": null, "type": "java.lang.String", "isrequired": false, "weblinkname": null, "name": "Catalog Number", "desc": "User-assigned identifier for the component"}, + "collectionobject": {"format": null, "ishidden": true, "isuiformatter": null, "picklistname": null, "type": "ManyToOne", "isrequired": true, "weblinkname": null, "name": "Collection Object", "desc": "Collection Object"}, + "createdbyagent": {"format": null, "ishidden": true, "isuiformatter": null, "picklistname": null, "type": "ManyToOne", "isrequired": false, "weblinkname": null, "name": "Created By Agent", "desc": "Created By Agent"}, + "identifiedby": {"format": null, "ishidden": true, "isuiformatter": null, "picklistname": null, "type": "ManyToOne", "isrequired": false, "weblinkname": null, "name": "Identified By", "desc": "Identified By"}, + "identifieddate": {"format": null, "ishidden": true, "isuiformatter": null, "picklistname": null, "type": "java.util.Calendar", "isrequired": false, "weblinkname": null, "name": "Identified Date", "desc": "Identified Date"}, + "integer1": {"format": null, "ishidden": true, "isuiformatter": null, "picklistname": null, "type": "java.lang.Integer", "isrequired": false, "weblinkname": null, "name": "Integer1", "desc": "Integer1"}, + "integer2": {"format": null, "ishidden": true, "isuiformatter": null, "picklistname": null, "type": "java.lang.Integer", "isrequired": false, "weblinkname": null, "name": "Integer2", "desc": "Integer2"}, + "integer3": {"format": null, "ishidden": true, "isuiformatter": null, "picklistname": null, "type": "java.lang.Integer", "isrequired": false, "weblinkname": null, "name": "Integer3", "desc": "Integer3"}, + "integer4": {"format": null, "ishidden": true, "isuiformatter": null, "picklistname": null, "type": "java.lang.Integer", "isrequired": false, "weblinkname": null, "name": "Integer4", "desc": "Integer4"}, + "integer5": {"format": null, "ishidden": true, "isuiformatter": null, "picklistname": null, "type": "java.lang.Integer", "isrequired": false, "weblinkname": null, "name": "Integer5", "desc": "Integer5"}, + "integer6": {"format": null, "ishidden": true, "isuiformatter": null, "picklistname": null, "type": "java.lang.Integer", "isrequired": false, "weblinkname": null, "name": "Integer6", "desc": "Integer6"}, + "modifiedbyagent": {"format": null, "ishidden": true, "isuiformatter": null, "picklistname": null, "type": "ManyToOne", "isrequired": false, "weblinkname": null, "name": "Modified By Agent", "desc": "Modified By Agent"}, + "name": {"format": null, "ishidden": false, "isuiformatter": null, "picklistname": null, "type": "ManyToOne", "isrequired": false, "weblinkname": null, "name": "Name", "desc": "The name from a taxon tree corresponding to the chosen type."}, + "number1": {"format": null, "ishidden": true, "isuiformatter": null, "picklistname": null, "type": "java.math.BigDecimal", "isrequired": false, "weblinkname": null, "name": "Number1", "desc": "Number1"}, + "number2": {"format": null, "ishidden": true, "isuiformatter": null, "picklistname": null, "type": "java.math.BigDecimal", "isrequired": false, "weblinkname": null, "name": "Number2", "desc": "Number2"}, + "number3": {"format": null, "ishidden": true, "isuiformatter": null, "picklistname": null, "type": "java.math.BigDecimal", "isrequired": false, "weblinkname": null, "name": "Number3", "desc": "Number3"}, + "number4": {"format": null, "ishidden": true, "isuiformatter": null, "picklistname": null, "type": "java.math.BigDecimal", "isrequired": false, "weblinkname": null, "name": "Number4", "desc": "Number4"}, + "number5": {"format": null, "ishidden": true, "isuiformatter": null, "picklistname": null, "type": "java.math.BigDecimal", "isrequired": false, "weblinkname": null, "name": "Number5", "desc": "Number5"}, + "number6": {"format": null, "ishidden": true, "isuiformatter": null, "picklistname": null, "type": "java.math.BigDecimal", "isrequired": false, "weblinkname": null, "name": "Number6", "desc": "Number6"}, + "proportion": {"format": null, "ishidden": true, "isuiformatter": null, "picklistname": null, "type": "java.lang.Integer", "isrequired": false, "weblinkname": null, "name": "Proportion", "desc": "Specify the proportion of the component relative to the whole."}, + "relativeages": {"format": null, "ishidden": true, "isuiformatter": null, "picklistname": null, "type": "OneToMany", "isrequired": false, "weblinkname": null, "name": "Relative Ages", "desc": "Relative Ages"}, + "role": {"format": null, "ishidden": true, "isuiformatter": null, "picklistname": null, "type": "java.lang.String", "isrequired": false, "weblinkname": null, "name": "Role", "desc": "Define the role or purpose of the component in the overall collection."}, + "text1": {"format": null, "ishidden": true, "isuiformatter": null, "picklistname": null, "type": "text", "isrequired": false, "weblinkname": null, "name": "Text1", "desc": "Text1"}, + "text2": {"format": null, "ishidden": true, "isuiformatter": null, "picklistname": null, "type": "text", "isrequired": false, "weblinkname": null, "name": "Text2", "desc": "Text2"}, + "text3": {"format": null, "ishidden": true, "isuiformatter": null, "picklistname": null, "type": "text", "isrequired": false, "weblinkname": null, "name": "Text3", "desc": "Text3"}, + "text4": {"format": null, "ishidden": true, "isuiformatter": null, "picklistname": null, "type": "text", "isrequired": false, "weblinkname": null, "name": "Text4", "desc": "Text4"}, + "text5": {"format": null, "ishidden": true, "isuiformatter": null, "picklistname": null, "type": "text", "isrequired": false, "weblinkname": null, "name": "Text5", "desc": "Text5"}, + "text6": {"format": null, "ishidden": true, "isuiformatter": null, "picklistname": null, "type": "text", "isrequired": false, "weblinkname": null, "name": "Text6", "desc": "Text6"}, + "timestampcreated": {"format": null, "ishidden": true, "isuiformatter": null, "picklistname": null, "type": "java.sql.Timestamp", "isrequired": true, "weblinkname": null, "name": "Timestamp Created", "desc": "Timestamp Created"}, + "timestampmodified": {"format": null, "ishidden": true, "isuiformatter": null, "picklistname": null, "type": "java.sql.Timestamp", "isrequired": false, "weblinkname": null, "name": "Timestamp Modified", "desc": "Timestamp Modified"}, + "type": {"format": null, "ishidden": false, "isuiformatter": null, "picklistname": "CollectionObjectType", "type": "ManyToOne", "isrequired": true, "weblinkname": null, "name": "Type", "desc": "Determines the valid options for component names."}, + "uniqueidentifier": {"format": null, "ishidden": true, "isuiformatter": null, "picklistname": null, "type": "java.lang.String", "isrequired": false, "weblinkname": null, "name": "Unique Identifier", "desc": "Uniquely identifies each component record"}, + "verbatimname": {"format": null, "ishidden": true, "isuiformatter": null, "picklistname": null, "type": "text", "isrequired": false, "weblinkname": null, "name": "Verbatim Name", "desc": "The original name printed or associated with the component."}, + "version": {"format": null, "ishidden": true, "isuiformatter": null, "picklistname": null, "type": "java.lang.Integer", "isrequired": false, "weblinkname": null, "name": "Version", "desc": "Version"}, + "yesno1": {"format": null, "ishidden": true, "isuiformatter": null, "picklistname": null, "type": "java.lang.Boolean", "isrequired": false, "weblinkname": null, "name": "Yes No1", "desc": "Yes No1"}, + "yesno2": {"format": null, "ishidden": true, "isuiformatter": null, "picklistname": null, "type": "java.lang.Boolean", "isrequired": false, "weblinkname": null, "name": "Yes No2", "desc": "Yes No2"}, + "yesno3": {"format": null, "ishidden": true, "isuiformatter": null, "picklistname": null, "type": "java.lang.Boolean", "isrequired": false, "weblinkname": null, "name": "Yes No3", "desc": "Yes No3"}, + "yesno4": {"format": null, "ishidden": true, "isuiformatter": null, "picklistname": null, "type": "java.lang.Boolean", "isrequired": false, "weblinkname": null, "name": "Yes No4", "desc": "Yes No4"}, + "yesno5": {"format": null, "ishidden": true, "isuiformatter": null, "picklistname": null, "type": "java.lang.Boolean", "isrequired": false, "weblinkname": null, "name": "Yes No5", "desc": "Yes No5"}, + "yesno6": {"format": null, "ishidden": true, "isuiformatter": null, "picklistname": null, "type": "java.lang.Boolean", "isrequired": false, "weblinkname": null, "name": "Yes No6", "desc": "Yes No6"} + }, + "format": null, + "ishidden": false, + "isuiformatter": null, + "picklistname": null, + "type": null, + "aggregator": null, + "defaultui": null, + "name": "Component", + "desc": "Component" + }, "conservdescription": { "items": { "backgroundinfo": {"name": "Background Info", "desc": "Any background information on the object.", "format": null, "ishidden": false, "isuiformatter": false, "picklistname": null, "type": "text", "isrequired": false, "weblinkname": null}, @@ -5288,6 +5343,7 @@ "ageuncertainty": {"name": "Age Uncertainty", "desc": "Age Uncertainty", "format": null, "ishidden": false, "isuiformatter": null, "picklistname": null, "type": "java.math.BigDecimal", "isrequired": false, "weblinkname": null}, "collectiondate": {"name": "Collection Date", "desc": "Collection Date", "format": null, "ishidden": true, "isuiformatter": null, "picklistname": null, "type": "java.util.Date", "isrequired": false, "weblinkname": null}, "collectionobject": {"name": "Collection Object", "desc": "Collection Object", "format": null, "ishidden": true, "isuiformatter": null, "picklistname": null, "type": "ManyToOne", "isrequired": true, "weblinkname": null}, + "component": {"name": "Component", "desc": "Component", "format": null, "ishidden": true, "isuiformatter": null, "picklistname": null, "type": "ManyToOne", "isrequired": false, "weblinkname": null}, "createdbyagent": {"name": "Created By Agent", "desc": "Created By Agent", "format": null, "ishidden": true, "isuiformatter": null, "picklistname": null, "type": "ManyToOne", "isrequired": false, "weblinkname": null}, "date1": {"name": "Date1", "desc": "Date1", "format": null, "ishidden": true, "isuiformatter": null, "picklistname": null, "type": "java.util.Date", "isrequired": false, "weblinkname": null}, "date2": {"name": "Date2", "desc": "Date2", "format": null, "ishidden": true, "isuiformatter": null, "picklistname": null, "type": "java.util.Date", "isrequired": false, "weblinkname": null}, From 7cbc57d09cd67ffb8781c1205833d5ee51a87e12 Mon Sep 17 00:00:00 2001 From: melton-jason Date: Wed, 24 Jun 2026 08:45:55 -0500 Subject: [PATCH 112/113] fix: use correct case for table labels and descriptions --- specifyweb/specify/migration_utils/schema_writer.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/specifyweb/specify/migration_utils/schema_writer.py b/specifyweb/specify/migration_utils/schema_writer.py index e729ba1f251..37062b6e70d 100644 --- a/specifyweb/specify/migration_utils/schema_writer.py +++ b/specifyweb/specify/migration_utils/schema_writer.py @@ -54,6 +54,7 @@ def get_or_create_splocalecontainer(Splocalecontainer, Splocaleitemstr, table_la **container_attrs } + string_label = resolved_container_attrs["name"] resolved_container_attrs['name'] = resolved_container_attrs['name'].lower() sp_local_container = ( @@ -62,7 +63,7 @@ def get_or_create_splocalecontainer(Splocalecontainer, Splocaleitemstr, table_la discipline_id=resolved_container_attrs['discipline_id'], schematype=resolved_container_attrs['schematype'] ) - .order_by('id') + .order_by('pk') .first() ) @@ -81,12 +82,12 @@ def get_or_create_splocalecontainer(Splocalecontainer, Splocaleitemstr, table_la { **common_string_attrs, "containername": sp_local_container, - "text": table_label or camel_to_spaced_title_case(uncapitilize(resolved_container_attrs["name"])) + "text": table_label or camel_to_spaced_title_case(uncapitilize(string_label)) }, { **common_string_attrs, "containerdesc": sp_local_container, - "text": table_description or camel_to_spaced_title_case(uncapitilize(resolved_container_attrs["name"])) + "text": table_description or camel_to_spaced_title_case(uncapitilize(string_label)) } ] @@ -243,7 +244,7 @@ def update_table_field_schema_config_with_defaults( sp_local_container = get_or_create_splocalecontainer( Splocalecontainer, Splocaleitemstr, - name=table.name.lower(), + name=table.name, discipline_id=discipline_id ) @@ -370,7 +371,7 @@ def update_table_field_schema_config_params( Splocalecontainer, Splocaleitemstr, discipline_id=discipline_id, - name=table.name.lower() + name=table.name ) try: From 9ceac77c643b00218e7aab25ffacc7bba48a7962 Mon Sep 17 00:00:00 2001 From: melton-jason Date: Wed, 24 Jun 2026 10:19:20 -0500 Subject: [PATCH 113/113] fix: use correct Picklist Type when filtering in migration --- .../migration_helpers/helper_0007_schema_config_update.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specifyweb/specify/migration_utils/migration_helpers/helper_0007_schema_config_update.py b/specifyweb/specify/migration_utils/migration_helpers/helper_0007_schema_config_update.py index 95c4a48db4f..bbfa3280f4b 100644 --- a/specifyweb/specify/migration_utils/migration_helpers/helper_0007_schema_config_update.py +++ b/specifyweb/specify/migration_utils/migration_helpers/helper_0007_schema_config_update.py @@ -62,7 +62,7 @@ def create_cogtype_picklist(apps): Picklist.objects.filter( collection_id=OuterRef("pk"), name=COG_PICKLIST_NAME, - type=0 + type=1 ) ) ).filter(has_existing_picklist=False).values_list("pk", flat=True)