diff --git a/specifyweb/frontend/js_src/lib/components/Interactions/InteractionDialog.tsx b/specifyweb/frontend/js_src/lib/components/Interactions/InteractionDialog.tsx index 0199a185191..c08a1e144b9 100644 --- a/specifyweb/frontend/js_src/lib/components/Interactions/InteractionDialog.tsx +++ b/specifyweb/frontend/js_src/lib/components/Interactions/InteractionDialog.tsx @@ -80,7 +80,8 @@ export function InteractionDialog({ ); const isLoanReturnLike = - isLoanReturn || (actionTable.name !== 'Loan' && actionTable.name.includes('Loan')); + isLoanReturn || + (actionTable.name !== 'Loan' && actionTable.name.includes('Loan')); const itemTable = isLoanReturnLike ? tables.Loan : tables.CollectionObject; @@ -206,8 +207,7 @@ export function InteractionDialog({ ) ).then((data) => availablePrepsReady(catalogNumbers, data, { - skipEntryMatch: - searchField.name.toLowerCase() !== 'catalognumber', + skipEntryMatch: searchField.name.toLowerCase() !== 'catalognumber', }) ) ); @@ -377,7 +377,9 @@ export function InteractionDialog({ values, isLoan ) - ).then((data) => availablePrepsReady(values, data, { skipEntryMatch: true })) + ).then((data) => + availablePrepsReady(values, data, { skipEntryMatch: true }) + ) ); } diff --git a/specifyweb/specify/datamodel.py b/specifyweb/specify/datamodel.py index 9fcbcdcb2b6..7ea0b9d3dba 100644 --- a/specifyweb/specify/datamodel.py +++ b/specifyweb/specify/datamodel.py @@ -1,5 +1,5 @@ from .models_utils.load_datamodel import Table, Field, Relationship, IdField, Datamodel, Index, add_collectingevents_to_locality, \ - flag_dependent_fields, flag_system_tables, DoesNotExistError, TableDoesNotExistError, FieldDoesNotExistError + flag_dependent_fields, flag_system_tables, DoesNotExistError, TableDoesNotExistError, FieldDoesNotExistError, ManyToMany # These datamodel classes were generated by the specifyweb.specify.sp7_build_datamodel.py script. # The original models in this file are based on the Specify 6.8.03 datamodel schema. @@ -815,10 +815,10 @@ def is_tree_table(table: Table): Index(name='SchemeNameIDX', column_names=['SchemeName']) ], relationships=[ - Relationship(name='collections', type='many-to-many',required=False, relatedModelName='Collection', otherSideName='numberingSchemes'), + ManyToMany(name='collections', required=False, relatedModelName="Collection", otherSideName="numberingSchemes", through_model="Autonumschcoll", through_field="autonumberingscheme"), Relationship(name='createdByAgent', type='many-to-one',required=False, relatedModelName='Agent', column='CreatedByAgentID'), - Relationship(name='disciplines', type='many-to-many',required=False, relatedModelName='Discipline', otherSideName='numberingSchemes'), - Relationship(name='divisions', type='many-to-many',required=False, relatedModelName='Division', otherSideName='numberingSchemes'), + ManyToMany(name='disciplines', required=False, relatedModelName="Discipline", otherSideName="numberingSchemes", through_model="Autonumschdsp", through_field="autonumberingscheme"), + ManyToMany(name='divisions', required=False, relatedModelName="Division", otherSideName="numberingSchemes", through_model="Autonumschdiv", through_field="autonumberingscheme"), Relationship(name='modifiedByAgent', type='many-to-one',required=False, relatedModelName='Agent', column='ModifiedByAgentID') ], fieldAliases=[ @@ -1482,7 +1482,7 @@ def is_tree_table(table: Table): Relationship(name='institutionNetwork', type='many-to-one',required=False, relatedModelName='Institution', column='InstitutionNetworkID'), Relationship(name='leftSideRelTypes', type='one-to-many',required=False, relatedModelName='CollectionRelType', otherSideName='leftSideCollection'), Relationship(name='modifiedByAgent', type='many-to-one',required=False, relatedModelName='Agent', column='ModifiedByAgentID'), - Relationship(name='numberingSchemes', type='many-to-many',required=False, relatedModelName='AutoNumberingScheme', otherSideName='collections'), + ManyToMany(name='numberingSchemes', required=False, relatedModelName="AutoNumberingScheme", otherSideName="collections", through_model="Autonumschcoll", through_field="collection"), Relationship(name='pickLists', type='one-to-many',required=False, relatedModelName='PickList', otherSideName='collection'), Relationship(name='prepTypes', type='one-to-many',required=False, relatedModelName='PrepType', otherSideName='collection'), Relationship(name='rightSideRelTypes', type='one-to-many',required=False, relatedModelName='CollectionRelType', otherSideName='rightSideCollection'), @@ -1601,7 +1601,7 @@ def is_tree_table(table: Table): Relationship(name='otherIdentifiers', type='one-to-many',required=False, relatedModelName='OtherIdentifier', otherSideName='collectionObject', dependent=True), Relationship(name='paleoContext', type='many-to-one',required=False, relatedModelName='PaleoContext', column='PaleoContextID', otherSideName='collectionObjects'), Relationship(name='preparations', type='one-to-many',required=False, relatedModelName='Preparation', otherSideName='collectionObject', dependent=True), - Relationship(name='projects', type='many-to-many',required=False, relatedModelName='Project', otherSideName='collectionObjects'), + ManyToMany(name='projects', required=False, relatedModelName="Project", otherSideName="collectionObjects", through_model="Project_colobj", through_field="collectionobject"), Relationship(name='rightSideRels', type='one-to-many',required=False, relatedModelName='CollectionRelationship', otherSideName='rightSide', dependent=True), Relationship(name='treatmentEvents', type='one-to-many',required=False, relatedModelName='TreatmentEvent', otherSideName='collectionObject', dependent=True), Relationship(name='visibilitySetBy', type='many-to-one',required=False, relatedModelName='SpecifyUser', column='VisibilitySetByID'), @@ -3064,7 +3064,7 @@ def is_tree_table(table: Table): Relationship(name='lithoStratTreeDef', type='many-to-one',required=False, relatedModelName='LithoStratTreeDef', column='LithoStratTreeDefID', otherSideName='disciplines'), Relationship(name='tectonicUnitTreeDef', type='many-to-one',required=False, relatedModelName='TectonicUnitTreeDef', column='TectonicUnitTreeDefID', otherSideName='disciplines'), Relationship(name='modifiedByAgent', type='many-to-one',required=False, relatedModelName='Agent', column='ModifiedByAgentID'), - Relationship(name='numberingSchemes', type='many-to-many',required=False, relatedModelName='AutoNumberingScheme', otherSideName='disciplines'), + ManyToMany(name='numberingSchemes', required=False, relatedModelName="AutoNumberingScheme", otherSideName="disciplines", through_model="Autonumschdsp", through_field="discipline"), Relationship(name='spExportSchemas', type='one-to-many',required=False, relatedModelName='SpExportSchema', otherSideName='discipline'), Relationship(name='spLocaleContainers', type='one-to-many',required=False, relatedModelName='SpLocaleContainer', otherSideName='discipline'), Relationship(name='userGroups', type='one-to-many',required=False, relatedModelName='SpPrincipal', otherSideName='scope') @@ -3236,7 +3236,7 @@ def is_tree_table(table: Table): Relationship(name='institution', type='many-to-one',required=True, relatedModelName='Institution', column='InstitutionID', otherSideName='divisions'), Relationship(name='members', type='one-to-many',required=False, relatedModelName='Agent', otherSideName='division'), Relationship(name='modifiedByAgent', type='many-to-one',required=False, relatedModelName='Agent', column='ModifiedByAgentID'), - Relationship(name='numberingSchemes', type='many-to-many',required=False, relatedModelName='AutoNumberingScheme', otherSideName='divisions'), + ManyToMany(name='numberingSchemes', required=False, relatedModelName="AutoNumberingScheme", otherSideName="divisions", through_model="Autonumschdiv", through_field="division"), Relationship(name='userGroups', type='one-to-many',required=False, relatedModelName='SpPrincipal', otherSideName='scope') ], fieldAliases=[ @@ -5900,7 +5900,7 @@ def is_tree_table(table: Table): ], relationships=[ Relationship(name='agent', type='many-to-one',required=False, relatedModelName='Agent', column='ProjectAgentID'), - Relationship(name='collectionObjects', type='many-to-many',required=False, relatedModelName='CollectionObject', otherSideName='projects'), + ManyToMany(name='collectionObjects', required=False, relatedModelName="CollectionObject", otherSideName="projects", through_model="Project_colobj", through_field="project"), Relationship(name='createdByAgent', type='many-to-one',required=False, relatedModelName='Agent', column='CreatedByAgentID'), Relationship(name='modifiedByAgent', type='many-to-one',required=False, relatedModelName='Agent', column='ModifiedByAgentID') ], @@ -6360,7 +6360,7 @@ def is_tree_table(table: Table): Relationship(name='discipline', type='many-to-one',required=True, relatedModelName='Discipline', column='DisciplineID', otherSideName='spExportSchemas'), Relationship(name='modifiedByAgent', type='many-to-one',required=False, relatedModelName='Agent', column='ModifiedByAgentID'), Relationship(name='spExportSchemaItems', type='one-to-many',required=False, relatedModelName='SpExportSchemaItem', otherSideName='spExportSchema'), - Relationship(name='spExportSchemaMappings', type='many-to-many',required=False, relatedModelName='SpExportSchemaMapping', otherSideName='spExportSchemas') + ManyToMany(name='spExportSchemaMappings', required=False, relatedModelName="SpExportSchemaMapping", otherSideName="spExportSchemas", through_model="Spexportschema_exportmapping", through_field="spexportschema"), ], fieldAliases=[ @@ -6451,7 +6451,7 @@ def is_tree_table(table: Table): Relationship(name='createdByAgent', type='many-to-one',required=False, relatedModelName='Agent', column='CreatedByAgentID'), Relationship(name='mappings', type='one-to-many',required=False, relatedModelName='SpExportSchemaItemMapping', otherSideName='exportSchemaMapping'), Relationship(name='modifiedByAgent', type='many-to-one',required=False, relatedModelName='Agent', column='ModifiedByAgentID'), - Relationship(name='spExportSchemas', type='many-to-many',required=False, relatedModelName='SpExportSchema', otherSideName='spExportSchemaMappings'), + ManyToMany(name='spExportSchemas', required=False, relatedModelName="SpExportSchema", otherSideName="spExportSchemaMappings", through_model="Spexportschema_exportmapping", through_field="spexportschemamapping"), Relationship(name='symbiotaInstances', type='one-to-many',required=False, relatedModelName='SpSymbiotaInstance', otherSideName='schemaMapping') ], fieldAliases=[ @@ -6613,7 +6613,7 @@ def is_tree_table(table: Table): ], relationships=[ - Relationship(name='principals', type='many-to-many',required=False, relatedModelName='SpPrincipal', otherSideName='permissions') + ManyToMany(name='principals', required=False, relatedModelName="SpPrincipal", otherSideName="permissions", through_model="Spprincipal_sppermission", through_field="sppermission"), ], fieldAliases=[ @@ -6643,9 +6643,9 @@ def is_tree_table(table: Table): relationships=[ Relationship(name='createdByAgent', type='many-to-one',required=False, relatedModelName='Agent', column='CreatedByAgentID'), Relationship(name='modifiedByAgent', type='many-to-one',required=False, relatedModelName='Agent', column='ModifiedByAgentID'), - Relationship(name='permissions', type='many-to-many',required=False, relatedModelName='SpPermission', otherSideName='principals'), + ManyToMany(name='permissions', required=False, relatedModelName="SpPermission", otherSideName="principals", through_model="Spprincipal_sppermission", through_field="spprincipal"), Relationship(name='scope', type='many-to-one',required=False, relatedModelName='UserGroupScope', column='userGroupScopeID', otherSideName='userGroups'), - Relationship(name='specifyUsers', type='many-to-many',required=False, relatedModelName='SpecifyUser', otherSideName='spPrincipals') + ManyToMany(name='specifyUsers', required=False, relatedModelName="SpecifyUser", otherSideName="spPrincipals", through_model="Specifyuser_spprincipal", through_field="spprincipal"), ], fieldAliases=[ @@ -6954,7 +6954,7 @@ def is_tree_table(table: Table): Relationship(name='modifiedByAgent', type='many-to-one',required=False, relatedModelName='Agent', column='ModifiedByAgentID'), Relationship(name='spAppResourceDirs', type='one-to-many',required=False, relatedModelName='SpAppResourceDir', otherSideName='specifyUser'), Relationship(name='spAppResources', type='one-to-many',required=False, relatedModelName='SpAppResource', otherSideName='specifyUser'), - Relationship(name='spPrincipals', type='many-to-many',required=False, relatedModelName='SpPrincipal', otherSideName='specifyUsers'), + ManyToMany(name='spPrincipals', required=False, relatedModelName="SpPrincipal", otherSideName="specifyUsers", through_model="Specifyuser_spprincipal", through_field="specifyuser"), Relationship(name='spQuerys', type='one-to-many',required=False, relatedModelName='SpQuery', otherSideName='specifyUser'), Relationship(name='taskSemaphores', type='one-to-many',required=False, relatedModelName='SpTaskSemaphore', otherSideName='owner'), Relationship(name='workbenchTemplates', type='one-to-many',required=False, relatedModelName='WorkbenchTemplate', otherSideName='specifyUser'), diff --git a/specifyweb/specify/migrations/0001_initial.py b/specifyweb/specify/migrations/0001_initial.py index 5c037acb8e4..8b62d337368 100644 --- a/specifyweb/specify/migrations/0001_initial.py +++ b/specifyweb/specify/migrations/0001_initial.py @@ -2430,7 +2430,7 @@ class Migration(migrations.Migration): ('version', models.IntegerField(blank=True, db_column='Version', default=0, null=True)), ('createdbyagent', models.ForeignKey(db_column='CreatedByAgentID', null=True, on_delete=specifyweb.specify.models.protect_with_blockers, related_name='+', to='specify.agent')), ('modifiedbyagent', models.ForeignKey(db_column='ModifiedByAgentID', null=True, on_delete=specifyweb.specify.models.protect_with_blockers, related_name='+', to='specify.agent')), - ('parent', models.ForeignKey(db_column='ParentItemID', null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='children', to='specify.taxontreedefitem')), + ('parent', models.ForeignKey(db_column='ParentItemID', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='children', to='specify.taxontreedefitem')), ('treedef', models.ForeignKey(db_column='TaxonTreeDefID', on_delete=specifyweb.specify.models.protect_with_blockers, related_name='treedefitems', to='specify.taxontreedef')), ], options={ @@ -6977,4 +6977,144 @@ class Migration(migrations.Migration): model_name='accession', index=models.Index(fields=['dateaccessioned'], name='AccessionDateIDX'), ), + migrations.CreateModel( + name='Spprincipal_sppermission', + fields=[ + ('id', models.AutoField(db_column='SpPrincipalSpPermissionID', primary_key=True, serialize=False)), + ('sppermission', models.ForeignKey(db_column='SpPermissionID', on_delete=specifyweb.specify.models.protect_with_blockers, related_name='+', to='specify.sppermission')), + ('spprincipal', models.ForeignKey(db_column='SpPrincipalID', on_delete=specifyweb.specify.models.protect_with_blockers, related_name='+', to='specify.spprincipal')), + ], + options={ + 'db_table': 'spprincipal_sppermission', + }, + ), + migrations.CreateModel( + name='Spexportschema_exportmapping', + fields=[ + ('id', models.AutoField(db_column='SpExportSchemaExportMappingID', primary_key=True, serialize=False)), + ('spexportschema', models.ForeignKey(db_column='SpExportSchemaID', on_delete=specifyweb.specify.models.protect_with_blockers, related_name='+', to='specify.spexportschema')), + ('spexportschemamapping', models.ForeignKey(db_column='SpExportSchemaMappingID', on_delete=specifyweb.specify.models.protect_with_blockers, related_name='+', to='specify.spexportschemamapping')), + ], + options={ + 'db_table': 'sp_schema_mapping', + }, + ), + migrations.CreateModel( + name='Specifyuser_spprincipal', + fields=[ + ('id', models.AutoField(db_column='SpeicfyuserSpPrincipalID', primary_key=True, serialize=False)), + ('specifyuser', models.ForeignKey(db_column='SpecifyUserID', on_delete=django.db.models.deletion.CASCADE, related_name='+', to=settings.AUTH_USER_MODEL)), + ('spprincipal', models.ForeignKey(db_column='SpPrincipalID', on_delete=specifyweb.specify.models.protect_with_blockers, related_name='+', to='specify.spprincipal')), + ], + options={ + 'db_table': 'specifyuser_spprincipal', + }, + ), + migrations.CreateModel( + name='Project_colobj', + fields=[ + ('id', models.AutoField(db_column='ProjectColObjID', primary_key=True, serialize=False)), + ('collectionobject', models.ForeignKey(db_column='CollectionObjectID', on_delete=specifyweb.specify.models.protect_with_blockers, related_name='+', to='specify.collectionobject')), + ('project', models.ForeignKey(db_column='ProjectID', on_delete=specifyweb.specify.models.protect_with_blockers, related_name='+', to='specify.project')), + ], + options={ + 'db_table': 'project_colobj', + }, + ), + migrations.CreateModel( + name='Autonumschdsp', + fields=[ + ('id', models.AutoField(db_column='AutonumSchDspID', primary_key=True, serialize=False)), + ('autonumberingscheme', models.ForeignKey(db_column='AutoNumberingSchemeID', on_delete=specifyweb.specify.models.protect_with_blockers, related_name='+', to='specify.autonumberingscheme')), + ('discipline', models.ForeignKey(db_column='DisciplineID', on_delete=specifyweb.specify.models.protect_with_blockers, related_name='+', to='specify.discipline')), + ], + options={ + 'db_table': 'autonumsch_dsp', + }, + ), + migrations.CreateModel( + name='Autonumschdiv', + fields=[ + ('id', models.AutoField(db_column='AutonumSchDivID', primary_key=True, serialize=False)), + ('autonumberingscheme', models.ForeignKey(db_column='AutoNumberingSchemeID', on_delete=specifyweb.specify.models.protect_with_blockers, related_name='+', to='specify.autonumberingscheme')), + ('division', models.ForeignKey(db_column='DivisionID', on_delete=specifyweb.specify.models.protect_with_blockers, related_name='+', to='specify.division')), + ], + options={ + 'db_table': 'autonumsch_div', + }, + ), + migrations.CreateModel( + name='Autonumschcoll', + fields=[ + ('id', models.AutoField(db_column='AutonumSchCollID', primary_key=True, serialize=False)), + ('autonumberingscheme', models.ForeignKey(db_column='AutoNumberingSchemeID', on_delete=specifyweb.specify.models.protect_with_blockers, related_name='+', to='specify.autonumberingscheme')), + ('collection', models.ForeignKey(db_column='CollectionID', on_delete=specifyweb.specify.models.protect_with_blockers, related_name='+', to='specify.collection')), + ], + options={ + 'db_table': 'autonumsch_coll', + }, + ), + migrations.AddField( + model_name='autonumberingscheme', + name='collections', + field=models.ManyToManyField(related_name='autonumberingschemes', through='specify.Autonumschcoll', to='specify.collection'), + ), + migrations.AddField( + model_name='autonumberingscheme', + name='disciplines', + field=models.ManyToManyField(related_name='autonumberingschemes', through='specify.Autonumschdsp', to='specify.discipline'), + ), + migrations.AddField( + model_name='autonumberingscheme', + name='divisions', + field=models.ManyToManyField(related_name='autonumberingschemes', through='specify.Autonumschdiv', to='specify.division'), + ), + migrations.AddField( + model_name='project', + name='collectionobjects', + field=models.ManyToManyField(related_name='projects', through='specify.Project_colobj', to='specify.collectionobject'), + ), + migrations.AddField( + model_name='specifyuser', + name='spprincipals', + field=models.ManyToManyField(related_name='spprincipals', through='specify.Specifyuser_spprincipal', to='specify.spprincipal'), + ), + migrations.AddField( + model_name='spexportschema', + name='mappings', + field=models.ManyToManyField(related_name='spexportschemas', through='specify.Spexportschema_exportmapping', to='specify.spexportschemamapping'), + ), + migrations.AddField( + model_name='spprincipal', + name='sppermissions', + field=models.ManyToManyField(related_name='spprincipals', through='specify.Spprincipal_sppermission', to='specify.sppermission'), + ), + migrations.AddConstraint( + model_name='spprincipal_sppermission', + constraint=models.UniqueConstraint(fields=('spprincipal', 'sppermission'), name='spprincipal_sppermission'), + ), + migrations.AddConstraint( + model_name='spexportschema_exportmapping', + constraint=models.UniqueConstraint(fields=('spexportschema', 'spexportschemamapping'), name='exportschema_exportmapping'), + ), + migrations.AddConstraint( + model_name='specifyuser_spprincipal', + constraint=models.UniqueConstraint(fields=('specifyuser', 'spprincipal'), name='specifyuser_spprincipal'), + ), + migrations.AddConstraint( + model_name='project_colobj', + constraint=models.UniqueConstraint(fields=('project', 'collectionobject'), name='project_collectionobject'), + ), + migrations.AddConstraint( + model_name='autonumschdsp', + constraint=models.UniqueConstraint(fields=('autonumberingscheme', 'discipline'), name='autonumberingscheme_discipline'), + ), + migrations.AddConstraint( + model_name='autonumschdiv', + constraint=models.UniqueConstraint(fields=('autonumberingscheme', 'division'), name='autonumberingscheme_division'), + ), + migrations.AddConstraint( + model_name='autonumschcoll', + constraint=models.UniqueConstraint(fields=('autonumberingscheme', 'collection'), name='autonumberingscheme_collection'), + ), ] diff --git a/specifyweb/specify/models.py b/specifyweb/specify/models.py index d78f01d3e0c..9615d4b1179 100644 --- a/specifyweb/specify/models.py +++ b/specifyweb/specify/models.py @@ -741,6 +741,26 @@ class Autonumberingscheme(models.Model): createdbyagent = models.ForeignKey('Agent', db_column='CreatedByAgentID', related_name='+', null=True, on_delete=protect_with_blockers) modifiedbyagent = models.ForeignKey('Agent', db_column='ModifiedByAgentID', related_name='+', null=True, on_delete=protect_with_blockers) + # Relationships: Many-to-Many + collections = models.ManyToManyField( + "Collection", + through="Autonumschcoll", + through_fields=("autonumberingscheme", "collection"), + related_name="autonumberingschemes" + ) + disciplines = models.ManyToManyField( + "Discipline", + through="Autonumschdsp", + through_fields=("autonumberingscheme", "discipline"), + related_name="autonumberingschemes" + ) + divisions = models.ManyToManyField( + "Division", + through="Autonumschdiv", + through_fields=("autonumberingscheme", "division"), + related_name="autonumberingschemes" + ) + class Meta: db_table = 'autonumberingscheme' ordering = () @@ -5583,6 +5603,14 @@ class Project(models.Model): createdbyagent = models.ForeignKey('Agent', db_column='CreatedByAgentID', related_name='+', null=True, on_delete=protect_with_blockers) modifiedbyagent = models.ForeignKey('Agent', db_column='ModifiedByAgentID', related_name='+', null=True, on_delete=protect_with_blockers) + # Relationships: Many-to-Many + collectionobjects = models.ManyToManyField( + 'CollectionObject', + through="Project_colobj", + through_fields=("project", "collectionobject"), + related_name="projects" + ) + class Meta: db_table = 'project' ordering = () @@ -6042,6 +6070,14 @@ class Spexportschema(models.Model): discipline = models.ForeignKey('Discipline', db_column='DisciplineID', related_name='spexportschemas', null=False, on_delete=protect_with_blockers) modifiedbyagent = models.ForeignKey('Agent', db_column='ModifiedByAgentID', related_name='+', null=True, on_delete=protect_with_blockers) + # Relationships: Many-to-Many + mappings = models.ManyToManyField( + "Spexportschemamapping", + through="Spexportschema_exportmapping", + through_fields=("spexportschema", "spexportschemamapping"), + related_name="spexportschemas" + ) + class Meta: db_table = 'spexportschema' ordering = () @@ -6309,6 +6345,14 @@ class Spprincipal(models.Model): modifiedbyagent = models.ForeignKey('Agent', db_column='ModifiedByAgentID', related_name='+', null=True, on_delete=protect_with_blockers) userGroupScopeID = models.IntegerField(blank=True, null=True, db_column='userGroupScopeID') + # Relationships: Many-to-Many + sppermissions = models.ManyToManyField( + "SpPermission", + through="Spprincipal_sppermission", + through_fields=("spprincipal", "sppermission"), + related_name="spprincipals" + ) + class Meta: db_table = 'spprincipal' ordering = () @@ -6609,6 +6653,14 @@ class Specifyuser(model_extras.Specifyuser): createdbyagent = models.ForeignKey('Agent', db_column='CreatedByAgentID', related_name='+', null=True, on_delete=protect_with_blockers) modifiedbyagent = models.ForeignKey('Agent', db_column='ModifiedByAgentID', related_name='+', null=True, on_delete=protect_with_blockers) + # Relationships: Many-to-Many + spprincipals = models.ManyToManyField( + "SpPrincipal", + through="Specifyuser_spprincipal", + through_fields=("specifyuser", "spprincipal"), + related_name="spprincipals" + ) + class Meta: db_table = 'specifyuser' ordering = () @@ -7988,4 +8040,108 @@ class Meta: db_table = 'tectonicunit' ordering = () - save = partialmethod(custom_save) \ No newline at end of file + save = partialmethod(custom_save) + +class Autonumschcoll(models.Model): + # specify_model = datamodel.get_table_strict("Autonumschcoll") + + id = models.AutoField(primary_key=True, db_column='AutonumSchCollID') + + autonumberingscheme = models.ForeignKey('Autonumberingscheme', db_column='AutoNumberingSchemeID', related_name="+", on_delete=protect_with_blockers) + collection = models.ForeignKey('Collection', db_column='CollectionID', related_name="+", on_delete=protect_with_blockers) + + save = partialmethod(custom_save) + + class Meta: + db_table='autonumsch_coll' + constraints = [ + models.UniqueConstraint(fields=["autonumberingscheme", "collection"], name="autonumberingscheme_collection") + ] + +class Autonumschdsp(models.Model): + # specify_model = datamodel.get_table_strict("Autonumschdsp") + + id = models.AutoField(primary_key=True, db_column='AutonumSchDspID') + + autonumberingscheme = models.ForeignKey('Autonumberingscheme', db_column='AutoNumberingSchemeID', related_name="+", on_delete=protect_with_blockers) + discipline = models.ForeignKey('Discipline', db_column='DisciplineID', related_name="+", on_delete=protect_with_blockers) + + save = partialmethod(custom_save) + + class Meta: + db_table='autonumsch_dsp' + constraints = [ + models.UniqueConstraint(fields=["autonumberingscheme", "discipline"], name="autonumberingscheme_discipline") + ] + +class Autonumschdiv(models.Model): + # specify_model = datamodel.get_table_strict("Autonumschdiv") + + id = models.AutoField(primary_key=True, db_column='AutonumSchDivID') + + autonumberingscheme = models.ForeignKey('Autonumberingscheme', db_column='AutoNumberingSchemeID', related_name="+", on_delete=protect_with_blockers) + division = models.ForeignKey('Division', db_column='DivisionID', related_name="+", on_delete=protect_with_blockers) + + save = partialmethod(custom_save) + + class Meta: + db_table='autonumsch_div' + constraints = [ + models.UniqueConstraint(fields=["autonumberingscheme", "division"], name="autonumberingscheme_division") + ] + +class Specifyuser_spprincipal(models.Model): + id = models.AutoField(primary_key=True, db_column='SpeicfyuserSpPrincipalID') + + specifyuser = models.ForeignKey('SpecifyUser', db_column='SpecifyUserID', on_delete=models.CASCADE, related_name="+") + spprincipal = models.ForeignKey('SpPrincipal', db_column='SpPrincipalID', on_delete=protect_with_blockers, related_name="+") + + save = partialmethod(custom_save) + + class Meta: + db_table = 'specifyuser_spprincipal' + constraints = [ + models.UniqueConstraint(fields=["specifyuser", "spprincipal"], name="specifyuser_spprincipal") + ] + +class Spprincipal_sppermission(models.Model): + id = models.AutoField(primary_key=True, db_column='SpPrincipalSpPermissionID') + + sppermission = models.ForeignKey('SpPermission', db_column='SpPermissionID', related_name="+", on_delete=protect_with_blockers) + spprincipal = models.ForeignKey('SpPrincipal', db_column='SpPrincipalID', related_name="+", on_delete=protect_with_blockers) + + save = partialmethod(custom_save) + + class Meta: + db_table = 'spprincipal_sppermission' + constraints = [ + models.UniqueConstraint(fields=["spprincipal", "sppermission"], name="spprincipal_sppermission") + ] + +class Project_colobj(models.Model): + id = models.AutoField(primary_key=True, db_column='ProjectColObjID') + + project = models.ForeignKey('Project', db_column='ProjectID', related_name="+", on_delete=protect_with_blockers) + collectionobject = models.ForeignKey('CollectionObject', db_column='CollectionObjectID', related_name="+", on_delete=protect_with_blockers) + + save = partialmethod(custom_save) + + class Meta: + db_table = 'project_colobj' + constraints = [ + models.UniqueConstraint(fields=["project", "collectionobject"], name="project_collectionobject") + ] + +class Spexportschema_exportmapping(models.Model): + id = models.AutoField(primary_key=True, db_column='SpExportSchemaExportMappingID') + + spexportschema = models.ForeignKey('Spexportschema', db_column='SpExportSchemaID', related_name="+", on_delete=protect_with_blockers) + spexportschemamapping = models.ForeignKey('Spexportschemamapping',db_column='SpExportSchemaMappingID', related_name="+", on_delete=protect_with_blockers) + + save = partialmethod(custom_save) + + class Meta: + db_table = 'sp_schema_mapping' + constraints = [ + models.UniqueConstraint(fields=["spexportschema", "spexportschemamapping"], name="exportschema_exportmapping") + ] \ No newline at end of file diff --git a/specifyweb/specify/models_utils/load_datamodel.py b/specifyweb/specify/models_utils/load_datamodel.py index 0432496fab0..dbe2c8f8f72 100644 --- a/specifyweb/specify/models_utils/load_datamodel.py +++ b/specifyweb/specify/models_utils/load_datamodel.py @@ -368,6 +368,35 @@ def __init__( def is_remote_to_one(self): return self.type == "one-to-one" and self.column == None +# REFACTOR: extract other relationship types from base Relationship? +class ManyToMany(Relationship): + through_model: str + through_field: str + + def __init__(self, + name = None, + required = None, + relatedModelName = None, + otherSideName = None, + through_model = None, + through_field = None): + super().__init__(name=name, + type='many-to-many', + is_relationship=True, + #FEATURE: add support for dependent many-to-many + dependent=False, + required=required, + relatedModelName=relatedModelName, + otherSideName=otherSideName) + if through_model is None: + raise ValueError("A through model must be specified for a \ + ManyToMany Relationship!") + if through_field is None: + raise ValueError("A column on the through table for the source \ + side must be specified!") + + self.through_model = through_model + self.through_field = through_field def make_table(tabledef: ElementTree.Element) -> Table: iddef = tabledef.find("id") diff --git a/specifyweb/specify/models_utils/model_timestamp.py b/specifyweb/specify/models_utils/model_timestamp.py index 0080174df18..800f07d10b6 100644 --- a/specifyweb/specify/models_utils/model_timestamp.py +++ b/specifyweb/specify/models_utils/model_timestamp.py @@ -12,8 +12,11 @@ def save_auto_timestamp_field_with_override(save_func, args, kwargs, obj): fields_to_update = kwargs.get('update_fields', None) if fields_to_update is None: fields_to_update = [ - field.name for field in model._meta.get_fields(include_hidden=True) if field.concrete + field.name for field in model._meta.get_fields(include_hidden=True) + if field.concrete and not field.primary_key + # FEATURE: add support for patching in many_to_many changes + and not getattr(field, "many_to_many", False) ] if obj.id is not None: diff --git a/specifyweb/specify/models_utils/models_by_table_id.py b/specifyweb/specify/models_utils/models_by_table_id.py index 6132fb5088f..56ed4c6030c 100644 --- a/specifyweb/specify/models_utils/models_by_table_id.py +++ b/specifyweb/specify/models_utils/models_by_table_id.py @@ -217,7 +217,14 @@ 1026:'Tectonicunittreedefitem', 1027:'Tectonicunit', 1028:'Spdatasetattachment', - 1029: 'Component' + 1029: 'Component', + 1030:'Autonumschcoll', + 1031:'Autonumschdiv', + 1032:'Autonumschdsp', + 1033:'Project_colobj', + 1034:'Spexportschema_exportmapping', + 1035:'Specifyuser_spprincipal', + 1036:'Spprincipal_sppermission', } model_names_by_app = { @@ -448,7 +455,14 @@ 'Tectonicunittreedef', 'Tectonicunittreedefitem', 'Tectonicunit', - 'Component' + 'Component', + 'Autonumschcoll', + 'Autonumschdiv', + 'Autonumschdsp', + 'Project_colobj', + 'Spexportschema_exportmapping', + 'Specifyuser_spprincipal', + 'Spprincipal_sppermission', } }