From 09c586c390b74c85fdb7bfe7bebff882be3232f4 Mon Sep 17 00:00:00 2001 From: Caroline D <108160931+CarolineDenis@users.noreply.github.com> Date: Thu, 28 Mar 2024 10:55:47 -0700 Subject: [PATCH 1/5] Fixes agent merging failing unexpectedly Fixes #4685 --- specifyweb/specify/record_merging.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/specifyweb/specify/record_merging.py b/specifyweb/specify/record_merging.py index d813288d030..2fa9933c934 100644 --- a/specifyweb/specify/record_merging.py +++ b/specifyweb/specify/record_merging.py @@ -197,13 +197,12 @@ def record_merge_fx(model_name: str, old_model_ids: List[int], new_model_id: int # Fix by optimizing the query by consolidating it here if model_name.lower() in MERGING_OPTIMIZATION_FIELDS and \ table_name.lower() in MERGING_OPTIMIZATION_FIELDS[model_name.lower()]: - for field_name in MERGING_OPTIMIZATION_FIELDS[model_name.lower()][table_name.lower()]: + if field_name in MERGING_OPTIMIZATION_FIELDS[model_name.lower()][table_name.lower()]: query = Q(**{field_name: old_model_ids[0]}) for old_model_id in old_model_ids[1:]: query.add(Q(**{field_name: old_model_id}), Q.OR) foreign_model.objects.filter(query).update(**{field_name: new_model_id}) progress(1, 0) if progress is not None else None - continue apply_order = add_ordering_to_key(table_name.lower().title()) # BUG: timestampmodified could be null for one record, and not the other From 3da80c950551aa290c941beb888d29309c863eba Mon Sep 17 00:00:00 2001 From: Caroline D <108160931+CarolineDenis@users.noreply.github.com> Date: Thu, 28 Mar 2024 12:55:50 -0700 Subject: [PATCH 2/5] Add continue back --- specifyweb/specify/record_merging.py | 1 + 1 file changed, 1 insertion(+) diff --git a/specifyweb/specify/record_merging.py b/specifyweb/specify/record_merging.py index 2fa9933c934..ff5e644c4fd 100644 --- a/specifyweb/specify/record_merging.py +++ b/specifyweb/specify/record_merging.py @@ -203,6 +203,7 @@ def record_merge_fx(model_name: str, old_model_ids: List[int], new_model_id: int query.add(Q(**{field_name: old_model_id}), Q.OR) foreign_model.objects.filter(query).update(**{field_name: new_model_id}) progress(1, 0) if progress is not None else None + continue apply_order = add_ordering_to_key(table_name.lower().title()) # BUG: timestampmodified could be null for one record, and not the other From 7722dee5df07703d991d56de46376ac42c355367 Mon Sep 17 00:00:00 2001 From: Caroline D <108160931+CarolineDenis@users.noreply.github.com> Date: Thu, 28 Mar 2024 13:51:34 -0700 Subject: [PATCH 3/5] use failedMergingExecption --- specifyweb/specify/record_merging.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specifyweb/specify/record_merging.py b/specifyweb/specify/record_merging.py index ff5e644c4fd..5401bc060d0 100644 --- a/specifyweb/specify/record_merging.py +++ b/specifyweb/specify/record_merging.py @@ -308,7 +308,7 @@ def update_record(record: models.Model): response: http.HttpResponse = update_record(obj) if response is not None and response.status_code != 204: - return response + raise FailedMergingException(response) # Dedupe by deleting the record that is being replaced and updating the old model ID to the new one for old_model_id in old_model_ids: From 9ca828a7521ff0122c0183a223f2195a1fd7a3b8 Mon Sep 17 00:00:00 2001 From: Caroline D <108160931+CarolineDenis@users.noreply.github.com> Date: Thu, 28 Mar 2024 14:20:33 -0700 Subject: [PATCH 4/5] Modify unit tests --- specifyweb/specify/api_tests.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/specifyweb/specify/api_tests.py b/specifyweb/specify/api_tests.py index 739ec5624b1..dd3328a199a 100644 --- a/specifyweb/specify/api_tests.py +++ b/specifyweb/specify/api_tests.py @@ -584,7 +584,8 @@ def test_replace_agents(self): agent=agent_1, collectingevent=collecting_event ) - + self.collectionobjects[0].cataloger = agent_1 + self.collectionobjects[0].save() # Assert that the api request ran successfully response = c.post( f'/api/specify/agent/replace/{agent_2.id}/', From 049960a9128c21c0ae75d25e5f28f0d40b936aaa Mon Sep 17 00:00:00 2001 From: Caroline D <108160931+CarolineDenis@users.noreply.github.com> Date: Fri, 29 Mar 2024 09:44:08 -0700 Subject: [PATCH 5/5] move code --- specifyweb/specify/record_merging.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/specifyweb/specify/record_merging.py b/specifyweb/specify/record_merging.py index 5401bc060d0..ed4c2fee106 100644 --- a/specifyweb/specify/record_merging.py +++ b/specifyweb/specify/record_merging.py @@ -192,18 +192,6 @@ def record_merge_fx(model_name: str, old_model_ids: List[int], new_model_id: int except ValueError: continue - # Handle case of updating a large amount of record ids in a foreign table. - # Example: handle case of updating a large amount of agent ids in the audit logs. - # Fix by optimizing the query by consolidating it here - if model_name.lower() in MERGING_OPTIMIZATION_FIELDS and \ - table_name.lower() in MERGING_OPTIMIZATION_FIELDS[model_name.lower()]: - if field_name in MERGING_OPTIMIZATION_FIELDS[model_name.lower()][table_name.lower()]: - query = Q(**{field_name: old_model_ids[0]}) - for old_model_id in old_model_ids[1:]: - query.add(Q(**{field_name: old_model_id}), Q.OR) - foreign_model.objects.filter(query).update(**{field_name: new_model_id}) - progress(1, 0) if progress is not None else None - continue apply_order = add_ordering_to_key(table_name.lower().title()) # BUG: timestampmodified could be null for one record, and not the other @@ -221,6 +209,18 @@ def record_merge_fx(model_name: str, old_model_ids: List[int], new_model_id: int field_name_id = f'{field_name}_id' if not hasattr(foreign_model, field_name_id): continue + # Handle case of updating a large amount of record ids in a foreign table. + # Example: handle case of updating a large amount of agent ids in the audit logs. + # Fix by optimizing the query by consolidating it here + if model_name.lower() in MERGING_OPTIMIZATION_FIELDS and \ + table_name.lower() in MERGING_OPTIMIZATION_FIELDS[model_name.lower()]: + if field_name_id in MERGING_OPTIMIZATION_FIELDS[model_name.lower()][table_name.lower()]: + query = Q(**{field_name_id: old_model_ids[0]}) + for old_model_id in old_model_ids[1:]: + query.add(Q(**{field_name_id: old_model_id}), Q.OR) + foreign_model.objects.filter(query).update(**{field_name_id: new_model_id}) + progress(1, 0) if progress is not None else None + continue # Filter the objects in the foreign model that references the old target model foreign_objects = filter_and_lock_target_objects(foreign_model, old_model_ids, field_name_id)