From 627075735c5056a8c7bdc43291c9a1d1d9697b47 Mon Sep 17 00:00:00 2001 From: Mojtaba-z Date: Sun, 4 Jan 2026 10:39:02 +0330 Subject: [PATCH] fix - improve response time of org linked ranchers --- .env.local | 2 +- apps/herd/models.py | 3 + .../services/rancher_org_link_services.py | 85 ++++++++++++------- apps/livestock/models.py | 8 +- 4 files changed, 62 insertions(+), 36 deletions(-) diff --git a/.env.local b/.env.local index 13815d0..3402c15 100644 --- a/.env.local +++ b/.env.local @@ -7,7 +7,7 @@ ENV_NAME=DEV # Database secrets DB_HOST=31.7.78.133 DB_PORT=14352 -DB_NAME=Development +DB_NAME=Production DB_USERNAME=postgres DB_PASSWORD=pfLIVXupbDetvFMt2gUvxLXUL9b4HIOHaPcKXsBEZ1i8zl0iLUjmhUfXlGfJKcTV diff --git a/apps/herd/models.py b/apps/herd/models.py index 7fda366..5671993 100644 --- a/apps/herd/models.py +++ b/apps/herd/models.py @@ -16,6 +16,7 @@ class Herd(BaseModel): 'Rancher', on_delete=models.CASCADE, related_name='herd', + db_index=True, null=True ) cooperative = models.ForeignKey( @@ -153,12 +154,14 @@ class RancherOrganizationLink(BaseModel): Organization, on_delete=models.CASCADE, related_name='rancher_links', + db_index=True, null=True ) rancher = models.ForeignKey( Rancher, on_delete=models.CASCADE, related_name='organization_links', + db_index=True, null=True ) diff --git a/apps/herd/services/rancher_org_link_services.py b/apps/herd/services/rancher_org_link_services.py index a354158..e6d5fff 100644 --- a/apps/herd/services/rancher_org_link_services.py +++ b/apps/herd/services/rancher_org_link_services.py @@ -1,8 +1,11 @@ +from collections import defaultdict + from django.db.models import Count from apps.authentication.models import Organization from apps.authentication.services.service import get_all_org_child -from apps.herd.models import RancherOrganizationLink +from apps.herd.models import RancherOrganizationLink, Herd +from apps.livestock.models import LiveStock # class RancherOrganizationService: @@ -63,15 +66,18 @@ class RancherOrganizationService: def orgs_linked_rancher(self, org: Organization, org_type_key: str): # -------------------------------------------------- - # 1. Base organizations queryset + # 1. Resolve organization ids # -------------------------------------------------- if org.type.key != 'ADM': - child_orgs = get_all_org_child(org) - org_ids = [o.id for o in child_orgs] + org_ids = list( + o.id for o in get_all_org_child(org) + ) else: - org_ids = Organization.objects.filter( - type__key=org_type_key - ).values_list('id', flat=True) + org_ids = list( + Organization.objects.filter( + type__key=org_type_key + ).values_list('id', flat=True) + ) organizations = ( Organization.objects @@ -84,12 +90,12 @@ class RancherOrganizationService: # 2. Rancher count per organization # -------------------------------------------------- rancher_counts = { - row['organization_id']: row['cnt'] - for row in ( + r['organization_id']: r['cnt'] + for r in ( RancherOrganizationLink.objects .filter(organization_id__in=org_ids) .values('organization_id') - .annotate(cnt=Count('rancher_id', distinct=True)) + .annotate(cnt=Count('rancher_id')) ) } @@ -97,39 +103,54 @@ class RancherOrganizationService: # 3. Herd count per organization # -------------------------------------------------- herd_counts = { - row['organization_id']: row['cnt'] - for row in ( + r['organization_id']: r['cnt'] + for r in ( RancherOrganizationLink.objects .filter(organization_id__in=org_ids) .values('organization_id') - .annotate(cnt=Count('rancher__herd', distinct=True)) + .annotate(cnt=Count('rancher__herd')) ) } # -------------------------------------------------- - # 4. Livestock count per organization + # 4. Livestock count (optimized path) + # LiveStockHerd -> Herd -> Org # -------------------------------------------------- - livestock_counts = { - row['organization_id']: row['cnt'] + + # 4-1 livestock count per herd (NO JOIN, NO DISTINCT) + livestock_per_herd = { + row['herd_id']: row['cnt'] for row in ( - RancherOrganizationLink.objects - .filter(organization_id__in=org_ids) - .values('organization_id') - .annotate( - cnt=Count( - 'rancher__herd__live_stock_herd', - distinct=True - ) - ) + LiveStock.objects + .values('herd_id') + .annotate(cnt=Count('id')) ) } + # 4-2 sum livestock per organization + livestock_counts = defaultdict(int) + + herd_org_map = ( + Herd.objects + .filter( + rancher__organization_links__organization_id__in=org_ids + ) + .values( + 'id', + 'rancher__organization_links__organization_id' + ) + ) + + for row in herd_org_map: + livestock_counts[ + row['rancher__organization_links__organization_id'] + ] += livestock_per_herd.get(row['id'], 0) + # -------------------------------------------------- - # 5. Final response (merge in memory) + # 5. Final response # -------------------------------------------------- - response = [] - for org in organizations: - response.append({ + return [ + { "id": org.id, "name": org.name, "org_service_area": [ @@ -145,6 +166,6 @@ class RancherOrganizationService: "rancher_count": rancher_counts.get(org.id, 0), "herd_count": herd_counts.get(org.id, 0), "livestock_count": livestock_counts.get(org.id, 0), - }) - - return response + } + for org in organizations + ] diff --git a/apps/livestock/models.py b/apps/livestock/models.py index c7ec812..ecb71d7 100644 --- a/apps/livestock/models.py +++ b/apps/livestock/models.py @@ -1,7 +1,8 @@ +from django.db import models + from apps.core.models import BaseModel from apps.herd import models as herd_models from apps.tag import models as tag_models -from django.db import models class LiveStockSpecies(BaseModel): # noqa @@ -53,6 +54,7 @@ class LiveStock(BaseModel): herd_models.Herd, on_delete=models.CASCADE, related_name="live_stock_herd", + db_index=True, null=True ) tag = models.ForeignKey( @@ -113,9 +115,9 @@ class TemporaryLiveStock(BaseModel): null=True ) count = models.PositiveBigIntegerField(default=0) - + def __str__(self): return f'temporary: {self.id} - rancher: {self.rancher.national_code}' - + def save(self, *args, **kwargs): return super(TemporaryLiveStock, self).save(*args, **kwargs)