From ec9fa069646540cbb3b2c5e65a3035697147832d Mon Sep 17 00:00:00 2001 From: dglemos Date: Thu, 6 Feb 2025 16:24:26 +0000 Subject: [PATCH 1/3] Endpoint to do bulk updates of disease --- .../gene2phenotype_app/urls.py | 5 + .../gene2phenotype_app/views/__init__.py | 3 +- .../gene2phenotype_app/views/disease.py | 103 +++++++++++++++++- 3 files changed, 106 insertions(+), 5 deletions(-) diff --git a/gene2phenotype_project/gene2phenotype_app/urls.py b/gene2phenotype_project/gene2phenotype_app/urls.py index c841303d..0f419632 100644 --- a/gene2phenotype_project/gene2phenotype_app/urls.py +++ b/gene2phenotype_project/gene2phenotype_app/urls.py @@ -59,6 +59,11 @@ def perform_create(self, serializer): path('lgd//comment/', views.LGDEditComment.as_view(), name="lgd_comment"), # Delete LGD record. Action: UPDATE path('lgd//delete/', views.LocusGenotypeDiseaseDelete.as_view(), name="lgd_delete"), + # Update disease IDs for LGD records. Action: POST + path('lgd_disease_updates/', views.LGDUpdateDisease.as_view(), name="lgd_disease_updates"), + + ### Endpoints to update other data ### + path('update/diseases/', views.UpdateDisease.as_view(), name="update_diseases"), ### Curation endpoints ### path('add/curation/', views.AddCurationData.as_view(), name="add_curation_data"), diff --git a/gene2phenotype_project/gene2phenotype_app/views/__init__.py b/gene2phenotype_project/gene2phenotype_app/views/__init__.py index 213544b2..566b6604 100644 --- a/gene2phenotype_project/gene2phenotype_app/views/__init__.py +++ b/gene2phenotype_project/gene2phenotype_app/views/__init__.py @@ -5,7 +5,8 @@ from .locus import LocusGene, LocusGeneSummary, GeneFunction -from .disease import GeneDiseaseView, DiseaseDetail, DiseaseSummary, AddDisease +from .disease import (GeneDiseaseView, DiseaseDetail, DiseaseSummary, AddDisease, + UpdateDisease, LGDUpdateDisease) from .curation import (AddCurationData, ListCurationEntries, CurationDataDetail, UpdateCurationData, PublishRecord, DeleteCurationData) diff --git a/gene2phenotype_project/gene2phenotype_app/views/disease.py b/gene2phenotype_project/gene2phenotype_app/views/disease.py index 3861c237..4eba7105 100644 --- a/gene2phenotype_project/gene2phenotype_app/views/disease.py +++ b/gene2phenotype_project/gene2phenotype_app/views/disease.py @@ -1,6 +1,7 @@ -from rest_framework import permissions +from rest_framework import permissions, status from rest_framework.response import Response from django.db.models import Q +from django.shortcuts import get_object_or_404 from gene2phenotype_app.serializers import (GeneDiseaseSerializer, DiseaseDetailSerializer, @@ -8,10 +9,10 @@ from gene2phenotype_app.models import (AttribType, Locus, OntologyTerm, DiseaseOntologyTerm, Disease, - LocusAttrib, GeneDisease) + LocusAttrib, GeneDisease, LocusGenotypeDisease) from ..utils import clean_omim_disease -from .base import BaseView, BaseAdd +from .base import BaseView, BaseAdd, IsSuperUser class GeneDiseaseView(BaseView): """ @@ -147,4 +148,98 @@ def list(self, request, *args, **kwargs): """ class AddDisease(BaseAdd): serializer_class = CreateDiseaseSerializer - permission_classes = [permissions.IsAuthenticated] + permission_classes = [permissions.IsAuthenticated, IsSuperUser] + +### Update data +class UpdateDisease(BaseAdd): + http_method_names = ['post', 'options'] + permission_classes = [permissions.IsAuthenticated, IsSuperUser] + + def post(self, request): + diseases = request.data # list of diseases {'id': ..., 'name': ...} + + if not isinstance(diseases, list): + return Response({"error": "Request should be a list"}, status=status.HTTP_400_BAD_REQUEST) + + updated_diseases = [] + errors = [] + + for disease_data in diseases: + disease_id = disease_data.get("id") + new_name = disease_data.get("name") + + if not disease_id or not new_name: + errors.append({"error": "Both 'id' and 'name' are required."}) + continue + + # Fetch disease or return 404 if not found + disease = get_object_or_404(Disease, id=disease_id) + + # Ensure the new name is unique + check_disease = Disease.objects.filter(name=new_name).exclude(id=disease_id) + if check_disease: + errors.append({ + "id": disease_id, + "name": new_name, + "existing_id": check_disease[0].id, + "error": f"A disease with the name '{new_name}' already exists." + }) + continue + + # Update and save + disease.name = new_name + disease.save() + updated_diseases.append({"id": disease_id, "name": new_name}) + + response_data = {"updated": updated_diseases} + if errors: + response_data["errors"] = errors + + return Response(response_data, status=status.HTTP_200_OK if updated_diseases else status.HTTP_400_BAD_REQUEST) + +class LGDUpdateDisease(BaseAdd): + http_method_names = ['post', 'options'] + permission_classes = [permissions.IsAuthenticated, IsSuperUser] + + def post(self, request): + data_to_update = request.data + + if not isinstance(data_to_update, list): + return Response({"error": "Request should be a list"}, status=status.HTTP_400_BAD_REQUEST) + + updated_records = [] + errors = [] + + for disease_to_update in data_to_update: + current_disease_id = disease_to_update.get("disease_id") + new_disease_id = disease_to_update.get("new_disease_id") + + if not current_disease_id or not new_disease_id: + errors.append({"error": "Both 'disease_id' and 'new_disease_id' are required."}) + continue + + # Get records that use the disease id + lgd_list = LocusGenotypeDisease.objects.filter(disease_id=current_disease_id, is_deleted=0) + + for lgd_obj in lgd_list: + # Check if there is another LGD record linked to the new disease id + try: + existing_lgd_obj = LocusGenotypeDisease.objects.get( + locus_id = lgd_obj.locus_id, + disease_id = new_disease_id, + genotype_id = lgd_obj.genotype_id, + mechanism_id = lgd_obj.mechanism_id + ) + errors.append({"disease_id": current_disease_id, "error": f"Found a different record with same locus, genotype, disease and mechanism: '{existing_lgd_obj.stable_id.stable_id}'"}) + except: + # Update record with new disease id + lgd_obj.disease_id = new_disease_id + lgd_obj.save() + updated_records.append({"g2p_id": lgd_obj.stable_id.stable_id, "lgd_id": lgd_obj.id}) + + response_data = { + "Updated records": updated_records, + "Errors": errors + } + + return Response(response_data, status=status.HTTP_200_OK) \ No newline at end of file From c87073186a84881d97f8a8831b85b1780bd1a5b8 Mon Sep 17 00:00:00 2001 From: dglemos Date: Mon, 10 Feb 2025 15:51:08 +0000 Subject: [PATCH 2/3] improve messages --- .../gene2phenotype_app/views/disease.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/gene2phenotype_project/gene2phenotype_app/views/disease.py b/gene2phenotype_project/gene2phenotype_app/views/disease.py index 4eba7105..56a0afef 100644 --- a/gene2phenotype_project/gene2phenotype_app/views/disease.py +++ b/gene2phenotype_project/gene2phenotype_app/views/disease.py @@ -191,7 +191,10 @@ def post(self, request): disease.save() updated_diseases.append({"id": disease_id, "name": new_name}) - response_data = {"updated": updated_diseases} + response_data = {} + if updated_diseases: + response_data["updated"] = updated_diseases + if errors: response_data["errors"] = errors @@ -237,9 +240,11 @@ def post(self, request): lgd_obj.save() updated_records.append({"g2p_id": lgd_obj.stable_id.stable_id, "lgd_id": lgd_obj.id}) - response_data = { - "Updated records": updated_records, - "Errors": errors - } + response_data = {} + if updated_records: + response_data["Updated records"] = updated_records + + if errors: + response_data["Errors"] = errors - return Response(response_data, status=status.HTTP_200_OK) \ No newline at end of file + return Response(response_data, status=status.HTTP_200_OK if updated_records else status.HTTP_400_BAD_REQUEST) \ No newline at end of file From 577e9b12e62a95772abe978e6432ebffdf2d15f3 Mon Sep 17 00:00:00 2001 From: dglemos Date: Tue, 11 Feb 2025 13:27:27 +0000 Subject: [PATCH 3/3] Update permission --- gene2phenotype_project/gene2phenotype_app/views/disease.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gene2phenotype_project/gene2phenotype_app/views/disease.py b/gene2phenotype_project/gene2phenotype_app/views/disease.py index 56a0afef..cd425ee6 100644 --- a/gene2phenotype_project/gene2phenotype_app/views/disease.py +++ b/gene2phenotype_project/gene2phenotype_app/views/disease.py @@ -148,12 +148,12 @@ def list(self, request, *args, **kwargs): """ class AddDisease(BaseAdd): serializer_class = CreateDiseaseSerializer - permission_classes = [permissions.IsAuthenticated, IsSuperUser] + permission_classes = [IsSuperUser] ### Update data class UpdateDisease(BaseAdd): http_method_names = ['post', 'options'] - permission_classes = [permissions.IsAuthenticated, IsSuperUser] + permission_classes = [IsSuperUser] def post(self, request): diseases = request.data # list of diseases {'id': ..., 'name': ...} @@ -202,7 +202,7 @@ def post(self, request): class LGDUpdateDisease(BaseAdd): http_method_names = ['post', 'options'] - permission_classes = [permissions.IsAuthenticated, IsSuperUser] + permission_classes = [IsSuperUser] def post(self, request): data_to_update = request.data