Merge branch 'distance' into 'dev'

add_distances_to_point_qs

See merge request spatial/postamates!70
dev
Timofey Malinin 3 years ago
commit 145fe263f4

@ -1,6 +1,7 @@
from rest_framework import serializers
from service import models
from service.service import PointService
class PlacementPointSerializer(serializers.ModelSerializer):
@ -8,6 +9,12 @@ class PlacementPointSerializer(serializers.ModelSerializer):
model = models.PlacementPoint
fields = '__all__'
def to_representation(self, instance):
representation = super().to_representation(instance)
min_distances = PointService.get_min_distances_to_group(instance.id)
representation['min_distance_to_group'] = min_distances
return representation
class PostAndPVZGroupSerializer(serializers.ModelSerializer):
class Meta:

@ -9,6 +9,7 @@ from postamates.settings import DEFAULT_PLACEMENT_POINT_UPDATE_RADIUS
from service import models
from service.enums import PointStatus
from service.tasks import raschet
from service.utils import create_columns_dist
class LayerService:
@ -18,6 +19,7 @@ class LayerService:
class PointService:
def update_fact(self, postamat_id: str, fact: int):
qs = self.get_point_by_postamat_id(postamat_id)
qs.update(**{'fact': fact})
@ -26,6 +28,12 @@ class PointService:
qs = self.get_point_by_id(point_id)
qs.update(**{'postamat_id': postamat_id})
@staticmethod
def get_min_distances_to_group(postamat_id: str):
return {d['pvz_postamates_group']: d['dist'] for d in list(
models.PlacementPointPVZDistance.objects.filter(placement_point=postamat_id).values(
'pvz_postamates_group', 'dist'))}
@staticmethod
def update_points_in_radius(qs: models.PlacementPoint, new_status: str):
triggers = False
@ -66,13 +74,25 @@ class PointService:
return models.PlacementPoint.objects.filter(postamat_id=postamat_id)
@staticmethod
def to_excel(qs: models.PlacementPoint):
data = pd.DataFrame(list(qs.values()))
def to_excel(serializer):
data = pd.DataFrame(serializer.data)
if not data.empty:
if data['start_date'].any():
data['start_date'] = data.get('start_date').dt.tz_localize(None)
data['sample_trn'] = data['sample_trn'].astype(int)
data.rename(columns={'district_id': 'district', 'area_id': 'area'}, inplace=True)
data['min_distance_to_group'] = data['min_distance_to_group'].apply(lambda x: list(x.items()))
new_columns = data.apply(create_columns_dist, axis=1)
for ind in new_columns.columns:
expanded = new_columns[ind].apply(pd.Series)
group = models.Post_and_pvzGroup.objects.get(id=int(expanded.loc[0, 0]))
expanded[[f"group_{ind + 1}_name", f"group_{ind + 1}_category"]] = group.name, group.category.name
expanded = expanded.rename(columns={1: f"dist_to_group_{ind + 1}"})
expanded = expanded.drop(0, axis=1)
new_columns = pd.concat([new_columns, expanded], axis=1)
new_columns = new_columns.drop(ind, axis=1)
data.drop('min_distance_to_group', axis=1, inplace=True)
data = pd.concat([data, new_columns], axis=1)
with BytesIO() as b:
with pd.ExcelWriter(b) as writer:
data.to_excel(
@ -82,13 +102,25 @@ class PointService:
return b.getvalue()
@staticmethod
def to_json(qs: models.PlacementPoint):
data = pd.DataFrame(list(qs.values()))
def to_json(serializer):
data = pd.DataFrame(serializer.data)
data['start_date'] = pd.to_datetime(data['start_date'], errors='coerce')
data['start_date'] = data['start_date'].dt.tz_localize(None)
data['sample_trn'] = data['sample_trn'].astype(int)
data['geometry'] = data['geometry'].apply(lambda x: {'latitude': x[1], 'longtitude': x[0]})
data.rename(columns={'district_id': 'district', 'area_id': 'area'}, inplace=True)
data['min_distance_to_group'] = data['min_distance_to_group'].apply(lambda x: list(x.items()))
new_columns = data.apply(create_columns_dist, axis=1)
for ind in new_columns.columns:
expanded = new_columns[ind].apply(pd.Series)
group = models.Post_and_pvzGroup.objects.get(id=int(expanded.loc[0, 0]))
expanded[[f"group_{ind + 1}_name", f"group_{ind + 1}_category"]] = group.name, group.category.name
expanded = expanded.rename(columns={1: f"dist_to_group_{ind + 1}"})
expanded = expanded.drop(0, axis=1)
new_columns = pd.concat([new_columns, expanded], axis=1)
new_columns = new_columns.drop(ind, axis=1)
data.drop('min_distance_to_group', axis=1, inplace=True)
data = pd.concat([data, new_columns], axis=1)
return data.to_json(orient='records')
@staticmethod

@ -56,10 +56,15 @@ def cached_func(key, func, timeout=settings.CACHE_TIMEOUT, *args, **kwargs):
cache.set(key, d, timeout)
return d
class CustomReadOnlyModelViewSet(ReadOnlyModelViewSet):
def list(self, request, *args, **kwargs):
def f():
return ReadOnlyModelViewSet.list(self, request, *args, **kwargs).data
d = cached_func(self.__class__.__name__, f)
return Response(d)
def create_columns_dist(row):
return pd.Series(row['min_distance_to_group'])

@ -29,6 +29,7 @@ from django.contrib import messages
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import filters
from service.utils import CustomReadOnlyModelViewSet
from django.db.models import Min, Max
import os
@ -218,7 +219,13 @@ class PlacementPointViewSet(ReadOnlyModelViewSet):
min(temp_data[key]), max(temp_data[key]),
] if temp_data[key] else [0, 100] for key in keys
}
data['dist_to_groups'] = [{'group_id': d['pvz_postamates_group'], 'dist': [d['min_dist'], d['max_dist']]}
for d in list(
models.PlacementPointPVZDistance.objects.values('pvz_postamates_group').annotate(
min_dist=Min('dist'), max_dist=Max('dist')))]
return data
data = utils.cached_func('get_filter_data', get_filter_data, 120)
return Response(data, status=HTTPStatus.OK)
@ -284,9 +291,10 @@ class PlacementPointViewSet(ReadOnlyModelViewSet):
@action(detail=False, methods=['get'])
def to_excel(self, request):
qs = self.get_queryset()
serializer = serializers.PlacementPointSerializer(qs, many=True)
filename = EXCEL_EXPORT_FILENAME
res = HttpResponse(
PointService.to_excel(qs),
PointService.to_excel(serializer),
content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
)
res['Content-Disposition'] = f'attachment; filename={filename}'
@ -295,8 +303,9 @@ class PlacementPointViewSet(ReadOnlyModelViewSet):
@action(detail=False, methods=['get'])
def to_json(self, request):
qs = self.get_queryset()
serializer = serializers.PlacementPointSerializer(qs, many=True)
filename = JSON_EXPORT_FILENAME
response = HttpResponse(PointService.to_json(qs), content_type='application/json')
response = HttpResponse(PointService.to_json(serializer), content_type='application/json')
response['Content-Disposition'] = f'attachment; filename={filename}'
return response

Loading…
Cancel
Save