From 54968da37230944dc01ca530a845842b6843fc7d Mon Sep 17 00:00:00 2001 From: Prafful Sharma Date: Wed, 28 Jan 2026 11:59:29 +0530 Subject: [PATCH 1/4] N+1 issues --- care/emr/api/viewsets/patient.py | 12 +++++++++--- care/emr/api/viewsets/scheduling/booking.py | 1 + care/emr/models/patient.py | 7 +++++-- care/emr/resources/allergy_intolerance/spec.py | 6 +----- care/emr/resources/condition/spec.py | 5 +---- care/emr/resources/device/history_spec.py | 8 +++----- care/emr/resources/encounter/spec.py | 8 ++++++-- care/emr/resources/facility_organization/spec.py | 6 +----- care/emr/resources/file_upload/spec.py | 14 +++++++------- care/emr/resources/location/spec.py | 6 +----- .../resources/medication/administration/spec.py | 6 +++--- care/emr/resources/meta_artifact/spec.py | 5 +---- care/emr/resources/notes/notes_spec.py | 10 +++------- care/emr/resources/notes/thread_spec.py | 10 +++------- care/emr/resources/observation/spec.py | 13 +++++++------ .../emr/resources/observation_definition/spec.py | 10 +++++----- care/emr/resources/patient/spec.py | 6 +----- care/emr/resources/questionnaire/spec.py | 5 +---- .../emr/resources/questionnaire_response/spec.py | 5 +---- care/emr/resources/report/template/spec.py | 10 +++++----- care/emr/resources/resource_request/spec.py | 16 ++++++---------- care/emr/resources/tag/config_spec.py | 15 ++++++++++----- care/emr/resources/user/spec.py | 3 ++- care/emr/resources/valueset/spec.py | 5 +---- 24 files changed, 84 insertions(+), 108 deletions(-) diff --git a/care/emr/api/viewsets/patient.py b/care/emr/api/viewsets/patient.py index 43bfbb0d3a..a0c2d91d84 100644 --- a/care/emr/api/viewsets/patient.py +++ b/care/emr/api/viewsets/patient.py @@ -250,7 +250,9 @@ def search(self, request, *args, **kwargs): ): partial = True - queryset = queryset.order_by("-created_date")[:page_size] + queryset = queryset.select_related("geo_organization").order_by( + "-created_date" + )[:page_size] if partial: data = [PatientPartialSpec.serialize(obj).to_json() for obj in queryset] return Response({"partial": True, "results": data}) @@ -268,7 +270,9 @@ class SearchRetrieveRequestSpec(BaseModel): @action(detail=False, methods=["POST"]) def search_retrieve(self, request, *args, **kwargs): request_data = self.SearchRetrieveRequestSpec(**request.data) - queryset = Patient.objects.filter(phone_number=request_data.phone_number) + queryset = Patient.objects.filter( + phone_number=request_data.phone_number + ).select_related("geo_organization") queryset = queryset.filter(year_of_birth=request_data.year_of_birth) for patient in queryset: if str(patient.external_id)[:5] == request_data.partial_id: @@ -283,7 +287,9 @@ def search_retrieve(self, request, *args, **kwargs): @action(detail=True, methods=["GET"]) def get_users(self, request, *args, **kwargs): patient = self.get_object() - patient_users = PatientUser.objects.filter(patient=patient) + patient_users = PatientUser.objects.filter(patient=patient).select_related( + "user" + ) data = [ UserSpec.serialize(patient_user.user).to_json() for patient_user in patient_users diff --git a/care/emr/api/viewsets/scheduling/booking.py b/care/emr/api/viewsets/scheduling/booking.py index 232fc52345..c91ea18860 100644 --- a/care/emr/api/viewsets/scheduling/booking.py +++ b/care/emr/api/viewsets/scheduling/booking.py @@ -274,6 +274,7 @@ def available_users(self, request, *args, **kwargs): user_id__in=facility_organization_users.values("user_id") ) + user_resources = user_resources.select_related("user") return Response( { "users": [ diff --git a/care/emr/models/patient.py b/care/emr/models/patient.py index a704c42461..0e3549bd97 100644 --- a/care/emr/models/patient.py +++ b/care/emr/models/patient.py @@ -190,8 +190,11 @@ def get_config(cls, config_id) -> PatientIdentifierConfig: from care.emr.resources.patient_identifier.spec import PatientIdentifierListSpec if config_id not in cls.configs: - cls.configs[config_id] = PatientIdentifierListSpec.serialize( - PatientIdentifierConfig.objects.get(external_id=config_id) + config = PatientIdentifierConfig.objects.only("id").get( + external_id=config_id + ) + cls.configs[config_id] = model_from_cache( + PatientIdentifierListSpec, id=config.id ).to_json() return cls.configs[config_id] diff --git a/care/emr/resources/allergy_intolerance/spec.py b/care/emr/resources/allergy_intolerance/spec.py index b56dffa37e..fee0e4eb58 100644 --- a/care/emr/resources/allergy_intolerance/spec.py +++ b/care/emr/resources/allergy_intolerance/spec.py @@ -8,7 +8,6 @@ from care.emr.resources.allergy_intolerance.valueset import CARE_ALLERGY_CODE_VALUESET from care.emr.resources.base import EMRResource from care.emr.resources.common.coding import Coding -from care.emr.resources.user.spec import UserSpec from care.emr.utils.valueset_coding_type import ValueSetBoundCoding @@ -134,9 +133,6 @@ class AllergyIntoleranceReadSpec(BaseAllergyIntoleranceSpec): @classmethod def perform_extra_serialization(cls, mapping, obj): mapping["id"] = obj.external_id - if obj.created_by: - mapping["created_by"] = UserSpec.serialize(obj.created_by) - if obj.updated_by: - mapping["updated_by"] = UserSpec.serialize(obj.updated_by) + cls.serialize_audit_users(mapping, obj) if obj.encounter: mapping["encounter"] = obj.encounter.external_id diff --git a/care/emr/resources/condition/spec.py b/care/emr/resources/condition/spec.py index 94a3e55ffe..460d7fee56 100644 --- a/care/emr/resources/condition/spec.py +++ b/care/emr/resources/condition/spec.py @@ -131,10 +131,7 @@ def perform_extra_serialization(cls, mapping, obj): if obj.encounter: mapping["encounter"] = obj.encounter.external_id - if obj.created_by: - mapping["created_by"] = UserSpec.serialize(obj.created_by) - if obj.updated_by: - mapping["updated_by"] = UserSpec.serialize(obj.updated_by) + cls.serialize_audit_users(mapping, obj) class ConditionUpdateSpec(BaseConditionSpec): diff --git a/care/emr/resources/device/history_spec.py b/care/emr/resources/device/history_spec.py index 35dda7b4f9..d6640d311f 100644 --- a/care/emr/resources/device/history_spec.py +++ b/care/emr/resources/device/history_spec.py @@ -3,9 +3,8 @@ from pydantic import UUID4 from care.emr.models import DeviceServiceHistory -from care.emr.resources.base import EMRResource +from care.emr.resources.base import EMRResource, model_from_cache from care.emr.resources.user.spec import UserSpec -from care.users.models import User class DeviceServiceHistorySpecBase(EMRResource): @@ -41,9 +40,8 @@ def perform_extra_serialization(cls, mapping, obj): edit_history = [] for history in obj.edit_history: user = history.get("updated_by") - user_obj = User.objects.filter(id=user).first() - if user_obj: - history["updated_by"] = UserSpec.serialize(user_obj).to_json() + if user: + history["updated_by"] = model_from_cache(UserSpec, id=user) else: history["updated_by"] = {} # Edge Case edit_history.append(history) diff --git a/care/emr/resources/encounter/spec.py b/care/emr/resources/encounter/spec.py index 4ea072e906..3e448ad457 100644 --- a/care/emr/resources/encounter/spec.py +++ b/care/emr/resources/encounter/spec.py @@ -131,7 +131,9 @@ class EncounterListSpec(EncounterSpecBase): def perform_extra_serialization(cls, mapping, obj): mapping["id"] = obj.external_id mapping["patient"] = PatientListSpec.serialize(obj.patient).to_json() - mapping["facility"] = FacilityBareMinimumSpec.serialize(obj.facility).to_json() + mapping["facility"] = model_from_cache( + FacilityBareMinimumSpec, id=obj.facility_id + ) mapping["tags"] = SingleFacilityTagManager().render_tags(obj) mapping["current_location"] = None if obj.current_location: @@ -155,7 +157,9 @@ def perform_extra_serialization(cls, mapping, obj): mapping["patient"] = PatientRetrieveSpec.serialize( obj.patient, facility=obj.facility ).to_json() - mapping["facility"] = FacilityBareMinimumSpec.serialize(obj.facility).to_json() + mapping["facility"] = model_from_cache( + FacilityBareMinimumSpec, id=obj.facility_id + ) mapping["tags"] = SingleFacilityTagManager().render_tags(obj) if obj.appointment: mapping["appointment"] = TokenBookingReadSpec.serialize( diff --git a/care/emr/resources/facility_organization/spec.py b/care/emr/resources/facility_organization/spec.py index 3dbb56bdaf..857b020e43 100644 --- a/care/emr/resources/facility_organization/spec.py +++ b/care/emr/resources/facility_organization/spec.py @@ -85,11 +85,7 @@ class FacilityOrganizationReadSpec(FacilityOrganizationBaseSpec): def perform_extra_serialization(cls, mapping, obj): mapping["id"] = obj.external_id mapping["parent"] = obj.get_parent_json() - - if obj.created_by: - mapping["created_by"] = UserSpec.serialize(obj.created_by) - if obj.updated_by: - mapping["updated_by"] = UserSpec.serialize(obj.updated_by) + cls.serialize_audit_users(mapping, obj) class FacilityOrganizationRetrieveSpec(FacilityOrganizationReadSpec): diff --git a/care/emr/resources/file_upload/spec.py b/care/emr/resources/file_upload/spec.py index 41300f0183..a2d57e4d02 100644 --- a/care/emr/resources/file_upload/spec.py +++ b/care/emr/resources/file_upload/spec.py @@ -6,7 +6,7 @@ from pydantic import UUID4, field_validator from care.emr.models import FileUpload -from care.emr.resources.base import EMRResource +from care.emr.resources.base import EMRResource, model_from_cache from care.emr.resources.user.spec import UserSpec from care.utils.models.validators import file_name_validator @@ -92,10 +92,10 @@ def perform_extra_serialization(cls, mapping, obj): mapping["id"] = obj.external_id mapping["extension"] = obj.get_extension() mapping["mime_type"] = obj.meta.get("mime_type") - if obj.created_by: - mapping["uploaded_by"] = UserSpec.serialize(obj.created_by) - if obj.archived_by: - mapping["archived_by"] = UserSpec.serialize(obj.archived_by) + if obj.created_by_id: + mapping["uploaded_by"] = model_from_cache(UserSpec, id=obj.created_by_id) + if obj.archived_by_id: + mapping["archived_by"] = model_from_cache(UserSpec, id=obj.archived_by_id) class FileUploadRetrieveSpec(FileUploadListSpec): @@ -112,8 +112,8 @@ def perform_extra_serialization(cls, mapping, obj): else: mapping["read_signed_url"] = obj.files_manager.read_signed_url(obj) - if obj.updated_by: - mapping["updated_by"] = UserSpec.serialize(obj.updated_by) + if obj.updated_by_id: + mapping["updated_by"] = model_from_cache(UserSpec, id=obj.updated_by_id) class ConsentFileUploadCreateSpec(FileUploadBaseSpec): diff --git a/care/emr/resources/location/spec.py b/care/emr/resources/location/spec.py index 8b93f525ad..5abe6606de 100644 --- a/care/emr/resources/location/spec.py +++ b/care/emr/resources/location/spec.py @@ -7,7 +7,6 @@ from care.emr.models.location import FacilityLocation from care.emr.resources.base import EMRResource from care.emr.resources.common import Coding -from care.emr.resources.user.spec import UserSpec class LocationEncounterAvailabilityStatusChoices(str, Enum): @@ -156,10 +155,7 @@ class FacilityLocationRetrieveSpec(FacilityLocationListSpec): @classmethod def perform_extra_serialization(cls, mapping, obj): super().perform_extra_serialization(mapping, obj) - if obj.created_by: - mapping["created_by"] = UserSpec.serialize(obj.created_by) - if obj.updated_by: - mapping["updated_by"] = UserSpec.serialize(obj.updated_by) + cls.serialize_audit_users(mapping, obj) class FacilityLocationEncounterBaseSpec(EMRResource): diff --git a/care/emr/resources/medication/administration/spec.py b/care/emr/resources/medication/administration/spec.py index 496e3c7847..d77b13414f 100644 --- a/care/emr/resources/medication/administration/spec.py +++ b/care/emr/resources/medication/administration/spec.py @@ -7,7 +7,7 @@ from care.emr.models.medication_administration import MedicationAdministration from care.emr.models.medication_request import MedicationRequest from care.emr.models.product_knowledge import ProductKnowledge -from care.emr.resources.base import EMRResource +from care.emr.resources.base import EMRResource, model_from_cache from care.emr.resources.common import Quantity from care.emr.resources.inventory.product_knowledge.spec import ProductKnowledgeReadSpec from care.emr.resources.medication.valueset.administration_method import ( @@ -191,5 +191,5 @@ def perform_extra_serialization(cls, mapping, obj): obj.administered_product ) - if obj.created_by: - mapping["created_by"] = UserSpec.serialize(obj.created_by) + if obj.created_by_id: + mapping["created_by"] = model_from_cache(UserSpec, id=obj.created_by_id) diff --git a/care/emr/resources/meta_artifact/spec.py b/care/emr/resources/meta_artifact/spec.py index cbdfcea3ed..b81ed62dea 100644 --- a/care/emr/resources/meta_artifact/spec.py +++ b/care/emr/resources/meta_artifact/spec.py @@ -42,10 +42,7 @@ class MetaArtifactReadSpec(MetaArtifactBaseSpec): @classmethod def perform_extra_serialization(cls, mapping, obj): mapping["id"] = obj.external_id - if obj.created_by: - mapping["created_by"] = UserSpec.serialize(obj.created_by) - if obj.updated_by: - mapping["updated_by"] = UserSpec.serialize(obj.updated_by) + cls.serialize_audit_users(mapping, obj) class MetaArtifactCreateSpec(MetaArtifactBaseSpec): diff --git a/care/emr/resources/notes/notes_spec.py b/care/emr/resources/notes/notes_spec.py index 98dcc09ac6..29e0152fc2 100644 --- a/care/emr/resources/notes/notes_spec.py +++ b/care/emr/resources/notes/notes_spec.py @@ -5,7 +5,6 @@ from care.emr.models.notes import NoteMessage from care.emr.resources.base import EMRResource -from care.emr.resources.user.spec import UserSpec class NoteMessageSpec(EMRResource): @@ -40,8 +39,8 @@ def perform_extra_deserialization(self, is_update, obj): class NoteMessageReadSpec(NoteMessageSpec): message_history: dict - created_by: UserSpec = {} - updated_by: UserSpec = {} + created_by: dict = {} + updated_by: dict = {} created_date: datetime.datetime modified_date: datetime.datetime @@ -49,7 +48,4 @@ class NoteMessageReadSpec(NoteMessageSpec): def perform_extra_serialization(cls, mapping, obj): mapping["id"] = obj.external_id - if obj.created_by: - mapping["created_by"] = UserSpec.serialize(obj.created_by).to_json() - if obj.updated_by: - mapping["updated_by"] = UserSpec.serialize(obj.updated_by).to_json() + cls.serialize_audit_users(mapping, obj) diff --git a/care/emr/resources/notes/thread_spec.py b/care/emr/resources/notes/thread_spec.py index 904c00f8e7..1946316fdb 100644 --- a/care/emr/resources/notes/thread_spec.py +++ b/care/emr/resources/notes/thread_spec.py @@ -5,7 +5,6 @@ from care.emr.models import Encounter from care.emr.models.notes import NoteThread from care.emr.resources.base import EMRResource -from care.emr.resources.user.spec import UserSpec class NoteThreadSpec(EMRResource): @@ -36,8 +35,8 @@ class NoteThreadUpdateSpec(NoteThreadSpec): class NoteThreadReadSpec(NoteThreadSpec): - created_by: UserSpec = {} - updated_by: UserSpec = {} + created_by: dict = {} + updated_by: dict = {} created_date: datetime.datetime modified_date: datetime.datetime @@ -45,7 +44,4 @@ class NoteThreadReadSpec(NoteThreadSpec): def perform_extra_serialization(cls, mapping, obj): mapping["id"] = obj.external_id - if obj.created_by: - mapping["created_by"] = UserSpec.serialize(obj.created_by).to_json() - if obj.updated_by: - mapping["updated_by"] = UserSpec.serialize(obj.updated_by).to_json() + cls.serialize_audit_users(mapping, obj) diff --git a/care/emr/resources/observation/spec.py b/care/emr/resources/observation/spec.py index 4f025589d5..88940ffb92 100644 --- a/care/emr/resources/observation/spec.py +++ b/care/emr/resources/observation/spec.py @@ -130,12 +130,13 @@ def perform_extra_serialization(cls, mapping, obj): mapping["patient"] = None mapping["questionnaire_response"] = None - if obj.created_by: - mapping["created_by"] = UserSpec.serialize(obj.created_by) - if obj.updated_by: - mapping["updated_by"] = UserSpec.serialize(obj.updated_by) - if obj.data_entered_by: - mapping["data_entered_by"] = UserSpec.serialize(obj.data_entered_by) + cls.serialize_audit_users(mapping, obj) + if obj.data_entered_by_id: + from care.emr.resources.base import model_from_cache + + mapping["data_entered_by"] = model_from_cache( + UserSpec, id=obj.data_entered_by_id + ) class ObservationRetrieveSpec(ObservationReadSpec): diff --git a/care/emr/resources/observation_definition/spec.py b/care/emr/resources/observation_definition/spec.py index 7e9f2cd56a..59d453bb04 100644 --- a/care/emr/resources/observation_definition/spec.py +++ b/care/emr/resources/observation_definition/spec.py @@ -4,7 +4,7 @@ from pydantic import UUID4, BaseModel, Field, field_validator, model_validator from care.emr.models.observation_definition import ObservationDefinition -from care.emr.resources.base import EMRResource +from care.emr.resources.base import EMRResource, model_from_cache from care.emr.resources.common.condition_evaluator import EvaluatorConditionSpec from care.emr.resources.facility.spec import FacilityBareMinimumSpec from care.emr.resources.observation.valueset import ( @@ -224,8 +224,8 @@ class ObservationDefinitionReadSpec(BaseObservationDefinitionSpec): @classmethod def perform_extra_serialization(cls, mapping, obj): mapping["id"] = obj.external_id - if obj.facility: - mapping["facility"] = FacilityBareMinimumSpec.serialize( - obj.facility - ).to_json() + if obj.facility_id: + mapping["facility"] = model_from_cache( + FacilityBareMinimumSpec, id=obj.facility_id + ) mapping["slug_config"] = obj.parse_slug(obj.slug) diff --git a/care/emr/resources/patient/spec.py b/care/emr/resources/patient/spec.py index 955b639530..aa07ddedec 100644 --- a/care/emr/resources/patient/spec.py +++ b/care/emr/resources/patient/spec.py @@ -261,17 +261,13 @@ class PatientRetrieveSpec(PatientListSpec, PatientPermissionsMixin): @classmethod def perform_extra_serialization(cls, mapping, obj, *args, **kwargs): from care.emr.resources.organization.spec import OrganizationReadSpec - from care.emr.resources.user.spec import UserSpec super().perform_extra_serialization(mapping, obj, *args, **kwargs) if obj.geo_organization: mapping["geo_organization"] = OrganizationReadSpec.serialize( obj.geo_organization ).to_json() - if obj.created_by: - mapping["created_by"] = UserSpec.serialize(obj.created_by).to_json() - if obj.updated_by: - mapping["updated_by"] = UserSpec.serialize(obj.updated_by).to_json() + cls.serialize_audit_users(mapping, obj) if obj.instance_identifiers: mapping["instance_identifiers"] = [ { diff --git a/care/emr/resources/questionnaire/spec.py b/care/emr/resources/questionnaire/spec.py index 7acd55fa75..5b1c050020 100644 --- a/care/emr/resources/questionnaire/spec.py +++ b/care/emr/resources/questionnaire/spec.py @@ -290,10 +290,7 @@ def perform_extra_serialization(cls, mapping, obj): for tag in obj.tags: tags.append(QuestionnaireTag.get_tag(tag)) mapping["tags"] = tags - if obj.created_by: - mapping["created_by"] = UserSpec.serialize(obj.created_by) - if obj.updated_by: - mapping["updated_by"] = UserSpec.serialize(obj.updated_by) + cls.serialize_audit_users(mapping, obj) # Add this to handle recursive Question type diff --git a/care/emr/resources/questionnaire_response/spec.py b/care/emr/resources/questionnaire_response/spec.py index dbb29fd63d..4a4d669c31 100644 --- a/care/emr/resources/questionnaire_response/spec.py +++ b/care/emr/resources/questionnaire_response/spec.py @@ -73,7 +73,4 @@ def perform_extra_serialization(cls, mapping, obj): mapping["encounter"] = obj.encounter.external_id else: mapping["encounter"] = None - if obj.created_by: - mapping["created_by"] = UserSpec.serialize(obj.created_by) - if obj.updated_by: - mapping["updated_by"] = UserSpec.serialize(obj.updated_by) + cls.serialize_audit_users(mapping, obj) diff --git a/care/emr/resources/report/template/spec.py b/care/emr/resources/report/template/spec.py index be9155e8df..40d224f429 100644 --- a/care/emr/resources/report/template/spec.py +++ b/care/emr/resources/report/template/spec.py @@ -6,7 +6,7 @@ from care.emr.reports.context_builder.data_point_registry import DataPointRegistry from care.emr.reports.renderer.generators import GeneratorRegistry from care.emr.reports.report_type_registry import ReportTypeRegistry -from care.emr.resources.base import EMRResource +from care.emr.resources.base import EMRResource, model_from_cache from care.emr.resources.facility.spec import FacilityBareMinimumSpec from care.emr.utils.slug_type import SlugType from care.facility.models.facility import Facility @@ -113,7 +113,7 @@ class TemplateRetrieveSpec(TemplateReadSpec): @classmethod def perform_extra_serialization(cls, mapping, obj): super().perform_extra_serialization(mapping, obj) - if obj.facility: - mapping["facility"] = FacilityBareMinimumSpec.serialize( - obj.facility - ).to_json() + if obj.facility_id: + mapping["facility"] = model_from_cache( + FacilityBareMinimumSpec, id=obj.facility_id + ) diff --git a/care/emr/resources/resource_request/spec.py b/care/emr/resources/resource_request/spec.py index f92798c867..c3859c148c 100644 --- a/care/emr/resources/resource_request/spec.py +++ b/care/emr/resources/resource_request/spec.py @@ -6,7 +6,7 @@ from care.emr.models import Patient from care.emr.models.organization import FacilityOrganizationUser from care.emr.models.resource_request import ResourceRequest, ResourceRequestComment -from care.emr.resources.base import EMRResource +from care.emr.resources.base import EMRResource, model_from_cache from care.emr.resources.facility.spec import FacilityReadSpec from care.emr.resources.patient.spec import PatientListSpec from care.emr.resources.user.spec import UserSpec @@ -147,13 +147,9 @@ def perform_extra_serialization(cls, mapping, obj): mapping["related_patient"] = PatientListSpec.serialize( obj.related_patient ).to_json() - if obj.assigned_to: - mapping["assigned_to"] = UserSpec.serialize(obj.assigned_to).to_json() - - if obj.created_by: - mapping["created_by"] = UserSpec.serialize(obj.created_by) - if obj.updated_by: - mapping["updated_by"] = UserSpec.serialize(obj.updated_by) + if obj.assigned_to_id: + mapping["assigned_to"] = model_from_cache(UserSpec, id=obj.assigned_to_id) + cls.serialize_audit_users(mapping, obj) class ResourceRequestCommentBaseSpec(EMRResource): @@ -173,8 +169,8 @@ class ResourceRequestCommentListSpec(ResourceRequestCommentBaseSpec): @classmethod def perform_extra_serialization(cls, mapping, obj): - if obj.created_by: - mapping["created_by"] = UserSpec.serialize(obj.created_by) + if obj.created_by_id: + mapping["created_by"] = model_from_cache(UserSpec, id=obj.created_by_id) class ResourceRequestCommentRetrieveSpec(ResourceRequestCommentListSpec): diff --git a/care/emr/resources/tag/config_spec.py b/care/emr/resources/tag/config_spec.py index 47f6f5129f..a3fedc937d 100644 --- a/care/emr/resources/tag/config_spec.py +++ b/care/emr/resources/tag/config_spec.py @@ -11,7 +11,12 @@ from care.emr.models.organization import FacilityOrganization, Organization from care.emr.models.tag_config import TagConfig -from care.emr.resources.base import EMRResource, cacheable, model_string +from care.emr.resources.base import ( + EMRResource, + cacheable, + model_from_cache, + model_string, +) from care.emr.resources.facility.spec import FacilityBareMinimumSpec from care.emr.resources.tag.cache_invalidation import invalidate_tag_config_cache from care.facility.models.facility import Facility @@ -162,10 +167,10 @@ def perform_extra_serialization(cls, mapping, obj): parent = obj.get_parent_json() if parent: mapping["parent"] = parent - if obj.facility: - mapping["facility"] = FacilityBareMinimumSpec.serialize( - obj.facility - ).to_json() + if obj.facility_id: + mapping["facility"] = model_from_cache( + FacilityBareMinimumSpec, id=obj.facility_id + ) class TagConfigRetrieveSpec(TagConfigReadSpec): diff --git a/care/emr/resources/user/spec.py b/care/emr/resources/user/spec.py index 0e84295d9a..75a0977df1 100644 --- a/care/emr/resources/user/spec.py +++ b/care/emr/resources/user/spec.py @@ -201,7 +201,8 @@ def perform_extra_serialization(cls, mapping, obj: User) -> None: ).values_list("organization__facility_id", flat=True) ) mapping["facilities"] = [ - FacilityBareMinimumSpec.serialize(obj).to_json() for obj in user_facilities + model_from_cache(FacilityBareMinimumSpec, id=facility.id) + for facility in user_facilities ] mapping["permissions"] = list( diff --git a/care/emr/resources/valueset/spec.py b/care/emr/resources/valueset/spec.py index 95137615f5..680af8d051 100644 --- a/care/emr/resources/valueset/spec.py +++ b/care/emr/resources/valueset/spec.py @@ -66,10 +66,7 @@ class ValueSetReadSpec(ValueSetBaseSpec): @classmethod def perform_extra_serialization(cls, mapping, obj): mapping["id"] = obj.external_id - if obj.created_by: - mapping["created_by"] = UserSpec.serialize(obj.created_by) - if obj.updated_by: - mapping["updated_by"] = UserSpec.serialize(obj.updated_by) + cls.serialize_audit_users(mapping, obj) ValueSetSpec.model_rebuild() From 194b5d287f53ea1971cfd7351367e940357f99cc Mon Sep 17 00:00:00 2001 From: Prafful Sharma Date: Wed, 28 Jan 2026 11:59:56 +0530 Subject: [PATCH 2/4] N+1 issues --- care/emr/api/viewsets/facility.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/care/emr/api/viewsets/facility.py b/care/emr/api/viewsets/facility.py index c4d53aff5c..71fbbb5b31 100644 --- a/care/emr/api/viewsets/facility.py +++ b/care/emr/api/viewsets/facility.py @@ -84,7 +84,7 @@ class FacilityViewSet(EMRModelViewSet): filter_backends = [DjangoFilterBackend] def get_queryset(self): - qs = super().get_queryset() + qs = super().get_queryset().select_related("geo_organization", "created_by") if self.request.user.is_superuser: return qs organization_ids = list( @@ -217,4 +217,6 @@ class AllFacilityViewSet(EMRModelReadOnlyViewSet): search_fields = ["name"] def get_queryset(self): - return Facility.objects.filter(is_public=True).select_related() + return Facility.objects.filter(is_public=True).select_related( + "geo_organization" + ) From 49e7e47c2569f813d71cb4c50c9d2f668d99edca Mon Sep 17 00:00:00 2001 From: Prafful Sharma Date: Wed, 28 Jan 2026 12:04:15 +0530 Subject: [PATCH 3/4] N+1 issues --- care/emr/api/viewsets/facility.py | 2 +- care/emr/resources/facility/spec.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/care/emr/api/viewsets/facility.py b/care/emr/api/viewsets/facility.py index 71fbbb5b31..3bacdd0975 100644 --- a/care/emr/api/viewsets/facility.py +++ b/care/emr/api/viewsets/facility.py @@ -84,7 +84,7 @@ class FacilityViewSet(EMRModelViewSet): filter_backends = [DjangoFilterBackend] def get_queryset(self): - qs = super().get_queryset().select_related("geo_organization", "created_by") + qs = super().get_queryset().select_related("geo_organization") if self.request.user.is_superuser: return qs organization_ids = list( diff --git a/care/emr/resources/facility/spec.py b/care/emr/resources/facility/spec.py index 5cb0db567c..a0be8e3576 100644 --- a/care/emr/resources/facility/spec.py +++ b/care/emr/resources/facility/spec.py @@ -109,7 +109,7 @@ def perform_extra_serialization(cls, mapping, obj): mapping["id"] = obj.external_id mapping["read_cover_image_url"] = obj.read_cover_image_url() - if obj.created_by: + if obj.created_by_id: mapping["created_by"] = model_from_cache(UserSpec, id=obj.created_by_id) mapping["facility_type"] = REVERSE_FACILITY_TYPES[obj.facility_type] if obj.geo_organization: From 0e3dc546f828c7f316eea9aca8d72aadacdce7c6 Mon Sep 17 00:00:00 2001 From: Prafful Sharma Date: Wed, 28 Jan 2026 12:44:26 +0530 Subject: [PATCH 4/4] code rabbit review --- care/emr/models/patient.py | 2 +- care/emr/resources/resource_request/spec.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/care/emr/models/patient.py b/care/emr/models/patient.py index 0e3549bd97..ae5da1ea6c 100644 --- a/care/emr/models/patient.py +++ b/care/emr/models/patient.py @@ -195,7 +195,7 @@ def get_config(cls, config_id) -> PatientIdentifierConfig: ) cls.configs[config_id] = model_from_cache( PatientIdentifierListSpec, id=config.id - ).to_json() + ) return cls.configs[config_id] @classmethod diff --git a/care/emr/resources/resource_request/spec.py b/care/emr/resources/resource_request/spec.py index c3859c148c..07d2d59d2c 100644 --- a/care/emr/resources/resource_request/spec.py +++ b/care/emr/resources/resource_request/spec.py @@ -169,6 +169,7 @@ class ResourceRequestCommentListSpec(ResourceRequestCommentBaseSpec): @classmethod def perform_extra_serialization(cls, mapping, obj): + mapping["id"] = str(obj.external_id) if obj.created_by_id: mapping["created_by"] = model_from_cache(UserSpec, id=obj.created_by_id)