This commit is contained in:
2026-02-01 08:26:08 +03:30
parent 6c74e43629
commit 521dd9da5c
81 changed files with 103 additions and 53 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -21,7 +21,8 @@ from app.serializers import TransportingDetailSerializer, HatchingDetailSerializ
StewardForTransportCarcassSerializer, KillHouseForTransportCarcassSerializer, TransportCarcassDetailSerializer, \
GuildsForTransportCarcassSerializer, AllProductsTransportSerializer, AllProductsTransportCustomSerializer
from helpers import build_query
from app.helper import get_hatching_permit_code
from app.helper import get_hatching_permit_code, normalize_persian_arabic_text
def transporting_detail_excel(request):
filterset_class = TransportingDetailFilterSet
@@ -2589,10 +2590,7 @@ def all_products_transport_excel(request):
filters['product'] = product_type
if destination_province and destination_province != 'undefined':
if destination_province == 'مرکزی':
filters['destination_province'] = 'مركزي'
else:
filters['destination_province'] = destination_province
filters['destination_province'] = normalize_persian_arabic_text(destination_province)
if date1 and date2 and date1 != 'undefined' and date2 != 'undefined':
try:

View File

@@ -146,6 +146,26 @@ def api_get_hatching_permit_code(request):
return Response({'detail': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
def normalize_persian_arabic_text(text):
"""
نرمال‌سازی متن فارسی/عربی برای یکسان‌سازی کاراکترهای مشابه
تبدیل کاراکترهای فارسی به عربی برای سازگاری با دیتابیس
این تابع کاراکترهای 'ک' و 'ی' فارسی را به 'ك' و 'ي' عربی تبدیل می‌کند
تا با فرم استاندارد ذخیره شده در دیتابیس مطابقت داشته باشد
"""
if not text:
return text
# تبدیل کاراکترهای فارسی به عربی
# 'ک' (U+06A9 - Persian Kaf) -> 'ك' (U+0643 - Arabic Kaf)
# 'ی' (U+06CC - Persian Yeh) -> 'ي' (U+064A - Arabic Yeh)
text = str(text)
text = text.replace('ک', 'ك') # Persian Kaf to Arabic Kaf
text = text.replace('ی', 'ي') # Persian Yeh to Arabic Yeh
return text
def create_guild(**info):
Guilds(

View File

@@ -622,32 +622,66 @@ class AllProductsTransportCustomSerializer(serializers.ModelSerializer):
def get_location_origin(self, obj):
resul = {}
province_origin = Province.objects.filter(name=obj.origin_province).first()
city_origin = City.objects.filter(name=obj.origin_city).first()
if province_origin:
resul.update({
"provinceLat": province_origin.Lat,
"provinceLng": province_origin.Lng
})
if city_origin:
resul.update({
"cityLat": city_origin.Lat,
"cityLng": city_origin.Lng
})
# بهینه‌سازی: استفاده از context cache برای جلوگیری از N+1 queries
location_cache = self.context.get('location_cache', {})
if obj.origin_province:
cache_key = f"province_{obj.origin_province}"
if cache_key not in location_cache:
province_origin = Province.objects.filter(name=obj.origin_province).only('Lat', 'Lng').first()
if province_origin:
location_cache[cache_key] = {
"provinceLat": province_origin.Lat,
"provinceLng": province_origin.Lng
}
else:
location_cache[cache_key] = {}
resul.update(location_cache.get(cache_key, {}))
if obj.origin_city:
cache_key = f"city_{obj.origin_city}"
if cache_key not in location_cache:
city_origin = City.objects.filter(name=obj.origin_city).only('Lat', 'Lng').first()
if city_origin:
location_cache[cache_key] = {
"cityLat": city_origin.Lat,
"cityLng": city_origin.Lng
}
else:
location_cache[cache_key] = {}
resul.update(location_cache.get(cache_key, {}))
return resul
def get_location_destination(self, obj):
resul = {}
province_destination = Province.objects.filter(name=obj.destination_province).first()
city_destination = City.objects.filter(name=obj.destination_city).first()
if province_destination:
resul.update({
"provinceLat": province_destination.Lat,
"provinceLng": province_destination.Lng
})
if city_destination:
resul.update({
"cityLat": city_destination.Lat,
"cityLng": city_destination.Lng
})
# بهینه‌سازی: استفاده از context cache برای جلوگیری از N+1 queries
location_cache = self.context.get('location_cache', {})
if obj.destination_province:
cache_key = f"province_{obj.destination_province}"
if cache_key not in location_cache:
province_destination = Province.objects.filter(name=obj.destination_province).only('Lat', 'Lng').first()
if province_destination:
location_cache[cache_key] = {
"provinceLat": province_destination.Lat,
"provinceLng": province_destination.Lng
}
else:
location_cache[cache_key] = {}
resul.update(location_cache.get(cache_key, {}))
if obj.destination_city:
cache_key = f"city_{obj.destination_city}"
if cache_key not in location_cache:
city_destination = City.objects.filter(name=obj.destination_city).only('Lat', 'Lng').first()
if city_destination:
location_cache[cache_key] = {
"cityLat": city_destination.Lat,
"cityLng": city_destination.Lng
}
else:
location_cache[cache_key] = {}
resul.update(location_cache.get(cache_key, {}))
return resul

View File

@@ -26,7 +26,7 @@ from app.filtersets import PoultryFilterSet, PoultryHatchingFilterSet, Transport
PoultryInfoFilterSet, HatchingCalculationsFilterSet, HatchingsFilterSet, TransportingDetailFilterSet, \
KillHouseFilterSet, TransportingDetailCustomFilterSet, CustomHatchingsFilterSet, TransportCarcassDetailFilterSet, \
DriverFilterSet, GuildsFilterSet, AllProductsTransportFilterSet
from app.helper import SSLAdapter, get_hatching_permit_code
from app.helper import SSLAdapter, get_hatching_permit_code, normalize_persian_arabic_text
from app.models import Poultry, PoultryHatching, TransportingChickenDetail, Hatching, TransportingDetail, KillHouse, \
ApkInfo, TransportCarcassDetail, Guilds, Driver, InquiryCredentials, AllProductsTransport, EvacuationDetail, \
RasadyarAppInfo
@@ -4522,10 +4522,7 @@ class AllProductsTransportViewSet(viewsets.ModelViewSet):
filters['product'] = product_type
if destination_province and destination_province != 'undefined':
if destination_province == 'مرکزی':
filters['destination_province'] = 'مركزي'
else:
filters['destination_province'] = destination_province
filters['destination_province'] = normalize_persian_arabic_text(destination_province)
if date1 and date2 and date1 != 'undefined' and date2 != 'undefined':
try:
@@ -4536,23 +4533,33 @@ class AllProductsTransportViewSet(viewsets.ModelViewSet):
except ValueError:
pass
transports = AllProductsTransport.objects.filter(**filters).order_by('-date', '-create_date')
# بهینه‌سازی: استفاده از select_related برای جلوگیری از N+1 queries
# و اعمال order_by فقط یک بار
transports = AllProductsTransport.objects.select_related('hatching').filter(**filters)
if search and search != 'undefined' and search.strip():
transports = transports.filter(
build_query(self.filterset_class.Meta.fields, search)
)
transports = transports.filter(
build_query(self.filterset_class.Meta.fields, search)
)
# اعمال order_by فقط یک بار در آخر
transports = transports.order_by('-date', '-create_date')
page_size = request.query_params.get('page_size', None)
if page_size:
self.pagination_class.page_size = int(page_size)
page = self.paginate_queryset(transports.order_by('-date', '-create_date'))
page = self.paginate_queryset(transports)
# بهینه‌سازی: ایجاد cache برای Province و City در context برای جلوگیری از N+1 queries
location_cache = {}
context = self.get_serializer_context()
context['location_cache'] = location_cache
if page is not None:
serializer = self.get_serializer(page, many=True)
serializer = self.get_serializer(page, many=True, context=context)
return self.get_paginated_response(serializer.data)
serializer = self.serializer_class(transports.order_by('-date', '-create_date'), many=True)
serializer = self.serializer_class(transports, many=True, context=context)
return Response(serializer.data, status=status.HTTP_200_OK)
def create(self, request, *args, **kwargs):
@@ -4755,10 +4762,7 @@ class AllProductsTransportDashboardView(APIView):
destination_province = request.GET.get('destination_province')
kill_house_filterset_class = AllProductsTransportFilterSet
if destination_province and destination_province != 'undefined':
if destination_province == 'مرکزی':
filters['destination_province'] = 'مركزي'
else:
filters['destination_province'] = destination_province
filters['destination_province'] = normalize_persian_arabic_text(destination_province)
queryset = AllProductsTransport.objects.filter(**filters)
if search and search != 'undefined' and search.strip():
@@ -4785,10 +4789,7 @@ class AllProductsTransportDashboardView(APIView):
# bars = queryset.filter(jihadi_origin__in=kill_house_codes)
if destination_province and destination_province != 'undefined':
if destination_province == 'مرکزی':
filters_query['destination_province'] = 'مركزي'
else:
filters_query['destination_province'] = destination_province
filters_query['destination_province'] = normalize_persian_arabic_text(destination_province)
bars = queryset.filter(**filters_query)
aggregation = bars.aggregate(
total=Sum('quantity'),
@@ -4850,10 +4851,7 @@ class AllProductsTransportDashboardView(APIView):
).order_by('-modify_date')
if destination_province and destination_province != 'undefined':
if destination_province == 'مرکزی':
filters_query['destination_province'] = 'مركزي'
else:
filters_query['destination_province'] = destination_province
filters_query['destination_province'] = normalize_persian_arabic_text(destination_province)
bars = bars(**filters_query)
aggregation = bars.aggregate(
total=Sum('quantity'),