1- import tablib
21import re
32import urllib .parse
3+
4+ import tablib
45from django .contrib import admin
56from django .db .models import QuerySet
6- from django .http import HttpResponse , HttpRequest
7+ from django .http import HttpRequest , HttpResponse
78from django .urls import path
89from django .utils import timezone
910
10- from mailing .views import MailingTemplateRender
1111from core .utils import XlsxFileToExport
12- from partner_programs .models import PartnerProgram , PartnerProgramUserProfile
12+ from mailing .views import MailingTemplateRender
13+ from partner_programs .models import (
14+ PartnerProgram ,
15+ PartnerProgramField ,
16+ PartnerProgramFieldValue ,
17+ PartnerProgramMaterial ,
18+ PartnerProgramProject ,
19+ PartnerProgramUserProfile ,
20+ )
21+ from partner_programs .services import ProjectScoreDataPreparer
1322from project_rates .models import Criteria , ProjectScore
1423from projects .models import Project
15- from partner_programs .services import ProjectScoreDataPreparer
24+
25+
26+ class PartnerProgramMaterialInline (admin .StackedInline ):
27+ model = PartnerProgramMaterial
28+ extra = 1
29+ fields = ("title" , "url" , "file" )
30+ readonly_fields = ("datetime_created" , "datetime_updated" )
31+
32+
33+ class PartnerProgramFieldInline (admin .TabularInline ):
34+ model = PartnerProgramField
35+ extra = 0
1636
1737
1838@admin .register (PartnerProgram )
1939class PartnerProgramAdmin (admin .ModelAdmin ):
40+ inlines = [PartnerProgramMaterialInline , PartnerProgramFieldInline ]
2041 list_display = ("id" , "name" , "tag" , "city" , "datetime_created" )
2142 list_display_links = (
2243 "id" ,
@@ -32,7 +53,7 @@ class PartnerProgramAdmin(admin.ModelAdmin):
3253 )
3354 list_filter = ("city" ,)
3455
35- filter_horizontal = ("users" ,)
56+ filter_horizontal = ("users" , "managers" )
3657 date_hierarchy = "datetime_started"
3758
3859 def get_queryset (self , request : HttpRequest ) -> QuerySet [PartnerProgram ]:
@@ -54,7 +75,9 @@ def change_view(self, request, object_id, form_url="", extra_context=None):
5475 "partner_programs/admin/program_manager_change_form.html"
5576 )
5677 else :
57- self .change_form_template = "partner_programs/admin/programs_change_form.html"
78+ self .change_form_template = (
79+ "partner_programs/admin/programs_change_form.html"
80+ )
5881
5982 return super ().change_view (request , object_id , form_url , extra_context )
6083
@@ -145,7 +168,7 @@ def get_export_file(self, partner_program: PartnerProgram):
145168
146169 binary_data = response_data .export ("xlsx" )
147170 file_name = (
148- f' { partner_program .name } { timezone .now ().strftime (" %d-%m-%Y %H:%M:%S" ) } '
171+ f" { partner_program .name } { timezone .now ().strftime (' %d-%m-%Y %H:%M:%S' ) } "
149172 )
150173 response = HttpResponse (
151174 content_type = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" ,
@@ -155,22 +178,26 @@ def get_export_file(self, partner_program: PartnerProgram):
155178 return response
156179
157180 def get_export_rates_view (self , request , object_id ):
158- rates_data_to_write : list [dict ] = self ._get_prepared_rates_data_for_export (object_id )
181+ rates_data_to_write : list [dict ] = self ._get_prepared_rates_data_for_export (
182+ object_id
183+ )
159184
160185 xlsx_file_writer = XlsxFileToExport ()
161186 xlsx_file_writer .write_data_to_xlsx (rates_data_to_write )
162187 binary_data_to_export : bytes = xlsx_file_writer .get_binary_data_from_self_file ()
163188 xlsx_file_writer .delete_self_xlsx_file_from_local_machine ()
164189
165190 encoded_file_name : str = urllib .parse .quote (
166- f' { PartnerProgram .objects .get (pk = object_id ).name } _оценки { timezone .now ().strftime (" %d-%m-%Y %H:%M:%S" ) } '
191+ f" { PartnerProgram .objects .get (pk = object_id ).name } _оценки { timezone .now ().strftime (' %d-%m-%Y %H:%M:%S' ) } "
167192 f".xlsx"
168193 )
169194 response = HttpResponse (
170195 binary_data_to_export ,
171196 content_type = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" ,
172197 )
173- response ["Content-Disposition" ] = f'attachment; filename*=UTF-8\' \' { encoded_file_name } '
198+ response ["Content-Disposition" ] = (
199+ f"attachment; filename*=UTF-8''{ encoded_file_name } "
200+ )
174201 return response
175202
176203 def _get_prepared_rates_data_for_export (self , program_id : int ) -> list [dict ]:
@@ -179,19 +206,22 @@ def _get_prepared_rates_data_for_export(self, program_id: int) -> list[dict]:
179206 Columns example:
180207 ФИО|Email|Регион_РФ|Учебное_заведение|Название_учебного_заведения|Класс_курс|Фамилия эксперта|**criteria
181208 """
182- criterias = Criteria .objects .filter (partner_program__id = program_id ).select_related ("partner_program" )
209+ criterias = Criteria .objects .filter (
210+ partner_program__id = program_id
211+ ).select_related ("partner_program" )
183212 scores = (
184- ProjectScore .objects
185- .filter (criteria__in = criterias )
213+ ProjectScore .objects .filter (criteria__in = criterias )
186214 .select_related ("user" , "criteria" , "project" )
187215 .order_by ("project" , "criteria" )
188216 )
189- user_programm_profiles = (
190- PartnerProgramUserProfile .objects
191- .filter (partner_program__id = program_id )
192- .select_related ("user" )
217+ user_programm_profiles = PartnerProgramUserProfile .objects .filter (
218+ partner_program__id = program_id
219+ ).select_related ("user" )
220+ projects = (
221+ Project .objects .filter (scores__in = scores )
222+ .select_related ("leader" )
223+ .distinct ()
193224 )
194- projects = Project .objects .filter (scores__in = scores ).select_related ("leader" ).distinct ()
195225
196226 # To reduce the number of DB requests.
197227 user_profiles_dict : dict [int , PartnerProgramUserProfile ] = {
@@ -203,7 +233,9 @@ def _get_prepared_rates_data_for_export(self, program_id: int) -> list[dict]:
203233
204234 prepared_projects_rates_data : list [dict ] = []
205235 for project in projects :
206- project_data_preparer = ProjectScoreDataPreparer (user_profiles_dict , scores_dict , project .id , program_id )
236+ project_data_preparer = ProjectScoreDataPreparer (
237+ user_profiles_dict , scores_dict , project .id , program_id
238+ )
207239 full_project_rates_data : dict = {
208240 ** project_data_preparer .get_project_user_info (),
209241 ** project_data_preparer .get_project_expert_info (),
@@ -242,3 +274,66 @@ def get_form(self, request, obj=None, **kwargs):
242274 form = super ().get_form (request , obj , ** kwargs )
243275 form .base_fields ["project" ].required = False
244276 return form
277+
278+
279+ @admin .register (PartnerProgramMaterial )
280+ class PartnerProgramMaterialAdmin (admin .ModelAdmin ):
281+ list_display = ("title" , "program" , "short_url" , "has_file" , "datetime_created" )
282+ list_filter = ("program" ,)
283+ search_fields = ("title" , "program__name" )
284+
285+ readonly_fields = ("datetime_created" , "datetime_updated" )
286+
287+ def short_url (self , obj ):
288+ return obj .url [:60 ] if obj .url else "—"
289+
290+ short_url .short_description = "Ссылка"
291+
292+ def has_file (self , obj ):
293+ return bool (obj .file )
294+
295+ has_file .boolean = True
296+ has_file .short_description = "Файл"
297+
298+
299+ class PartnerProgramFieldValueInline (admin .TabularInline ):
300+ model = PartnerProgramFieldValue
301+ extra = 0
302+ autocomplete_fields = ("field" ,)
303+ readonly_fields = ("get_display_value" ,)
304+
305+ def get_display_value (self , obj ):
306+ return obj .value_text or "-"
307+
308+ get_display_value .short_description = "Значение"
309+
310+
311+ @admin .register (PartnerProgramProject )
312+ class PartnerProgramProjectAdmin (admin .ModelAdmin ):
313+ list_display = (
314+ "id" ,
315+ "project" ,
316+ "partner_program" ,
317+ "datetime_created" ,
318+ "submitted" ,
319+ "datetime_submitted" ,
320+ )
321+ list_filter = ("partner_program" ,)
322+ search_fields = ("project__name" , "partner_program__name" )
323+ inlines = [PartnerProgramFieldValueInline ]
324+ autocomplete_fields = ("project" , "partner_program" )
325+
326+
327+ @admin .register (PartnerProgramField )
328+ class PartnerProgramFieldAdmin (admin .ModelAdmin ):
329+ list_display = (
330+ "id" ,
331+ "partner_program" ,
332+ "name" ,
333+ "label" ,
334+ "field_type" ,
335+ "is_required" ,
336+ "show_filter" ,
337+ )
338+ list_filter = ("partner_program" ,)
339+ search_fields = ("name" , "label" , "help_text" )
0 commit comments