Aleksandr Popov 3 years ago committed by Timofey Malinin
parent 8de44f19f6
commit c1f498e3ec

@ -8,7 +8,9 @@ from service.models import AO
from service.models import PlacementPoint from service.models import PlacementPoint
from service.models import PointDist from service.models import PointDist
from service.models import Rayon from service.models import Rayon
from service.models import Rivals from service.models import Post_and_pvz, Post_and_pvzCategory, Post_and_pvzGroup, OtherObjects, OtherObjectsGroup, \
OtherObjectsCategory
from service.models import PlacementPointPVZDistance, TaskStatus
class MyAdminSite(AdminSite): class MyAdminSite(AdminSite):
@ -23,8 +25,20 @@ my_admin_site = MyAdminSite(name='myadmin')
my_admin_site.register(AO) my_admin_site.register(AO)
my_admin_site.register(Rayon) my_admin_site.register(Rayon)
my_admin_site.register(Rivals) my_admin_site.register(Post_and_pvz)
my_admin_site.register(PointDist) my_admin_site.register(Post_and_pvzCategory)
my_admin_site.register(Post_and_pvzGroup)
my_admin_site.register(OtherObjects)
my_admin_site.register(OtherObjectsGroup)
my_admin_site.register(OtherObjectsCategory)
my_admin_site.register(PlacementPointPVZDistance)
class TaskStatusAdmin(admin.ModelAdmin):
list_display = ('task_name', 'status')
my_admin_site.register(TaskStatus, TaskStatusAdmin)
class PlacementPointAdmin(admin.ModelAdmin): class PlacementPointAdmin(admin.ModelAdmin):

@ -0,0 +1,63 @@
# Generated by Django 3.2 on 2023-07-20 17:42
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('service', '0022_lastmlcall'),
]
operations = [
migrations.CreateModel(
name='RivalsCategory',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.TextField(verbose_name='Название слоя')),
('image', models.ImageField(blank=True, default=None, null=True, upload_to='rivals_category_images/', verbose_name='Картинка')),
('visible', models.BooleanField(default=True)),
],
options={
'verbose_name': 'Категории постаматов и ПВЗ',
},
),
migrations.RemoveField(
model_name='rivals',
name='info',
),
migrations.RemoveField(
model_name='rivals',
name='source',
),
migrations.RemoveField(
model_name='rivals',
name='type',
),
migrations.AddField(
model_name='rivals',
name='visible',
field=models.BooleanField(default=True),
),
migrations.CreateModel(
name='RivalsGroup',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.TextField(verbose_name='Название группы')),
('image', models.ImageField(blank=True, null=True, upload_to='rivals_group_images/', verbose_name='Картинка')),
('visible', models.BooleanField(default=True)),
('category', models.ForeignKey(default=None, on_delete=django.db.models.deletion.CASCADE, related_name='rivalsgroup', to='service.rivalscategory')),
],
),
migrations.AddField(
model_name='rivals',
name='category',
field=models.ForeignKey(default=None, on_delete=django.db.models.deletion.CASCADE, related_name='rivals', to='service.rivalscategory'),
),
migrations.AddField(
model_name='rivals',
name='group',
field=models.ForeignKey(default=None, on_delete=django.db.models.deletion.CASCADE, related_name='rivals', to='service.rivalsgroup'),
),
]

@ -0,0 +1,82 @@
# Generated by Django 3.2 on 2023-07-21 16:33
import django.contrib.gis.db.models.fields
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('service', '0023_auto_20230720_2042'),
]
operations = [
migrations.CreateModel(
name='OtherObjectsCategory',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.TextField(verbose_name='Название слоя')),
('image', models.ImageField(blank=True, default=None, null=True, upload_to='other_objects_category_images/', verbose_name='Картинка')),
('visible', models.BooleanField(default=True)),
],
options={
'verbose_name_plural': 'Категории прочих объектов',
},
),
migrations.AlterModelOptions(
name='ao',
options={'verbose_name_plural': 'АО'},
),
migrations.AlterModelOptions(
name='placementpoint',
options={'verbose_name_plural': 'Точки'},
),
migrations.AlterModelOptions(
name='pointdist',
options={'verbose_name_plural': 'Расстояния между точками'},
),
migrations.AlterModelOptions(
name='rayon',
options={'verbose_name_plural': 'Районы'},
),
migrations.AlterModelOptions(
name='rivals',
options={'verbose_name_plural': 'Постаматы и ПВЗ'},
),
migrations.AlterModelOptions(
name='rivalscategory',
options={'verbose_name_plural': 'Категории постаматов и ПВЗ'},
),
migrations.AlterModelOptions(
name='rivalsgroup',
options={'verbose_name_plural': 'Группы постаматов и ПВЗ'},
),
migrations.CreateModel(
name='OtherObjectsGroup',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.TextField(verbose_name='Название группы')),
('image', models.ImageField(blank=True, null=True, upload_to='other_objects_group_images/', verbose_name='Картинка')),
('visible', models.BooleanField(default=True)),
('category', models.ForeignKey(default=None, on_delete=django.db.models.deletion.CASCADE, related_name='otherobjectsgroup', to='service.otherobjectscategory')),
],
options={
'verbose_name_plural': 'Группы прочих объектов',
},
),
migrations.CreateModel(
name='OtherObjects',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('wkt', django.contrib.gis.db.models.fields.PointField(null=True, srid=4326)),
('param1', models.FloatField(blank=True, null=True)),
('visible', models.BooleanField(default=True)),
('category', models.ForeignKey(default=None, on_delete=django.db.models.deletion.CASCADE, related_name='other_objects', to='service.otherobjectscategory')),
('group', models.ForeignKey(default=None, on_delete=django.db.models.deletion.CASCADE, related_name='other_objects', to='service.otherobjectsgroup')),
],
options={
'verbose_name_plural': 'Прочие объекты',
},
),
]

@ -0,0 +1,18 @@
# Generated by Django 3.2 on 2023-07-21 17:01
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('service', '0024_auto_20230721_1933'),
]
operations = [
migrations.RenameField(
model_name='otherobjects',
old_name='param1',
new_name='param',
),
]

@ -0,0 +1,28 @@
# Generated by Django 3.2 on 2023-07-21 20:47
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('service', '0025_rename_param1_otherobjects_param'),
]
operations = [
migrations.AddField(
model_name='rivals',
name='inlude_in_ml',
field=models.BooleanField(default=True),
),
migrations.AddField(
model_name='rivalscategory',
name='inlude_in_ml',
field=models.BooleanField(default=True),
),
migrations.AddField(
model_name='rivalsgroup',
name='inlude_in_ml',
field=models.BooleanField(default=True),
),
]

@ -0,0 +1,87 @@
# Generated by Django 3.2 on 2023-07-22 20:10
import django.contrib.gis.db.models.fields
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('service', '0026_auto_20230721_2347'),
]
operations = [
migrations.CreateModel(
name='Post_and_pvz',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('wkt', django.contrib.gis.db.models.fields.PointField(null=True, srid=4326)),
('visible', models.BooleanField(default=True)),
('inlude_in_ml', models.BooleanField(default=True)),
],
options={
'verbose_name_plural': 'Постаматы и ПВЗ',
},
),
migrations.CreateModel(
name='Post_and_pvzCategory',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.TextField(verbose_name='Название слоя')),
('image', models.ImageField(blank=True, default=None, null=True, upload_to='post_and_pvz_category_images/', verbose_name='Картинка')),
('visible', models.BooleanField(default=True)),
('inlude_in_ml', models.BooleanField(default=True)),
],
options={
'verbose_name_plural': 'Категории постаматов и ПВЗ',
},
),
migrations.CreateModel(
name='Post_and_pvzGroup',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.TextField(verbose_name='Название группы')),
('image', models.ImageField(blank=True, null=True, upload_to='post_and_pvz_group_images/', verbose_name='Картинка')),
('visible', models.BooleanField(default=True)),
('inlude_in_ml', models.BooleanField(default=True)),
('category', models.ForeignKey(default=None, on_delete=django.db.models.deletion.CASCADE, related_name='post_and_pvz_group', to='service.post_and_pvzcategory')),
],
options={
'verbose_name_plural': 'Группы постаматов и ПВЗ',
},
),
migrations.RemoveField(
model_name='rivalsgroup',
name='category',
),
migrations.RenameField(
model_name='otherobjects',
old_name='param',
new_name='param1',
),
migrations.AddField(
model_name='otherobjects',
name='param2',
field=models.TextField(blank=True, null=True),
),
migrations.DeleteModel(
name='Rivals',
),
migrations.DeleteModel(
name='RivalsCategory',
),
migrations.DeleteModel(
name='RivalsGroup',
),
migrations.AddField(
model_name='post_and_pvz',
name='category',
field=models.ForeignKey(default=None, on_delete=django.db.models.deletion.CASCADE, related_name='post_and_pvz', to='service.post_and_pvzcategory'),
),
migrations.AddField(
model_name='post_and_pvz',
name='group',
field=models.ForeignKey(default=None, on_delete=django.db.models.deletion.CASCADE, related_name='post_and_pvz', to='service.post_and_pvzgroup'),
),
]

@ -0,0 +1,23 @@
# Generated by Django 3.2 on 2023-07-29 11:09
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('service', '0027_auto_20230722_2310'),
]
operations = [
migrations.CreateModel(
name='PlacementPointPVZDistance',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('dist', models.FloatField(blank=True, default=None, null=True)),
('placement_point', models.ForeignKey(default=None, on_delete=django.db.models.deletion.CASCADE, to='service.placementpoint')),
('pvz_postomates_group', models.ForeignKey(default=None, on_delete=django.db.models.deletion.CASCADE, to='service.post_and_pvzgroup')),
],
),
]

@ -0,0 +1,18 @@
# Generated by Django 3.2 on 2023-07-29 12:26
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('service', '0028_placementpointpvzdistance'),
]
operations = [
migrations.RenameField(
model_name='placementpointpvzdistance',
old_name='pvz_postomates_group',
new_name='pvz_postamates_group',
),
]

@ -0,0 +1,21 @@
# Generated by Django 3.2 on 2023-07-29 13:58
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('service', '0029_rename_pvz_postomates_group_placementpointpvzdistance_pvz_postamates_group'),
]
operations = [
migrations.CreateModel(
name='TaskStatus',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('task_name', models.TextField(unique=True)),
('status', models.IntegerField(blank=True, null=True)),
],
),
]

@ -0,0 +1,27 @@
# Generated by Django 3.2 on 2023-07-29 14:05
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('service', '0030_taskstatus'),
]
operations = [
migrations.AlterModelOptions(
name='taskstatus',
options={'verbose_name_plural': 'Статус фоновых задач'},
),
migrations.AlterField(
model_name='taskstatus',
name='status',
field=models.IntegerField(blank=True, null=True, verbose_name='Процент выполнения'),
),
migrations.AlterField(
model_name='taskstatus',
name='task_name',
field=models.TextField(unique=True, verbose_name='Название задачи'),
),
]

@ -0,0 +1,58 @@
# Generated by Django 3.2 on 2023-07-31 14:45
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('service', '0031_auto_20230729_1705'),
]
operations = [
migrations.AlterModelOptions(
name='ao',
options={'verbose_name': 'АО', 'verbose_name_plural': 'АО'},
),
migrations.AlterModelOptions(
name='otherobjects',
options={'verbose_name': 'Прочий объект', 'verbose_name_plural': 'Прочие объекты'},
),
migrations.AlterModelOptions(
name='otherobjectscategory',
options={'verbose_name': 'категория прочих объектов', 'verbose_name_plural': 'Категории прочих объектов'},
),
migrations.AlterModelOptions(
name='otherobjectsgroup',
options={'verbose_name': 'группа прочих объектов', 'verbose_name_plural': 'Группы прочих объектов'},
),
migrations.AlterModelOptions(
name='placementpoint',
options={'verbose_name': 'Точка', 'verbose_name_plural': 'Точки'},
),
migrations.AlterModelOptions(
name='post_and_pvz',
options={'verbose_name': 'Постамат или ПВЗ', 'verbose_name_plural': 'Постаматы и ПВЗ'},
),
migrations.AlterModelOptions(
name='post_and_pvzcategory',
options={'verbose_name': 'категория постаматов и ПВЗ', 'verbose_name_plural': 'Категории постаматов и ПВЗ'},
),
migrations.AlterModelOptions(
name='post_and_pvzgroup',
options={'verbose_name': 'группа постаматов и ПВЗ', 'verbose_name_plural': 'Группы постаматов и ПВЗ'},
),
migrations.AlterModelOptions(
name='rayon',
options={'verbose_name': 'Район', 'verbose_name_plural': 'Районы'},
),
migrations.AlterModelOptions(
name='taskstatus',
options={'verbose_name': 'Статус фоновых задач', 'verbose_name_plural': 'Статус фоновых задач'},
),
migrations.AlterField(
model_name='taskstatus',
name='status',
field=models.TextField(blank=True, null=True, verbose_name='Статус выполнения'),
),
]

@ -10,6 +10,10 @@ User._meta.get_field('email')._unique = True
class PlacementPoint(models.Model): class PlacementPoint(models.Model):
class Meta:
verbose_name = 'Точка'
verbose_name_plural = 'Точки'
STATUS_CHOICES = [(tag.name, tag.value) for tag in PointStatus] STATUS_CHOICES = [(tag.name, tag.value) for tag in PointStatus]
address = models.TextField(null=True, blank=True, verbose_name='Адрес') address = models.TextField(null=True, blank=True, verbose_name='Адрес')
name = models.TextField(null=True, blank=True, verbose_name='Название') name = models.TextField(null=True, blank=True, verbose_name='Название')
@ -83,28 +87,137 @@ class PlacementPoint(models.Model):
class AO(models.Model): class AO(models.Model):
class Meta:
verbose_name = 'АО'
verbose_name_plural = 'АО'
name = models.TextField(null=True, blank=True, verbose_name='Округ') name = models.TextField(null=True, blank=True, verbose_name='Округ')
polygon = gis_models.MultiPolygonField(null=True, srid=SRID) polygon = gis_models.MultiPolygonField(null=True, srid=SRID)
class Rayon(models.Model): class Rayon(models.Model):
class Meta:
verbose_name = 'Район'
verbose_name_plural = 'Районы'
name = models.TextField(null=True, blank=True, verbose_name='Район') name = models.TextField(null=True, blank=True, verbose_name='Район')
AO = models.ForeignKey('AO', related_name='rayons', on_delete=models.CASCADE) AO = models.ForeignKey('AO', related_name='rayons', on_delete=models.CASCADE)
polygon = gis_models.MultiPolygonField(null=True, srid=SRID) polygon = gis_models.MultiPolygonField(null=True, srid=SRID)
class Rivals(models.Model): class Post_and_pvz(models.Model):
class Meta:
verbose_name = 'Постамат или ПВЗ'
verbose_name_plural = 'Постаматы и ПВЗ'
wkt = gis_models.PointField(srid=SRID, null=True)
category = models.ForeignKey('Post_and_pvzCategory', default=None, related_name='post_and_pvz',
on_delete=models.CASCADE)
group = models.ForeignKey('Post_and_pvzGroup', default=None, related_name='post_and_pvz', on_delete=models.CASCADE)
visible = models.BooleanField(default=True)
inlude_in_ml = models.BooleanField(default=True)
class OtherObjects(models.Model):
class Meta:
verbose_name = 'Прочий объект'
verbose_name_plural = 'Прочие объекты'
wkt = gis_models.PointField(srid=SRID, null=True) wkt = gis_models.PointField(srid=SRID, null=True)
info = models.TextField(null=True, blank=True) category = models.ForeignKey('OtherObjectsCategory', default=None, related_name='other_objects',
type = models.TextField(null=True, blank=True) on_delete=models.CASCADE)
source = models.TextField(null=True, blank=True) group = models.ForeignKey('OtherObjectsGroup', default=None, related_name='other_objects', on_delete=models.CASCADE)
param1 = models.FloatField(blank=True, null=True)
param2 = models.TextField(blank=True, null=True)
visible = models.BooleanField(default=True)
class PointDist(models.Model): class PointDist(models.Model):
class Meta:
verbose_name_plural = 'Расстояния между точками'
id1 = models.ForeignKey('PlacementPoint', on_delete=models.CASCADE, null=False, related_name='placement_point_id1') id1 = models.ForeignKey('PlacementPoint', on_delete=models.CASCADE, null=False, related_name='placement_point_id1')
id2 = models.ForeignKey('PlacementPoint', on_delete=models.CASCADE, null=False, related_name='placement_point_id2') id2 = models.ForeignKey('PlacementPoint', on_delete=models.CASCADE, null=False, related_name='placement_point_id2')
distance = models.FloatField(null=False) distance = models.FloatField(null=False)
class Post_and_pvzCategory(models.Model):
class Meta:
verbose_name = 'категория постаматов и ПВЗ'
verbose_name_plural = 'Категории постаматов и ПВЗ'
def __str__(self):
return self.name
name = models.TextField(null=False, blank=False, verbose_name='Название слоя')
image = models.ImageField(blank=True, null=True, default=None, upload_to='post_and_pvz_category_images/',
verbose_name='Картинка')
visible = models.BooleanField(default=True)
inlude_in_ml = models.BooleanField(default=True)
class Post_and_pvzGroup(models.Model):
class Meta:
verbose_name = 'группа постаматов и ПВЗ'
verbose_name_plural = 'Группы постаматов и ПВЗ'
def __str__(self):
return self.category.name + ' ' + self.name
name = models.TextField(null=False, blank=False, verbose_name='Название группы')
category = models.ForeignKey('Post_and_pvzCategory', default=None, related_name='post_and_pvz_group',
on_delete=models.CASCADE)
image = models.ImageField(blank=True, null=True, upload_to='post_and_pvz_group_images/', verbose_name='Картинка')
visible = models.BooleanField(default=True)
inlude_in_ml = models.BooleanField(default=True)
class OtherObjectsCategory(models.Model):
class Meta:
verbose_name = 'категория прочих объектов'
verbose_name_plural = 'Категории прочих объектов'
def __str__(self):
return self.name
name = models.TextField(null=False, blank=False, verbose_name='Название слоя')
image = models.ImageField(blank=True, null=True, default=None, upload_to='other_objects_category_images/',
verbose_name='Картинка')
visible = models.BooleanField(default=True)
class OtherObjectsGroup(models.Model):
class Meta:
verbose_name = 'группа прочих объектов'
verbose_name_plural = 'Группы прочих объектов'
def __str__(self):
return self.category.name + ' ' + self.name
name = models.TextField(null=False, blank=False, verbose_name='Название группы')
category = models.ForeignKey('OtherObjectsCategory', default=None, related_name='otherobjectsgroup',
on_delete=models.CASCADE)
image = models.ImageField(blank=True, null=True, upload_to='other_objects_group_images/', verbose_name='Картинка')
visible = models.BooleanField(default=True)
class PlacementPointPVZDistance(models.Model):
placement_point = models.ForeignKey('PlacementPoint', default=None, on_delete=models.CASCADE)
pvz_postamates_group = models.ForeignKey('Post_and_pvzGroup', default=None, on_delete=models.CASCADE)
dist = models.FloatField(blank=True, null=True, default=None)
class TaskStatus(models.Model):
class Meta:
verbose_name = 'Статус фоновых задач'
verbose_name_plural = 'Статус фоновых задач'
def __str__(self):
return self.task_name
task_name = models.TextField(blank=False, unique=True, verbose_name='Название задачи')
status = models.TextField(blank=True, null=True, verbose_name='Статус выполнения')
class LastMLCall(models.Model): class LastMLCall(models.Model):
dt = models.DateTimeField(auto_now_add=True) dt = models.DateTimeField(auto_now_add=True)

@ -14,12 +14,13 @@ from shapely import wkb
from sklearn import metrics from sklearn import metrics
from sklearn import model_selection as ms from sklearn import model_selection as ms
from sqlalchemy import text from sqlalchemy import text
from django.contrib.gis.db.models.functions import Distance
import requests import requests
from io import StringIO
from postamates.settings import AGE_DAY_LIMIT from postamates.settings import AGE_DAY_LIMIT
from postamates.settings import DB_URL from postamates.settings import DB_URL
from service.models import PlacementPoint, LastMLCall from service.models import PlacementPoint, LastMLCall
from service import models
def log_to_telegram(msg): def log_to_telegram(msg):
@ -312,6 +313,32 @@ def raschet():
log_to_telegram('end raschet') log_to_telegram('end raschet')
@shared_task
def calculate_group_distance(groups: list):
status, _ = models.TaskStatus.objects.get_or_create(task_name='Расчет ближайшего расстояния')
points = models.PlacementPoint.objects.all()
num_points = points.count()
total = len(groups) * num_points
for _i, gr in enumerate(groups):
group = models.Post_and_pvzGroup.objects.get(name=gr['group'], category__name=gr['category'])
for _j, point in enumerate(points):
status.status = "Подсчет расстояний: " + str(int((num_points * _i + _j) / total * 100)) + "%"
status.save()
post_object = models.Post_and_pvz.objects.filter(group__name=group.name).annotate(
distance=Distance("wkt", point.geometry)).order_by('distance').first()
d = models.PlacementPointPVZDistance.objects.filter(placement_point=point,
pvz_postamates_group=group).first()
if d:
if d.dist > post_object.distance.m:
d.dist = post_object.distance.m
d.save()
else:
models.PlacementPointPVZDistance.objects.create(placement_point=point, pvz_postamates_group=group,
dist=post_object.distance.m)
status.status = "Подсчет расстояний завершен"
status.save()
@shared_task() @shared_task()
def add_age_day(): def add_age_day():
qs = PlacementPoint.objects qs = PlacementPoint.objects

@ -32,7 +32,8 @@ urlpatterns = [
path('ao_rayons', views.AOViewSet.as_view({'get': 'list'}), name='ao_and_rayons'), path('ao_rayons', views.AOViewSet.as_view({'get': 'list'}), name='ao_and_rayons'),
url(r'load_csv/', views.refresh_placement_points.as_view(), name='upload_placement_points'), url(r'load_csv/', views.refresh_placement_points.as_view(), name='upload_placement_points'),
url(r'upload_ao_and_rayons/', views.load_ao_and_rayons.as_view(), name='upload_ao_and_rayons'), url(r'upload_ao_and_rayons/', views.load_ao_and_rayons.as_view(), name='upload_ao_and_rayons'),
url(r'upload_rivals/', views.upload_rivals, name='upload_rivals'), url(r'upload_post_and_pvz/', views.upload_post_and_pvz, name='upload_post_and_pvz'),
url(r'upload_other_objects/', views.upload_other_objects, name='upload_other_objects'),
url(r'upload_dist/', views.upload_dist, name='upload_dist'), url(r'upload_dist/', views.upload_dist, name='upload_dist'),
url(r'me/', views.get_current_user, name='me'), url(r'me/', views.get_current_user, name='me'),
re_path(r'^swagger(?P<format>\.json|\.yaml)$', schema_view.without_ui(cache_timeout=0), name='schema-json'), re_path(r'^swagger(?P<format>\.json|\.yaml)$', schema_view.without_ui(cache_timeout=0), name='schema-json'),

@ -4,6 +4,7 @@ import pandas as pd
from django.contrib.gis.geos import GEOSGeometry from django.contrib.gis.geos import GEOSGeometry
from geojson import MultiPolygon from geojson import MultiPolygon
from tqdm import tqdm from tqdm import tqdm
from service.tasks import calculate_group_distance
from service import models from service import models
@ -44,13 +45,45 @@ def load_ao_and_rayons(
def load_rivals(filepath: str): def load_rivals(filepath: str):
models.Rivals.objects.all().delete() df = pd.read_excel(filepath)
df = pd.read_csv(filepath) df = df.replace(np.nan, None)
df = df.replace('NaT', None)
df.columns = df.columns.str.lower()
for row in tqdm(df.to_dict('records'), desc='Loading data...'):
category = row.get('category')
group = row.get('group')
if category:
cat, _ = models.Post_and_pvzCategory.objects.get_or_create(name=category)
if group:
gr, _ = models.Post_and_pvzGroup.objects.get_or_create(name=group, category=cat)
row['category'] = cat
row['group'] = gr
lon = str(row.pop('lon'))
lat = str(row.pop("lat"))
row['wkt'] = "POINT(" + lon + " " + lat + ")"
models.Post_and_pvz.objects.get_or_create(**row)
new_groups = df[['group', 'category']].drop_duplicates().to_dict(orient='records')
calculate_group_distance.delay(new_groups)
def load_other_objects(filepath: str):
df = pd.read_excel(filepath)
df = df.replace(np.nan, None) df = df.replace(np.nan, None)
df = df.replace('NaT', None) df = df.replace('NaT', None)
df.columns = df.columns.str.lower() df.columns = df.columns.str.lower()
for row in tqdm(df.to_dict('records'), desc='Loading data...'): for row in tqdm(df.to_dict('records'), desc='Loading data...'):
models.Rivals.objects.create(**row) category = row.get('category')
group = row.get('group')
if category:
cat, _ = models.OtherObjectsCategory.objects.get_or_create(name=category)
if group:
gr, _ = models.OtherObjectsGroup.objects.get_or_create(name=group, category=cat)
row['category'] = cat
row['group'] = gr
lon = str(row.pop('lon'))
lat = str(row.pop("lat"))
row['wkt'] = "POINT(" + lon + " " + lat + ")"
models.OtherObjects.objects.get_or_create(**row)
def load_dist(filepath: str): def load_dist(filepath: str):

@ -25,6 +25,8 @@ from service.service import PointService
from service.tasks import raschet from service.tasks import raschet
from service.utils import load_data from service.utils import load_data
from rest_framework.permissions import AllowAny from rest_framework.permissions import AllowAny
from django.shortcuts import redirect
from django.contrib import messages
class AOViewSet(ReadOnlyModelViewSet): class AOViewSet(ReadOnlyModelViewSet):
@ -231,7 +233,8 @@ class refresh_placement_points(APIView):
warnings.filterwarnings('ignore') warnings.filterwarnings('ignore')
file = request.FILES['file'] file = request.FILES['file']
load_data(file) load_data(file)
return Response(status=HTTPStatus.OK) messages.success(request, 'Файл точек успешно загружен')
return redirect('/admin')
class load_ao_and_rayons(APIView): class load_ao_and_rayons(APIView):
@ -241,15 +244,26 @@ class load_ao_and_rayons(APIView):
file_ao = request.FILES['file_ao'] file_ao = request.FILES['file_ao']
file_rayon = request.FILES['file_rayon'] file_rayon = request.FILES['file_rayon']
utils.load_ao_and_rayons(file_ao, file_rayon) utils.load_ao_and_rayons(file_ao, file_rayon)
return Response(status=HTTPStatus.OK) messages.success(request, 'Файл АО и Районов успешно загружен')
return redirect('/admin')
@api_view(['POST']) @api_view(['POST'])
def upload_rivals(request): def upload_post_and_pvz(request):
warnings.filterwarnings('ignore') warnings.filterwarnings('ignore')
file_rivals = request.FILES['file_rivals'] file_rivals = request.FILES['file_post_and_pvz']
utils.load_rivals(file_rivals) utils.load_rivals(file_rivals)
return JsonResponse({'message': 'OK'}) messages.success(request, 'Файл ПВЗ и Постаматов успешно загружен')
return redirect('/admin')
@api_view(['POST'])
def upload_other_objects(request):
warnings.filterwarnings('ignore')
file_rivals = request.FILES['file_other_objects']
utils.load_other_objects(file_rivals)
messages.success(request, 'Файл прочих объектов успешно загружен')
return redirect('/admin')
@api_view(['POST']) @api_view(['POST'])
@ -257,7 +271,8 @@ def upload_dist(request):
warnings.filterwarnings('ignore') warnings.filterwarnings('ignore')
file_dist = request.FILES['file_dist'] file_dist = request.FILES['file_dist']
utils.load_dist(file_dist) utils.load_dist(file_dist)
return JsonResponse({'message': 'OK'}) messages.success(request, 'Файл расстояний успешно загружен')
return redirect('/admin')
@api_view(['GET']) @api_view(['GET'])

@ -71,10 +71,16 @@
<input type="file" name="file" accept=".zip"> <input type="file" name="file" accept=".zip">
<input type="submit" value="Отправить"> <input type="submit" value="Отправить">
</form> </form>
<h3>Загрузить файл конкурентов</h3> <h3>Загрузить файл ПВЗ и Постаматов</h3>
<form method="post" action="/api/upload_rivals/" enctype="multipart/form-data"> <form method="post" action="/api/upload_post_and_pvz/" enctype="multipart/form-data">
{% csrf_token %} {% csrf_token %}
<input type="file" name="file_rivals" accept=".csv"> <input type="file" name="file_post_and_pvz" accept=".xlsx">
<input type="submit" value="Отправить">
</form>
<h3>Загрузить файл прочих объектов</h3>
<form method="post" action="/api/upload_other_objects/" enctype="multipart/form-data">
{% csrf_token %}
<input type="file" name="file_other_objects" accept=".xlsx">
<input type="submit" value="Отправить"> <input type="submit" value="Отправить">
</form> </form>
<h3>Загрузить файл расстояний</h3> <h3>Загрузить файл расстояний</h3>

Loading…
Cancel
Save