Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
145 changes: 111 additions & 34 deletions partner_programs/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import tablib
from django import forms
from django.contrib import admin
from django.db.models import QuerySet
from django.db.models import Prefetch, QuerySet
from django.http import HttpRequest, HttpResponse
from django.urls import path
from django.utils import timezone
Expand All @@ -19,16 +19,15 @@
PartnerProgramProject,
PartnerProgramUserProfile,
)
from partner_programs.services import ProjectScoreDataPreparer
from project_rates.models import Criteria, ProjectScore
from projects.models import Project


class PartnerProgramMaterialInline(admin.StackedInline):
model = PartnerProgramMaterial
extra = 1
fields = ("title", "url", "file")
readonly_fields = ("datetime_created", "datetime_updated")
autocomplete_fields = ("file",)


class PartnerProgramFieldInline(admin.TabularInline):
Expand Down Expand Up @@ -66,7 +65,7 @@ class Meta:
)
list_filter = ("city",)

filter_horizontal = ("managers",)
autocomplete_fields = ("managers",)
date_hierarchy = "datetime_started"
readonly_fields = ("datetime_created", "datetime_updated")
fieldsets = (
Expand Down Expand Up @@ -102,7 +101,9 @@ class Meta:
)

def get_queryset(self, request: HttpRequest) -> QuerySet[PartnerProgram]:
qs = super().get_queryset(request)
qs = super().get_queryset(request).prefetch_related(
"managers", "materials", "fields"
)
if "Руководитель программы" in request.user.groups.all().values_list(
"name", flat=True
):
Expand Down Expand Up @@ -247,46 +248,122 @@ def get_export_rates_view(self, request, object_id):

def _get_prepared_rates_data_for_export(self, program_id: int) -> list[dict]:
"""
Prepares info (list if dicts) for export about prjects_rates by experts.
Columns example:
ФИО|Email|Регион_РФ|Учебное_заведение|Название_учебного_заведения|Класс_курс|Фамилия эксперта|**criteria
Готовит данные для выгрузки оценок проектов.
Порядок колонок: название проекта → фамилия эксперта → доп. поля программы →
критерии → комментарий.
Если у проекта несколько экспертов, на каждый проект-эксперт создаётся отдельная строка.
"""
criterias = Criteria.objects.filter(
partner_program__id=program_id
).select_related("partner_program")
criterias = list(
Criteria.objects.filter(partner_program__id=program_id)
.select_related("partner_program")
.order_by("id")
)
if not criterias:
return []

comment_criteria = next(
(criteria for criteria in criterias if criteria.name == "Комментарий"),
None,
)
criterias_without_comment = [
criteria for criteria in criterias if criteria != comment_criteria
]

program_fields = list(
PartnerProgramField.objects.filter(partner_program_id=program_id).order_by(
"id"
)
)

scores = (
ProjectScore.objects.filter(criteria__in=criterias)
.select_related("user", "criteria", "project")
.order_by("project", "criteria")
.order_by("project_id", "criteria_id", "id")
)
user_programm_profiles = PartnerProgramUserProfile.objects.filter(
partner_program__id=program_id
).select_related("user")
projects = (
Project.objects.filter(scores__in=scores)
.select_related("leader")
.distinct()
)

# To reduce the number of DB requests.
user_profiles_dict: dict[int, PartnerProgramUserProfile] = {
profile.project_id: profile for profile in user_programm_profiles
}
scores_dict: dict[int, list[ProjectScore]] = {}
for score in scores:
scores_dict.setdefault(score.project_id, []).append(score)

if not scores_dict:
empty_row: dict[str, str] = {
"Название проекта": "",
"Фамилия эксперта": "",
}
for field in program_fields:
empty_row[field.label] = ""
for criteria in criterias_without_comment:
empty_row[criteria.name] = ""
if comment_criteria:
empty_row["Комментарий"] = ""
return [empty_row]

project_ids = list(scores_dict.keys())

field_values_prefetch = Prefetch(
"field_values",
queryset=PartnerProgramFieldValue.objects.select_related("field").filter(
program_project__partner_program_id=program_id,
program_project__project_id__in=project_ids,
),
to_attr="_prefetched_field_values",
)
program_projects = (
PartnerProgramProject.objects.filter(
partner_program_id=program_id, project_id__in=project_ids
)
.select_related("project")
.prefetch_related(field_values_prefetch)
)
program_project_by_project_id: dict[int, PartnerProgramProject] = {
link.project_id: link for link in program_projects
}

prepared_projects_rates_data: list[dict] = []
for project in projects:
project_data_preparer = ProjectScoreDataPreparer(
user_profiles_dict, scores_dict, project.id, program_id
for project_id, project_scores in scores_dict.items():
project_link = program_project_by_project_id.get(project_id)
project = (
project_link.project
if project_link
else (project_scores[0].project if project_scores else None)
)
full_project_rates_data: dict = {
**project_data_preparer.get_project_user_info(),
**project_data_preparer.get_project_expert_info(),
**project_data_preparer.get_project_scores_info(),
}
prepared_projects_rates_data.append(full_project_rates_data)

field_values_map: dict[int, str] = {}
field_values = (
getattr(project_link, "_prefetched_field_values", None)
if project_link
else None
)
if field_values:
for field_value in field_values:
field_values_map[field_value.field_id] = field_value.get_value()

scores_by_expert: dict[int, list[ProjectScore]] = {}
for score in project_scores:
scores_by_expert.setdefault(score.user_id, []).append(score)

for _, expert_scores in scores_by_expert.items():
row_data: dict[str, str] = {}
row_data["Название проекта"] = (
getattr(project, "name", "") if project else ""
)
row_data["Фамилия эксперта"] = (
expert_scores[0].user.last_name if expert_scores else ""
)

for field in program_fields:
row_data[field.label] = field_values_map.get(field.id, "")

scores_map: dict[int, str] = {
score.criteria_id: score.value for score in expert_scores
}

for criteria in criterias_without_comment:
row_data[criteria.name] = scores_map.get(criteria.id, "")

if comment_criteria:
row_data["Комментарий"] = scores_map.get(comment_criteria.id, "")

prepared_projects_rates_data.append(row_data)

return prepared_projects_rates_data

Expand Down