From 12d7e7af35ddf79795fe0af179d365c17e451a86 Mon Sep 17 00:00:00 2001 From: Alexey Kudelko Date: Wed, 7 Feb 2024 17:46:04 +0300 Subject: [PATCH 01/17] added POST request --- procollab/urls.py | 1 + rate_projects/admin.py | 29 ++++++++++++++++++++++++++ rate_projects/models.py | 13 ++++++++++++ rate_projects/serializers.py | 21 +++++++++++++++++++ rate_projects/urls.py | 7 +++++++ rate_projects/validators.py | 40 ++++++++++++++++++++++++++++++++++++ rate_projects/views.py | 33 +++++++++++++++++++++++++++++ users/permissions.py | 9 ++++++++ 8 files changed, 153 insertions(+) create mode 100644 rate_projects/admin.py create mode 100644 rate_projects/serializers.py create mode 100644 rate_projects/urls.py create mode 100644 rate_projects/validators.py create mode 100644 rate_projects/views.py diff --git a/procollab/urls.py b/procollab/urls.py index 4596fe57..33031d02 100644 --- a/procollab/urls.py +++ b/procollab/urls.py @@ -47,6 +47,7 @@ path("chats/", include("chats.urls", namespace="chats")), path("events/", include("events.urls", namespace="events")), path("programs/", include("partner_programs.urls", namespace="partner_programs")), + path("rate-project/", include(("rate_projects.urls", "rate_projects"))), path("feed/", include("feed.urls", namespace="feed")), path("api/token/", TokenObtainPairView.as_view(), name="token_obtain_pair"), path("api/token/refresh/", TokenRefreshView.as_view(), name="token_refresh"), diff --git a/rate_projects/admin.py b/rate_projects/admin.py new file mode 100644 index 00000000..9f7da922 --- /dev/null +++ b/rate_projects/admin.py @@ -0,0 +1,29 @@ +from django.contrib import admin +from .models import Criteria, ProjectScore + + +# Register your models here. +@admin.register(Criteria) +class CriteriaAdmin(admin.ModelAdmin): + list_display = ( + "id", + "name", + "type", + # добавить проект / программу + ) + list_display_links = ( + "id", + "name", + ) + + +@admin.register(ProjectScore) +class ProjectScoreAdmin(admin.ModelAdmin): + list_display = ( + "id", + # добавить проект / программу + ) + list_display_links = ( + "id", + ) + diff --git a/rate_projects/models.py b/rate_projects/models.py index 53e6b32b..a7795a16 100644 --- a/rate_projects/models.py +++ b/rate_projects/models.py @@ -4,6 +4,7 @@ from partner_programs.models import PartnerProgram from projects.models import Project from .constants import TYPES, get_type +from .validators import ProjectScoreValidate User = get_user_model() @@ -119,6 +120,18 @@ class ProjectScore(models.Model): def __str__(self): return f"ProjectScore<{self.id}> - {self.criteria.name}" + def save(self, *args, **kwargs): + ProjectScoreValidate( + criteria_type=self.criteria.type, + value_int=self.value_int, + value_str=self.value_str, + value_bool=self.value_bool, + value_float=self.value_float, + criteria_min_value=self.criteria.min_value, + criteria_max_value=self.criteria.max_value + ) + super().save(*args, **kwargs) + class Meta: verbose_name = "Оценка проекта" diff --git a/rate_projects/serializers.py b/rate_projects/serializers.py new file mode 100644 index 00000000..5402f676 --- /dev/null +++ b/rate_projects/serializers.py @@ -0,0 +1,21 @@ +from rest_framework import serializers + +from rate_projects.constants import get_type +from rate_projects.models import ProjectScore +from rate_projects.validators import ProjectScoreValidate + + +class ProjectScoreCreateSerializer(serializers.ModelSerializer[ProjectScore]): + class Meta: + model = ProjectScore + fields = [ + "criteria", + "user", + "project", + "value_int", + "value_float", + "value_bool", + "value_str" + ] + + diff --git a/rate_projects/urls.py b/rate_projects/urls.py new file mode 100644 index 00000000..b340b2b3 --- /dev/null +++ b/rate_projects/urls.py @@ -0,0 +1,7 @@ +from django.urls import path + +from rate_projects.views import RateProject + +urlpatterns = [ + path("rate/", RateProject.as_view()) +] \ No newline at end of file diff --git a/rate_projects/validators.py b/rate_projects/validators.py new file mode 100644 index 00000000..3f00d066 --- /dev/null +++ b/rate_projects/validators.py @@ -0,0 +1,40 @@ +from rate_projects.constants import get_type + + +class ProjectScoreValidate: + def __init__(self, **kwargs): + self.criteria_type = kwargs.get('criteria_type') + self.value_int = kwargs.get('value_int') + self.value_str = kwargs.get('value_str') + self.value_bool = kwargs.get('value_bool') + self.value_float = kwargs.get('value_float') + self.criteria_min_value = kwargs.get('criteria_min_value') + self.criteria_max_value = kwargs.get('criteria_max_value') + + self._validate_quantity_filled_fields() + self._validate_numeric_fields() + + @property + def _find_filled_field(self): + filled_fields = [] + for field in ['value_int', 'value_bool', 'value_str', 'value_float']: + if getattr(self, field) is not None: + filled_fields.append(getattr(self, field)) + return filled_fields + + def _validate_quantity_filled_fields(self): + filled_fields = self._find_filled_field + if len(filled_fields) > 1: + raise ValueError(f'Должно быть заполнено менее 2-ух полей!') + + if not isinstance(filled_fields[0], get_type.get(self.criteria_type)): + raise ValueError(f'Тип введённых данных не совпадает с требуемым!') + + def _validate_numeric_fields(self): + added_value = self._find_filled_field[0] + + if self.criteria_type != 'bool' and isinstance(added_value, (int, float)): + if self.criteria_min_value is not None and self.criteria_min_value > added_value: + raise ValueError("Оценка этого критерия принизила допустимые значения!") + elif self.criteria_max_value is not None and self.criteria_max_value < added_value: + raise ValueError("Оценка этого критерия превысила допустимые значения!") diff --git a/rate_projects/views.py b/rate_projects/views.py new file mode 100644 index 00000000..496a719e --- /dev/null +++ b/rate_projects/views.py @@ -0,0 +1,33 @@ +from django.contrib.auth import get_user_model + +from rest_framework import generics, status +from rest_framework.response import Response + + +from rate_projects.serializers import ProjectScoreCreateSerializer +from users.permissions import IsExpert + +User = get_user_model() + +class RateProject(generics.CreateAPIView): + serializer_class = ProjectScoreCreateSerializer + permission_classes = [IsExpert] + + def create(self, request, *args, **kwargs): + try: + data = self.request.data + data['user'] = self.request.user.id + + serializer = self.get_serializer(data=data) + if serializer.is_valid(): + serializer.save() + self.perform_create(serializer) + return Response({'success': True}, status=status.HTTP_201_CREATED) + else: + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + except Exception as e: + return Response({'error': str(e)}, status=status.HTTP_400_BAD_REQUEST) + + + + diff --git a/users/permissions.py b/users/permissions.py index df7eb8f9..ce7e91ae 100644 --- a/users/permissions.py +++ b/users/permissions.py @@ -10,3 +10,12 @@ def has_object_permission(self, request, view, obj): if request.method in SAFE_METHODS or (obj.user == request.user): return True return False + + + +class IsExpert(BasePermission): + """ + Allows access if user is EXPERT + """ + def has_permission(self, request, view): + return request.user.user_type == 3 \ No newline at end of file From 6c4171c5546694dd6f7fcd200fcadcc35bc9336c Mon Sep 17 00:00:00 2001 From: Alexey Kudelko Date: Fri, 9 Feb 2024 17:33:38 +0300 Subject: [PATCH 02/17] linter update --- rate_projects/admin.py | 5 +-- rate_projects/constants.py | 11 ++---- rate_projects/models.py | 68 ++++++++++-------------------------- rate_projects/serializers.py | 7 ++-- rate_projects/urls.py | 4 +-- rate_projects/validators.py | 36 +++++++++++-------- rate_projects/views.py | 11 +++--- 7 files changed, 50 insertions(+), 92 deletions(-) diff --git a/rate_projects/admin.py b/rate_projects/admin.py index 9f7da922..c5ee8df2 100644 --- a/rate_projects/admin.py +++ b/rate_projects/admin.py @@ -23,7 +23,4 @@ class ProjectScoreAdmin(admin.ModelAdmin): "id", # добавить проект / программу ) - list_display_links = ( - "id", - ) - + list_display_links = ("id",) diff --git a/rate_projects/constants.py b/rate_projects/constants.py index ed30d627..f0c1deea 100644 --- a/rate_projects/constants.py +++ b/rate_projects/constants.py @@ -1,13 +1,8 @@ -TYPES = ( +VERBOSE_NAME_TYPES = ( ("str", "Текст"), ("int", "Целочисленное число"), ("float", "Число с плавающей точкой"), - ("bool", "Да или нет") + ("bool", "Да или нет"), ) -get_type = { - "str": str, - "int": int, - "float": float, - "bool": bool -} +GET_TYPE_FROM_STRING = {"str": str, "int": int, "float": float, "bool": bool} diff --git a/rate_projects/models.py b/rate_projects/models.py index a7795a16..281efcd4 100644 --- a/rate_projects/models.py +++ b/rate_projects/models.py @@ -3,11 +3,12 @@ from partner_programs.models import PartnerProgram from projects.models import Project -from .constants import TYPES, get_type +from .constants import VERBOSE_NAME_TYPES from .validators import ProjectScoreValidate User = get_user_model() + class Criteria(models.Model): """ Criteria model @@ -21,32 +22,22 @@ class Criteria(models.Model): partner_program: A ForeignKey connection to PartnerProgram model """ - name = models.CharField( - verbose_name="Название", - max_length=50 - ) - description = models.TextField( - verbose_name="Описание", - null=True, - blank=True - ) - type = models.CharField( - verbose_name="Тип", - max_length=8, - choices=TYPES - ) + + name = models.CharField(verbose_name="Название", max_length=50) + description = models.TextField(verbose_name="Описание", null=True, blank=True) + type = models.CharField(verbose_name="Тип", max_length=8, choices=VERBOSE_NAME_TYPES) min_value = models.FloatField( verbose_name="Минимально допустимое числовое значение", help_text="(если есть)", null=True, - blank=True + blank=True, ) max_value = models.FloatField( verbose_name="Максимально допустимое числовое значение", help_text="(если есть)", null=True, - blank=True + blank=True, ) partner_program = models.ForeignKey( PartnerProgram, @@ -62,7 +53,6 @@ class Meta: verbose_name_plural = "Критерии оценки проектов" - class ProjectScore(models.Model): """ ProjectScore model @@ -77,46 +67,26 @@ class ProjectScore(models.Model): value_str: IntegerField for value """ + criteria = models.ForeignKey( - Criteria, - on_delete=models.CASCADE, - related_name="scores" - ) - user = models.ForeignKey( - User, - on_delete=models.CASCADE, - related_name="scores" - ) - project = models.ForeignKey( - Project, - on_delete=models.CASCADE, - related_name="scores" + Criteria, on_delete=models.CASCADE, related_name="scores" ) + user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="scores") + project = models.ForeignKey(Project, on_delete=models.CASCADE, related_name="scores") value_int = models.IntegerField( - verbose_name="Целочисленное значение", - null=True, - blank=True + verbose_name="Целочисленное значение", null=True, blank=True ) value_float = models.FloatField( - verbose_name="Значение с плавающей запятой", - max_length=50, - null=True, - blank=True + verbose_name="Значение с плавающей запятой", max_length=50, null=True, blank=True ) value_bool = models.BooleanField( - verbose_name="'Да или нет' значение", - null=True, - blank=True + verbose_name="'Да или нет' значение", null=True, blank=True ) value_str = models.FloatField( - verbose_name="Текстовое значение", - max_length=50, - null=True, - blank=True + verbose_name="Текстовое значение", max_length=50, null=True, blank=True ) - def __str__(self): return f"ProjectScore<{self.id}> - {self.criteria.name}" @@ -128,13 +98,11 @@ def save(self, *args, **kwargs): value_bool=self.value_bool, value_float=self.value_float, criteria_min_value=self.criteria.min_value, - criteria_max_value=self.criteria.max_value + criteria_max_value=self.criteria.max_value, ) super().save(*args, **kwargs) - class Meta: verbose_name = "Оценка проекта" verbose_name_plural = "Оценки проектов" - unique_together = ('criteria', 'user', 'project') - + unique_together = ("criteria", "user", "project") diff --git a/rate_projects/serializers.py b/rate_projects/serializers.py index 5402f676..83ec7a94 100644 --- a/rate_projects/serializers.py +++ b/rate_projects/serializers.py @@ -1,8 +1,7 @@ from rest_framework import serializers -from rate_projects.constants import get_type + from rate_projects.models import ProjectScore -from rate_projects.validators import ProjectScoreValidate class ProjectScoreCreateSerializer(serializers.ModelSerializer[ProjectScore]): @@ -15,7 +14,5 @@ class Meta: "value_int", "value_float", "value_bool", - "value_str" + "value_str", ] - - diff --git a/rate_projects/urls.py b/rate_projects/urls.py index b340b2b3..5bcb115a 100644 --- a/rate_projects/urls.py +++ b/rate_projects/urls.py @@ -2,6 +2,4 @@ from rate_projects.views import RateProject -urlpatterns = [ - path("rate/", RateProject.as_view()) -] \ No newline at end of file +urlpatterns = [path("rate/", RateProject.as_view())] diff --git a/rate_projects/validators.py b/rate_projects/validators.py index 3f00d066..dc72d9c2 100644 --- a/rate_projects/validators.py +++ b/rate_projects/validators.py @@ -1,15 +1,15 @@ -from rate_projects.constants import get_type +from rate_projects.constants import GET_TYPE_FROM_STRING class ProjectScoreValidate: def __init__(self, **kwargs): - self.criteria_type = kwargs.get('criteria_type') - self.value_int = kwargs.get('value_int') - self.value_str = kwargs.get('value_str') - self.value_bool = kwargs.get('value_bool') - self.value_float = kwargs.get('value_float') - self.criteria_min_value = kwargs.get('criteria_min_value') - self.criteria_max_value = kwargs.get('criteria_max_value') + self.criteria_type = kwargs.get("criteria_type") + self.value_int = kwargs.get("value_int") + self.value_str = kwargs.get("value_str") + self.value_bool = kwargs.get("value_bool") + self.value_float = kwargs.get("value_float") + self.criteria_min_value = kwargs.get("criteria_min_value") + self.criteria_max_value = kwargs.get("criteria_max_value") self._validate_quantity_filled_fields() self._validate_numeric_fields() @@ -17,7 +17,7 @@ def __init__(self, **kwargs): @property def _find_filled_field(self): filled_fields = [] - for field in ['value_int', 'value_bool', 'value_str', 'value_float']: + for field in ["value_int", "value_bool", "value_str", "value_float"]: if getattr(self, field) is not None: filled_fields.append(getattr(self, field)) return filled_fields @@ -25,16 +25,22 @@ def _find_filled_field(self): def _validate_quantity_filled_fields(self): filled_fields = self._find_filled_field if len(filled_fields) > 1: - raise ValueError(f'Должно быть заполнено менее 2-ух полей!') + raise ValueError("Должно быть заполнено менее 2-ух полей!") - if not isinstance(filled_fields[0], get_type.get(self.criteria_type)): - raise ValueError(f'Тип введённых данных не совпадает с требуемым!') + if not isinstance(filled_fields[0], GET_TYPE_FROM_STRING.get(self.criteria_type)): + raise ValueError("Тип введённых данных не совпадает с требуемым!") def _validate_numeric_fields(self): added_value = self._find_filled_field[0] - if self.criteria_type != 'bool' and isinstance(added_value, (int, float)): - if self.criteria_min_value is not None and self.criteria_min_value > added_value: + if self.criteria_type != "bool" and isinstance(added_value, (int, float)): + if ( + self.criteria_min_value is not None + and self.criteria_min_value > added_value + ): raise ValueError("Оценка этого критерия принизила допустимые значения!") - elif self.criteria_max_value is not None and self.criteria_max_value < added_value: + elif ( + self.criteria_max_value is not None + and self.criteria_max_value < added_value + ): raise ValueError("Оценка этого критерия превысила допустимые значения!") diff --git a/rate_projects/views.py b/rate_projects/views.py index 496a719e..23d5805c 100644 --- a/rate_projects/views.py +++ b/rate_projects/views.py @@ -9,6 +9,7 @@ User = get_user_model() + class RateProject(generics.CreateAPIView): serializer_class = ProjectScoreCreateSerializer permission_classes = [IsExpert] @@ -16,18 +17,14 @@ class RateProject(generics.CreateAPIView): def create(self, request, *args, **kwargs): try: data = self.request.data - data['user'] = self.request.user.id + data["user"] = self.request.user.id serializer = self.get_serializer(data=data) if serializer.is_valid(): serializer.save() self.perform_create(serializer) - return Response({'success': True}, status=status.HTTP_201_CREATED) + return Response({"success": True}, status=status.HTTP_201_CREATED) else: return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) except Exception as e: - return Response({'error': str(e)}, status=status.HTTP_400_BAD_REQUEST) - - - - + return Response({"error": str(e)}, status=status.HTTP_400_BAD_REQUEST) From d1b9a686a50ed191678290077611fb4d4d15ece5 Mon Sep 17 00:00:00 2001 From: Alexey Kudelko Date: Fri, 9 Feb 2024 17:35:28 +0300 Subject: [PATCH 03/17] linter fix --- users/permissions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/users/permissions.py b/users/permissions.py index ce7e91ae..ef53b4de 100644 --- a/users/permissions.py +++ b/users/permissions.py @@ -12,10 +12,10 @@ def has_object_permission(self, request, view, obj): return False - class IsExpert(BasePermission): """ Allows access if user is EXPERT """ + def has_permission(self, request, view): - return request.user.user_type == 3 \ No newline at end of file + return request.user.user_type == 3 From 751c9a648cdbf101a1c00b22b368b4c5f2d80058 Mon Sep 17 00:00:00 2001 From: Alexey Kudelko Date: Sat, 10 Feb 2024 05:29:51 +0300 Subject: [PATCH 04/17] added comment, changed namings, fixed models --- ...alter_projectscore_value_float_and_more.py | 34 +++++++++++++++++++ rate_projects/models.py | 13 +++++-- rate_projects/serializers.py | 3 +- 3 files changed, 47 insertions(+), 3 deletions(-) create mode 100644 rate_projects/migrations/0002_projectscore_comment_alter_projectscore_value_float_and_more.py diff --git a/rate_projects/migrations/0002_projectscore_comment_alter_projectscore_value_float_and_more.py b/rate_projects/migrations/0002_projectscore_comment_alter_projectscore_value_float_and_more.py new file mode 100644 index 00000000..5cb82ee0 --- /dev/null +++ b/rate_projects/migrations/0002_projectscore_comment_alter_projectscore_value_float_and_more.py @@ -0,0 +1,34 @@ +# Generated by Django 4.2.3 on 2024-02-10 02:14 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("rate_projects", "0001_initial"), + ] + + operations = [ + migrations.AddField( + model_name="projectscore", + name="comment", + field=models.CharField( + blank=True, max_length=100, null=True, verbose_name="Комментарий" + ), + ), + migrations.AlterField( + model_name="projectscore", + name="value_float", + field=models.FloatField( + blank=True, null=True, verbose_name="Значение с плавающей запятой" + ), + ), + migrations.AlterField( + model_name="projectscore", + name="value_str", + field=models.CharField( + blank=True, max_length=50, null=True, verbose_name="Текстовое значение" + ), + ), + ] \ No newline at end of file diff --git a/rate_projects/models.py b/rate_projects/models.py index 281efcd4..834d32b8 100644 --- a/rate_projects/models.py +++ b/rate_projects/models.py @@ -66,6 +66,11 @@ class ProjectScore(models.Model): value_bool: IntegerField for value value_str: IntegerField for value + value_float: FloatField for value + value_bool: BooleanField for value + value_str: CharField for value + commentary: CharField for optional commentary + """ criteria = models.ForeignKey( @@ -78,15 +83,19 @@ class ProjectScore(models.Model): verbose_name="Целочисленное значение", null=True, blank=True ) value_float = models.FloatField( - verbose_name="Значение с плавающей запятой", max_length=50, null=True, blank=True + verbose_name="Значение с плавающей запятой", null=True, blank=True ) value_bool = models.BooleanField( verbose_name="'Да или нет' значение", null=True, blank=True ) - value_str = models.FloatField( + value_str = models.CharField( verbose_name="Текстовое значение", max_length=50, null=True, blank=True ) + comment = models.CharField( + verbose_name="Комментарий", null=True, blank=True, max_length=100 + ) + def __str__(self): return f"ProjectScore<{self.id}> - {self.criteria.name}" diff --git a/rate_projects/serializers.py b/rate_projects/serializers.py index 83ec7a94..495fa002 100644 --- a/rate_projects/serializers.py +++ b/rate_projects/serializers.py @@ -4,7 +4,7 @@ from rate_projects.models import ProjectScore -class ProjectScoreCreateSerializer(serializers.ModelSerializer[ProjectScore]): +class ProjectScoreCreateSerializer(serializers.ModelSerializer): class Meta: model = ProjectScore fields = [ @@ -15,4 +15,5 @@ class Meta: "value_float", "value_bool", "value_str", + "comment", ] From d8fac388204ceaa0d667729ace76130ad4c3d317 Mon Sep 17 00:00:00 2001 From: Alexey Kudelko Date: Sat, 10 Feb 2024 14:10:16 +0300 Subject: [PATCH 05/17] changed model to one value field --- rate_projects/constants.py | 2 - rate_projects/migrations/0001_initial.py | 36 ++++--------- ...alter_projectscore_value_float_and_more.py | 34 ------------- rate_projects/models.py | 28 ++--------- rate_projects/serializers.py | 5 +- rate_projects/validators.py | 50 +++++++------------ 6 files changed, 32 insertions(+), 123 deletions(-) delete mode 100644 rate_projects/migrations/0002_projectscore_comment_alter_projectscore_value_float_and_more.py diff --git a/rate_projects/constants.py b/rate_projects/constants.py index f0c1deea..11504c22 100644 --- a/rate_projects/constants.py +++ b/rate_projects/constants.py @@ -4,5 +4,3 @@ ("float", "Число с плавающей точкой"), ("bool", "Да или нет"), ) - -GET_TYPE_FROM_STRING = {"str": str, "int": int, "float": float, "bool": bool} diff --git a/rate_projects/migrations/0001_initial.py b/rate_projects/migrations/0001_initial.py index b1bcb784..341ab849 100644 --- a/rate_projects/migrations/0001_initial.py +++ b/rate_projects/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2.3 on 2024-02-07 11:02 +# Generated by Django 4.2.3 on 2024-02-10 10:49 from django.conf import settings from django.db import migrations, models @@ -10,9 +10,9 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ("projects", "0021_project_subscribers"), - migrations.swappable_dependency(settings.AUTH_USER_MODEL), ("partner_programs", "0004_auto_20231230_0002"), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ("projects", "0021_project_subscribers"), ] operations = [ @@ -91,33 +91,15 @@ class Migration(migrations.Migration): ), ), ( - "value_int", - models.IntegerField( - blank=True, null=True, verbose_name="Целочисленное значение" - ), - ), - ( - "value_float", - models.FloatField( - blank=True, - max_length=50, - null=True, - verbose_name="Значение с плавающей запятой", - ), - ), - ( - "value_bool", - models.BooleanField( - blank=True, null=True, verbose_name="'Да или нет' значение" + "value", + models.CharField( + blank=True, max_length=50, null=True, verbose_name="Значение" ), ), ( - "value_str", - models.FloatField( - blank=True, - max_length=50, - null=True, - verbose_name="Текстовое значение", + "comment", + models.CharField( + blank=True, max_length=100, null=True, verbose_name="Комментарий" ), ), ( diff --git a/rate_projects/migrations/0002_projectscore_comment_alter_projectscore_value_float_and_more.py b/rate_projects/migrations/0002_projectscore_comment_alter_projectscore_value_float_and_more.py deleted file mode 100644 index 5cb82ee0..00000000 --- a/rate_projects/migrations/0002_projectscore_comment_alter_projectscore_value_float_and_more.py +++ /dev/null @@ -1,34 +0,0 @@ -# Generated by Django 4.2.3 on 2024-02-10 02:14 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("rate_projects", "0001_initial"), - ] - - operations = [ - migrations.AddField( - model_name="projectscore", - name="comment", - field=models.CharField( - blank=True, max_length=100, null=True, verbose_name="Комментарий" - ), - ), - migrations.AlterField( - model_name="projectscore", - name="value_float", - field=models.FloatField( - blank=True, null=True, verbose_name="Значение с плавающей запятой" - ), - ), - migrations.AlterField( - model_name="projectscore", - name="value_str", - field=models.CharField( - blank=True, max_length=50, null=True, verbose_name="Текстовое значение" - ), - ), - ] \ No newline at end of file diff --git a/rate_projects/models.py b/rate_projects/models.py index 834d32b8..3bc77742 100644 --- a/rate_projects/models.py +++ b/rate_projects/models.py @@ -61,14 +61,8 @@ class ProjectScore(models.Model): criteria: A ForeignKey connection to Criteria model user: A ForeignKey connection to User model - value_int: IntegerField for value - value_float: IntegerField for value - value_bool: IntegerField for value - value_str: IntegerField for value - - value_float: FloatField for value - value_bool: BooleanField for value - value_str: CharField for value + value: CharField for value + commentary: CharField for optional commentary """ @@ -79,17 +73,8 @@ class ProjectScore(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="scores") project = models.ForeignKey(Project, on_delete=models.CASCADE, related_name="scores") - value_int = models.IntegerField( - verbose_name="Целочисленное значение", null=True, blank=True - ) - value_float = models.FloatField( - verbose_name="Значение с плавающей запятой", null=True, blank=True - ) - value_bool = models.BooleanField( - verbose_name="'Да или нет' значение", null=True, blank=True - ) - value_str = models.CharField( - verbose_name="Текстовое значение", max_length=50, null=True, blank=True + value = models.CharField( + verbose_name="Значение", max_length=50, null=True, blank=True ) comment = models.CharField( @@ -102,10 +87,7 @@ def __str__(self): def save(self, *args, **kwargs): ProjectScoreValidate( criteria_type=self.criteria.type, - value_int=self.value_int, - value_str=self.value_str, - value_bool=self.value_bool, - value_float=self.value_float, + value=self.value, criteria_min_value=self.criteria.min_value, criteria_max_value=self.criteria.max_value, ) diff --git a/rate_projects/serializers.py b/rate_projects/serializers.py index 495fa002..70745d64 100644 --- a/rate_projects/serializers.py +++ b/rate_projects/serializers.py @@ -11,9 +11,6 @@ class Meta: "criteria", "user", "project", - "value_int", - "value_float", - "value_bool", - "value_str", + "value", "comment", ] diff --git a/rate_projects/validators.py b/rate_projects/validators.py index dc72d9c2..1dfc0a65 100644 --- a/rate_projects/validators.py +++ b/rate_projects/validators.py @@ -1,46 +1,30 @@ -from rate_projects.constants import GET_TYPE_FROM_STRING - - class ProjectScoreValidate: def __init__(self, **kwargs): self.criteria_type = kwargs.get("criteria_type") - self.value_int = kwargs.get("value_int") - self.value_str = kwargs.get("value_str") - self.value_bool = kwargs.get("value_bool") - self.value_float = kwargs.get("value_float") + self.value = kwargs.get("value") self.criteria_min_value = kwargs.get("criteria_min_value") self.criteria_max_value = kwargs.get("criteria_max_value") - self._validate_quantity_filled_fields() - self._validate_numeric_fields() - - @property - def _find_filled_field(self): - filled_fields = [] - for field in ["value_int", "value_bool", "value_str", "value_float"]: - if getattr(self, field) is not None: - filled_fields.append(getattr(self, field)) - return filled_fields - - def _validate_quantity_filled_fields(self): - filled_fields = self._find_filled_field - if len(filled_fields) > 1: - raise ValueError("Должно быть заполнено менее 2-ух полей!") + self._validate_data_type() + self._validate_numeric_limits() - if not isinstance(filled_fields[0], GET_TYPE_FROM_STRING.get(self.criteria_type)): - raise ValueError("Тип введённых данных не совпадает с требуемым!") + def _validate_data_type(self): + if self.criteria_type in ["float", "int"]: + try: + float(self.value) + except ValueError: + raise ValueError("Введённое значение не соответствует формату!") - def _validate_numeric_fields(self): - added_value = self._find_filled_field[0] + elif (self.criteria_type == "bool") and (self.value not in ["True", "False"]): + raise TypeError("Введённое значение не соответствует формату!") - if self.criteria_type != "bool" and isinstance(added_value, (int, float)): - if ( - self.criteria_min_value is not None - and self.criteria_min_value > added_value + def _validate_numeric_limits(self): + if self.criteria_type in ["int", "float"]: + if self.criteria_min_value is not None and self.criteria_min_value > float( + self.value ): raise ValueError("Оценка этого критерия принизила допустимые значения!") - elif ( - self.criteria_max_value is not None - and self.criteria_max_value < added_value + elif self.criteria_max_value is not None and self.criteria_max_value < float( + self.value ): raise ValueError("Оценка этого критерия превысила допустимые значения!") From 1f3ce2c2f7767012d220bb2938c8812e2b03020a Mon Sep 17 00:00:00 2001 From: Alexey Kudelko Date: Mon, 19 Feb 2024 21:01:41 +0300 Subject: [PATCH 06/17] POST project rate correction --- .../0002_remove_projectscore_comment.py | 17 ++++++++++++++++ rate_projects/models.py | 4 ---- rate_projects/serializers.py | 9 +-------- rate_projects/urls.py | 2 +- rate_projects/views.py | 20 ++++++++++++++----- 5 files changed, 34 insertions(+), 18 deletions(-) create mode 100644 rate_projects/migrations/0002_remove_projectscore_comment.py diff --git a/rate_projects/migrations/0002_remove_projectscore_comment.py b/rate_projects/migrations/0002_remove_projectscore_comment.py new file mode 100644 index 00000000..a4ffcc18 --- /dev/null +++ b/rate_projects/migrations/0002_remove_projectscore_comment.py @@ -0,0 +1,17 @@ +# Generated by Django 4.2.3 on 2024-02-19 17:04 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("rate_projects", "0001_initial"), + ] + + operations = [ + migrations.RemoveField( + model_name="projectscore", + name="comment", + ), + ] diff --git a/rate_projects/models.py b/rate_projects/models.py index 3bc77742..ad5f628a 100644 --- a/rate_projects/models.py +++ b/rate_projects/models.py @@ -77,10 +77,6 @@ class ProjectScore(models.Model): verbose_name="Значение", max_length=50, null=True, blank=True ) - comment = models.CharField( - verbose_name="Комментарий", null=True, blank=True, max_length=100 - ) - def __str__(self): return f"ProjectScore<{self.id}> - {self.criteria.name}" diff --git a/rate_projects/serializers.py b/rate_projects/serializers.py index 70745d64..d51def34 100644 --- a/rate_projects/serializers.py +++ b/rate_projects/serializers.py @@ -1,16 +1,9 @@ from rest_framework import serializers - from rate_projects.models import ProjectScore class ProjectScoreCreateSerializer(serializers.ModelSerializer): class Meta: model = ProjectScore - fields = [ - "criteria", - "user", - "project", - "value", - "comment", - ] + fields = ["criteria_id", "user_id", "project_id", "value"] diff --git a/rate_projects/urls.py b/rate_projects/urls.py index 5bcb115a..e461f04e 100644 --- a/rate_projects/urls.py +++ b/rate_projects/urls.py @@ -2,4 +2,4 @@ from rate_projects.views import RateProject -urlpatterns = [path("rate/", RateProject.as_view())] +urlpatterns = [path("rate/", RateProject.as_view())] diff --git a/rate_projects/views.py b/rate_projects/views.py index 23d5805c..ad48de89 100644 --- a/rate_projects/views.py +++ b/rate_projects/views.py @@ -3,7 +3,7 @@ from rest_framework import generics, status from rest_framework.response import Response - +from rate_projects.models import ProjectScore from rate_projects.serializers import ProjectScoreCreateSerializer from users.permissions import IsExpert @@ -17,12 +17,22 @@ class RateProject(generics.CreateAPIView): def create(self, request, *args, **kwargs): try: data = self.request.data - data["user"] = self.request.user.id - serializer = self.get_serializer(data=data) + user = self.request.user.id + project_id = self.kwargs.get("project_id") + for criteria in data: + criteria["user_id"] = user + criteria["project_id"] = project_id + criteria["criteria_id"] = criteria.pop("id") + + serializer = self.get_serializer(data=data, many=True) if serializer.is_valid(): - serializer.save() - self.perform_create(serializer) + serializer.is_valid() + + ProjectScore.objects.bulk_create( + [ProjectScore(**score) for score in data] + ) + return Response({"success": True}, status=status.HTTP_201_CREATED) else: return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) From f72f12068a7ce719ad7b2c44132ab4ff1c856310 Mon Sep 17 00:00:00 2001 From: Alexey Kudelko Date: Mon, 19 Feb 2024 21:02:17 +0300 Subject: [PATCH 07/17] minor description fix --- rate_projects/models.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/rate_projects/models.py b/rate_projects/models.py index ad5f628a..79cd5153 100644 --- a/rate_projects/models.py +++ b/rate_projects/models.py @@ -60,11 +60,8 @@ class ProjectScore(models.Model): Attributes: criteria: A ForeignKey connection to Criteria model user: A ForeignKey connection to User model - value: CharField for value - commentary: CharField for optional commentary - """ criteria = models.ForeignKey( From 92aa1889e04ea89acbe44be47a940f509afc2b16 Mon Sep 17 00:00:00 2001 From: Alexey Kudelko Date: Mon, 19 Feb 2024 21:12:21 +0300 Subject: [PATCH 08/17] =?UTF-8?q?minor=20grammar=20fix=20=F0=9F=92=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- rate_projects/views.py | 45 +++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/rate_projects/views.py b/rate_projects/views.py index ad48de89..a627a2f1 100644 --- a/rate_projects/views.py +++ b/rate_projects/views.py @@ -15,26 +15,25 @@ class RateProject(generics.CreateAPIView): permission_classes = [IsExpert] def create(self, request, *args, **kwargs): - try: - data = self.request.data - - user = self.request.user.id - project_id = self.kwargs.get("project_id") - for criteria in data: - criteria["user_id"] = user - criteria["project_id"] = project_id - criteria["criteria_id"] = criteria.pop("id") - - serializer = self.get_serializer(data=data, many=True) - if serializer.is_valid(): - serializer.is_valid() - - ProjectScore.objects.bulk_create( - [ProjectScore(**score) for score in data] - ) - - return Response({"success": True}, status=status.HTTP_201_CREATED) - else: - return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) - except Exception as e: - return Response({"error": str(e)}, status=status.HTTP_400_BAD_REQUEST) + # try: + data = self.request.data + + user = self.request.user.id + project_id = self.kwargs.get("project_id") + for criterion in data: + criterion["user_id"] = user + criterion["project_id"] = project_id + criterion["criteria_id"] = criterion.pop("criterion_id") + + serializer = self.get_serializer(data=data, many=True) + if serializer.is_valid(): + serializer.is_valid() + + ProjectScore.objects.bulk_create([ProjectScore(**score) for score in data]) + + return Response({"success": True}, status=status.HTTP_201_CREATED) + + # else: + # return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + # except Exception as e: + # return Response({"error": str(e)}, status=status.HTTP_400_BAD_REQUEST) From 96f17484ce8e4304cf46eaeaebca071a55051f9c Mon Sep 17 00:00:00 2001 From: Alexey Kudelko Date: Mon, 19 Feb 2024 21:15:15 +0300 Subject: [PATCH 09/17] error processing code uncommented --- rate_projects/views.py | 46 ++++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/rate_projects/views.py b/rate_projects/views.py index a627a2f1..c968db07 100644 --- a/rate_projects/views.py +++ b/rate_projects/views.py @@ -15,25 +15,27 @@ class RateProject(generics.CreateAPIView): permission_classes = [IsExpert] def create(self, request, *args, **kwargs): - # try: - data = self.request.data - - user = self.request.user.id - project_id = self.kwargs.get("project_id") - for criterion in data: - criterion["user_id"] = user - criterion["project_id"] = project_id - criterion["criteria_id"] = criterion.pop("criterion_id") - - serializer = self.get_serializer(data=data, many=True) - if serializer.is_valid(): - serializer.is_valid() - - ProjectScore.objects.bulk_create([ProjectScore(**score) for score in data]) - - return Response({"success": True}, status=status.HTTP_201_CREATED) - - # else: - # return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) - # except Exception as e: - # return Response({"error": str(e)}, status=status.HTTP_400_BAD_REQUEST) + try: + data = self.request.data + + user = self.request.user.id + project_id = self.kwargs.get("project_id") + for criterion in data: + criterion["user_id"] = user + criterion["project_id"] = project_id + criterion["criteria_id"] = criterion.pop("criterion_id") + + serializer = self.get_serializer(data=data, many=True) + if serializer.is_valid(): + serializer.is_valid() + + ProjectScore.objects.bulk_create( + [ProjectScore(**score) for score in data] + ) + + return Response({"success": True}, status=status.HTTP_201_CREATED) + + else: + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + except Exception as e: + return Response({"error": str(e)}, status=status.HTTP_400_BAD_REQUEST) From 2644543382c1b3f114c068bb10a413e64d26715b Mon Sep 17 00:00:00 2001 From: Alexey Kudelko Date: Wed, 21 Feb 2024 00:35:10 +0300 Subject: [PATCH 10/17] fixed no limit and no offset bug --- feed/helpers.py | 13 +++++++++++-- feed/pagination.py | 2 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/feed/helpers.py b/feed/helpers.py index 3c58e552..21785665 100644 --- a/feed/helpers.py +++ b/feed/helpers.py @@ -29,9 +29,16 @@ def paginate_serialize_feed( result = [] pages_count = 0 - offset = int(request.query_params.get("offset", 0)) + offset = request.query_params.get("offset", None) request.query_params._mutable = True - request.query_params["offset"] = int(request.query_params["offset"]) + + if offset == "" or offset is None: + offset = 0 + elif offset is not None: + offset = int(offset) + request.query_params["offset"] = offset + + offset_numbers = randomize_offset(offset, len(model_data.keys())) for i in range(len(model_data.keys())): @@ -45,6 +52,8 @@ def paginate_serialize_feed( shuffle(result) limit = int(request.query_params.get("limit", LIMIT_PAGINATION_CONSTANT)) + if limit == "": + limit = LIMIT_PAGINATION_CONSTANT return result[:limit], pages_count diff --git a/feed/pagination.py b/feed/pagination.py index 3335339b..9e88fc83 100644 --- a/feed/pagination.py +++ b/feed/pagination.py @@ -25,7 +25,7 @@ def custom_paginate_queryset( if self.count == 0 or self.offset > self.count: return {"queryset_ready": [], "count": self.count} - queryset_ready = queryset[self.offset: self.offset + self.limit] + queryset_ready = queryset[self.offset : self.offset + self.limit] return { "queryset_ready": queryset_ready, "count": self.count, From 5abf8cb166029353ce42d3a2c59bd2992ec694f5 Mon Sep 17 00:00:00 2001 From: Alexey Kudelko Date: Wed, 21 Feb 2024 02:46:58 +0300 Subject: [PATCH 11/17] fix of fix of feed --- feed/helpers.py | 75 ++++++++++++++++++++++++++++++++++------------ feed/pagination.py | 4 +-- 2 files changed, 58 insertions(+), 21 deletions(-) diff --git a/feed/helpers.py b/feed/helpers.py index 21785665..090f222e 100644 --- a/feed/helpers.py +++ b/feed/helpers.py @@ -5,7 +5,11 @@ from rest_framework.views import APIView from feed import constants -from feed.constants import SupportedModel, SupportedQuerySet, LIMIT_PAGINATION_CONSTANT +from feed.constants import ( + SupportedModel, + SupportedQuerySet, + LIMIT_PAGINATION_CONSTANT +) from feed.pagination import FeedPagination from feed.serializers import FeedItemSerializer from news.models import News @@ -29,42 +33,74 @@ def paginate_serialize_feed( result = [] pages_count = 0 - offset = request.query_params.get("offset", None) + if len(model_data) == 0: + return [], 0 + + offset = request.query_params.get("offset", 0) request.query_params._mutable = True - if offset == "" or offset is None: - offset = 0 - elif offset is not None: + if isinstance(offset, str) and offset.isdigit(): offset = int(offset) - request.query_params["offset"] = offset + else: + offset = 0 + request.query_params["offset"] = offset - offset_numbers = randomize_offset(offset, len(model_data.keys())) + models_counts = { + model_name: model_data[model_name].count() for model_name in model_data.keys() + } + offset_numbers = offset_distribution(offset, models_counts) + + for model_name in model_data.keys(): + request.query_params["offset"] = offset_numbers[model_name] - for i in range(len(model_data.keys())): - request.query_params["offset"] = offset_numbers[i] paginated_part: dict = paginate_serialize_feed_queryset( - model_data, paginator, request, list(model_data.keys())[i], view + model_data, paginator, request, model_name, models_counts[model_name], view ) + result += paginated_part["paginated_data"] pages_count += paginated_part["page_count"] - shuffle(result) + limit = request.query_params.get("limit", LIMIT_PAGINATION_CONSTANT) - limit = int(request.query_params.get("limit", LIMIT_PAGINATION_CONSTANT)) if limit == "": limit = LIMIT_PAGINATION_CONSTANT + else: + limit = int(limit) + + shuffle(result) return result[:limit], pages_count -def randomize_offset(offset: int, quantity_models: int) -> list[int]: - full_division = offset // quantity_models - extra_items = offset % quantity_models +def offset_distribution(offset: int, models_counts: dict) -> dict: + common_key_list = list(models_counts.keys()) + quantity_of_models = len(list(models_counts.keys())) + + full_division = offset // quantity_of_models + extra_items = offset % quantity_of_models + + distributed_not_ready = {model_name: full_division for model_name in common_key_list} + distributed = dict( + sorted(distributed_not_ready.items(), key=lambda item: models_counts[item[0]]) + ) + + last_key = common_key_list[-1] + distributed[last_key] += extra_items - pagination_numbers = [full_division] * quantity_models - pagination_numbers[-1] += extra_items + new_keys_list = list(distributed.keys()) + for i, key in enumerate( + new_keys_list + ): # распределяем переполненные значения от маленьких моделей к большим + offset_value = distributed[key] + model_count = models_counts[key] + if offset_value > model_count: + diff = offset_value - model_count + distributed[key] = model_count + if i + 1 < len(new_keys_list): + next_key = new_keys_list[i + 1] + distributed[next_key] += diff - return pagination_numbers + return distributed def paginate_serialize_feed_queryset( @@ -72,10 +108,11 @@ def paginate_serialize_feed_queryset( paginator: FeedPagination, request: Request, model: SupportedModel, + count: int, view: APIView, ) -> dict: paginated_info = paginator.custom_paginate_queryset( - model_data[model], request, view=view + model_data[model], request, count, view=view ) paginated_data = paginated_info["queryset_ready"] num_pages = paginated_info["count"] diff --git a/feed/pagination.py b/feed/pagination.py index 9e88fc83..eea7ff91 100644 --- a/feed/pagination.py +++ b/feed/pagination.py @@ -10,13 +10,13 @@ class FeedPagination(pagination.LimitOffsetPagination): offset_query_param = "offset" def custom_paginate_queryset( - self, queryset: SupportedQuerySet, request: Request, view=None + self, queryset: SupportedQuerySet, request: Request, count: int, view=None ) -> dict: self.limit = self.get_limit(request) if self.limit is None: return None - self.count = self.get_count(queryset) + self.count = count self.offset = self.get_offset(request) self.request = request if self.count > self.limit and self.template is not None: From e2fe20fcf03e0bf0490c8f199af781067b6ab017 Mon Sep 17 00:00:00 2001 From: Alexey Kudelko Date: Wed, 21 Feb 2024 04:40:58 +0300 Subject: [PATCH 12/17] fix serializer --- rate_projects/serializers.py | 20 ++++++++++++++- rate_projects/views.py | 50 ++++++++++++++++++------------------ 2 files changed, 44 insertions(+), 26 deletions(-) diff --git a/rate_projects/serializers.py b/rate_projects/serializers.py index d51def34..e7b48649 100644 --- a/rate_projects/serializers.py +++ b/rate_projects/serializers.py @@ -1,9 +1,27 @@ from rest_framework import serializers -from rate_projects.models import ProjectScore + +from rate_projects.models import ProjectScore, Criteria +from rate_projects.validators import ProjectScoreValidate class ProjectScoreCreateSerializer(serializers.ModelSerializer): class Meta: model = ProjectScore fields = ["criteria_id", "user_id", "project_id", "value"] + readonly_field = ["criterion_field"] + + +def serialize_data_func(criteria_to_get: list, data: dict): + criteria = Criteria.objects.in_bulk(criteria_to_get) + + for criterion in data: + needed_criteria = criteria.get(int(criterion["criterion_id"])) + + ProjectScoreValidate( + criteria_type=needed_criteria.type, + value=criterion["value"], + criteria_min_value=needed_criteria.min_value, + criteria_max_value=needed_criteria.max_value, + ) + criterion["criteria_id"] = criterion.pop("criterion_id") diff --git a/rate_projects/views.py b/rate_projects/views.py index c968db07..c088b46b 100644 --- a/rate_projects/views.py +++ b/rate_projects/views.py @@ -4,7 +4,7 @@ from rest_framework.response import Response from rate_projects.models import ProjectScore -from rate_projects.serializers import ProjectScoreCreateSerializer +from rate_projects.serializers import ProjectScoreCreateSerializer, serialize_data_func from users.permissions import IsExpert User = get_user_model() @@ -15,27 +15,27 @@ class RateProject(generics.CreateAPIView): permission_classes = [IsExpert] def create(self, request, *args, **kwargs): - try: - data = self.request.data - - user = self.request.user.id - project_id = self.kwargs.get("project_id") - for criterion in data: - criterion["user_id"] = user - criterion["project_id"] = project_id - criterion["criteria_id"] = criterion.pop("criterion_id") - - serializer = self.get_serializer(data=data, many=True) - if serializer.is_valid(): - serializer.is_valid() - - ProjectScore.objects.bulk_create( - [ProjectScore(**score) for score in data] - ) - - return Response({"success": True}, status=status.HTTP_201_CREATED) - - else: - return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) - except Exception as e: - return Response({"error": str(e)}, status=status.HTTP_400_BAD_REQUEST) + # try: + data = self.request.data + + user = self.request.user.id + project_id = self.kwargs.get("project_id") + + criteria_to_get = [] + for criterion in data: + criterion["user_id"] = user + criterion["project_id"] = project_id + criteria_to_get.append(criterion["criterion_id"]) + + serializer = self.get_serializer(data=data, many=True) + + if serializer.is_valid(): + serialize_data_func(criteria_to_get, data) + ProjectScore.objects.bulk_create([ProjectScore(**score) for score in data]) + + return Response({"success": True}, status=status.HTTP_201_CREATED) + else: + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + + # except Exception as e: + # return Response({"error": str(e)}, status=status.HTTP_400_BAD_REQUEST) From 76a5c0f00e418f0638db37fa1d8448b45ef1f0e2 Mon Sep 17 00:00:00 2001 From: Alexey Kudelko Date: Wed, 21 Feb 2024 04:42:19 +0300 Subject: [PATCH 13/17] minor fix --- rate_projects/views.py | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/rate_projects/views.py b/rate_projects/views.py index c088b46b..d0514006 100644 --- a/rate_projects/views.py +++ b/rate_projects/views.py @@ -15,27 +15,29 @@ class RateProject(generics.CreateAPIView): permission_classes = [IsExpert] def create(self, request, *args, **kwargs): - # try: - data = self.request.data + try: + data = self.request.data - user = self.request.user.id - project_id = self.kwargs.get("project_id") + user = self.request.user.id + project_id = self.kwargs.get("project_id") - criteria_to_get = [] - for criterion in data: - criterion["user_id"] = user - criterion["project_id"] = project_id - criteria_to_get.append(criterion["criterion_id"]) + criteria_to_get = [] + for criterion in data: + criterion["user_id"] = user + criterion["project_id"] = project_id + criteria_to_get.append(criterion["criterion_id"]) - serializer = self.get_serializer(data=data, many=True) + serializer = self.get_serializer(data=data, many=True) - if serializer.is_valid(): - serialize_data_func(criteria_to_get, data) - ProjectScore.objects.bulk_create([ProjectScore(**score) for score in data]) + if serializer.is_valid(): + serialize_data_func(criteria_to_get, data) + ProjectScore.objects.bulk_create( + [ProjectScore(**score) for score in data] + ) - return Response({"success": True}, status=status.HTTP_201_CREATED) - else: - return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + return Response({"success": True}, status=status.HTTP_201_CREATED) + else: + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) - # except Exception as e: - # return Response({"error": str(e)}, status=status.HTTP_400_BAD_REQUEST) + except Exception as e: + return Response({"error": str(e)}, status=status.HTTP_400_BAD_REQUEST) From 6aa7dfc08a4e0ce488834fa064906795e1e231de Mon Sep 17 00:00:00 2001 From: Alexey Kudelko Date: Wed, 21 Feb 2024 11:32:55 +0300 Subject: [PATCH 14/17] fixed vacancy skills --- users/serializers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/users/serializers.py b/users/serializers.py index 32df068f..64e7b48e 100644 --- a/users/serializers.py +++ b/users/serializers.py @@ -32,7 +32,7 @@ def to_representation(self, data): if isinstance(data, list): return data return [ - i.replace("'", "") for i in data.strip("][").split(", ") if i.replace("'", "") + i.replace("'", "") for i in data.strip("][").split(",") if i.replace("'", "") ] @@ -365,7 +365,7 @@ class Meta: "last_name", "patronymic", "key_skills", - "speciality" + "speciality", ] From a6b0475f20190a6e0a0baf5bdee8da4cae5cd55c Mon Sep 17 00:00:00 2001 From: Alexey Kudelko Date: Wed, 21 Feb 2024 11:36:55 +0300 Subject: [PATCH 15/17] comment added --- feed/pagination.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feed/pagination.py b/feed/pagination.py index eea7ff91..36965a2f 100644 --- a/feed/pagination.py +++ b/feed/pagination.py @@ -25,7 +25,7 @@ def custom_paginate_queryset( if self.count == 0 or self.offset > self.count: return {"queryset_ready": [], "count": self.count} - queryset_ready = queryset[self.offset : self.offset + self.limit] + queryset_ready = queryset[self.offset : self.offset + self.limit] # TODO: поправить линтер в будущем return { "queryset_ready": queryset_ready, "count": self.count, From 6e46a8c5f5e0752860842c805ab1fd79836b3d8a Mon Sep 17 00:00:00 2001 From: Alexey Kudelko Date: Wed, 21 Feb 2024 11:41:00 +0300 Subject: [PATCH 16/17] comment added x2 --- feed/pagination.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feed/pagination.py b/feed/pagination.py index 36965a2f..4ab8eaf1 100644 --- a/feed/pagination.py +++ b/feed/pagination.py @@ -25,7 +25,7 @@ def custom_paginate_queryset( if self.count == 0 or self.offset > self.count: return {"queryset_ready": [], "count": self.count} - queryset_ready = queryset[self.offset : self.offset + self.limit] # TODO: поправить линтер в будущем + queryset_ready = queryset[self.offset : self.offset + self.limit] # noqa: E203 return { "queryset_ready": queryset_ready, "count": self.count, From 743c95061fe01dcc1c852074e5e1fdf7d3d92849 Mon Sep 17 00:00:00 2001 From: Alexey Kudelko Date: Wed, 21 Feb 2024 11:41:33 +0300 Subject: [PATCH 17/17] comment added x2 --- feed/pagination.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feed/pagination.py b/feed/pagination.py index 4ab8eaf1..f7ffc1a9 100644 --- a/feed/pagination.py +++ b/feed/pagination.py @@ -25,7 +25,7 @@ def custom_paginate_queryset( if self.count == 0 or self.offset > self.count: return {"queryset_ready": [], "count": self.count} - queryset_ready = queryset[self.offset : self.offset + self.limit] # noqa: E203 + queryset_ready = queryset[self.offset : self.offset + self.limit] # noqa: E203 return { "queryset_ready": queryset_ready, "count": self.count,