From 868defd44da75db5e1453319bcc9773d07d3b5cd Mon Sep 17 00:00:00 2001 From: Toksi86 Date: Fri, 4 Jul 2025 15:48:11 +0500 Subject: [PATCH 1/3] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=BB=D0=B2=D0=B5?= =?UTF-8?q?=D0=BD=D1=8B=20=D0=BD=D0=BE=D0=B2=D1=8B=D0=B5=20=D0=BF=D0=BE?= =?UTF-8?q?=D0=BB=D1=8F=20=D0=B2=20=D0=BC=D0=BE=D0=B4=D0=B5=D0=BB=D1=8C=20?= =?UTF-8?q?=D0=9F=D1=80=D0=BE=D0=B5=D0=BA=D1=82=20=D1=81=20=D0=B4=D0=B0?= =?UTF-8?q?=D0=BD=D0=BD=D1=8B=D0=BC=D0=B8=20=D0=B4=D0=BB=D1=8F=20=D0=9C?= =?UTF-8?q?=D0=BE=D1=81=D0=9F=D0=BE=D0=BB=D0=B8=D1=82=D0=B5=D1=85=D0=B0;?= =?UTF-8?q?=20=D0=94=D0=BE=D0=B1=D0=B0=D0=BB=D0=B5=D0=B2=D0=BD=D1=8B=20?= =?UTF-8?q?=D0=BD=D0=BE=D0=B2=D1=8B=D0=B5=20=D0=BF=D0=BE=D0=BB=D1=8F=20?= =?UTF-8?q?=D0=B2=20=D0=9F=D1=80=D0=BE=D0=B5=D0=BA=D1=82=D1=8B=20=D0=B4?= =?UTF-8?q?=D0=BB=D1=8F=20=D1=80=D0=B5=D0=B0=D0=B4=D0=BA=D1=82=D0=B8=D1=80?= =?UTF-8?q?=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D1=8F=20=D0=B2=20=D0=B0=D0=B4?= =?UTF-8?q?=D0=BC=D0=B8=D0=BD=D0=BA=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- projects/admin.py | 56 +++++++++++++ ...project_direction_project_goal_and_more.py | 80 +++++++++++++++++++ projects/models.py | 45 +++++++++++ 3 files changed, 181 insertions(+) create mode 100644 projects/migrations/0024_project_actuality_project_direction_project_goal_and_more.py diff --git a/projects/admin.py b/projects/admin.py index 62785951..ffc35da6 100644 --- a/projects/admin.py +++ b/projects/admin.py @@ -17,11 +17,67 @@ class ProjectAdmin(admin.ModelAdmin): "name", "draft", "is_company", + "track", + "direction", + "specialty", ) list_display_links = ( "id", "name", ) + search_fields = ( + "name", + "track", + "specialty", + ) + list_filter = ( + "draft", + "is_company", + "track", + "direction", + "specialty", + ) + + fieldsets = ( + ("Основная информация", { + "fields": ( + "name", + "description", + "leader", + "industry", + "region", + "step", + "draft", + "is_company", + ) + }), + ("Для проектов ПД МосПолитеха", { + "fields": ( + "track", + "direction", + "specialty", + "actuality", + "goal", + "problem", + ) + }), + ("Медиа и обложка", { + "fields": ( + "presentation_address", + "image_address", + "cover", + "cover_image_address", + ) + }), + ("Служебные поля", { + "fields": ( + "hidden_score", + "datetime_created", + "datetime_updated", + ) + }), + ) + readonly_fields = ("datetime_created", "datetime_updated") @admin.register(ProjectNews) diff --git a/projects/migrations/0024_project_actuality_project_direction_project_goal_and_more.py b/projects/migrations/0024_project_actuality_project_direction_project_goal_and_more.py new file mode 100644 index 00000000..7c028914 --- /dev/null +++ b/projects/migrations/0024_project_actuality_project_direction_project_goal_and_more.py @@ -0,0 +1,80 @@ +# Generated by Django 4.2.11 on 2025-07-03 08:53 + +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("projects", "0023_project_cover_image_address"), + ] + + operations = [ + migrations.AddField( + model_name="project", + name="actuality", + field=models.TextField( + blank=True, + help_text="Почему проект важен (до 1000\u202fсимв.)", + null=True, + validators=[django.core.validators.MaxLengthValidator(1000)], + verbose_name="Актуальность", + ), + ), + migrations.AddField( + model_name="project", + name="direction", + field=models.CharField( + blank=True, + help_text="Более общее направление деятельности проекта", + max_length=256, + null=True, + verbose_name="Направление", + ), + ), + migrations.AddField( + model_name="project", + name="goal", + field=models.CharField( + blank=True, + help_text="Главная цель проекта (до 500\u202fсимв.)", + max_length=500, + null=True, + verbose_name="Цель", + ), + ), + migrations.AddField( + model_name="project", + name="problem", + field=models.TextField( + blank=True, + help_text="Какую проблему решает проект (до 1000\u202fсимв.)", + null=True, + validators=[django.core.validators.MaxLengthValidator(1000)], + verbose_name="Проблема", + ), + ), + migrations.AddField( + model_name="project", + name="specialty", + field=models.CharField( + blank=True, + help_text="Специализация проекта", + max_length=256, + null=True, + verbose_name="Специальность", + ), + ), + migrations.AddField( + model_name="project", + name="track", + field=models.CharField( + blank=True, + help_text="Направление/курс, в рамках которого реализуется проект", + max_length=256, + null=True, + verbose_name="Трек", + ), + ), + ] diff --git a/projects/models.py b/projects/models.py index b38a939e..7e1f9973 100644 --- a/projects/models.py +++ b/projects/models.py @@ -2,9 +2,11 @@ from django.contrib.auth import get_user_model from django.contrib.contenttypes.fields import GenericRelation +from django.core.validators import MaxLengthValidator from django.db import models from django.db.models import UniqueConstraint + from core.models import Like, View from files.models import UserFile from industries.models import Industry @@ -88,6 +90,49 @@ class Project(models.Model): step = models.PositiveSmallIntegerField(choices=VERBOSE_STEPS, null=True, blank=True) hidden_score = models.PositiveSmallIntegerField(default=100) + track = models.CharField( + max_length=256, + blank=True, + null=True, + verbose_name="Трек", + help_text="Направление/курс, в рамках которого реализуется проект", + ) + direction = models.CharField( + max_length=256, + blank=True, + null=True, + verbose_name="Направление", + help_text="Более общее направление деятельности проекта", + ) + specialty = models.CharField( + max_length=256, + blank=True, + null=True, + verbose_name="Специальность", + help_text="Специализация проекта", + ) + actuality = models.TextField( + blank=True, + null=True, + validators=[MaxLengthValidator(1000)], + verbose_name="Актуальность", + help_text="Почему проект важен (до 1000 симв.)", + ) + goal = models.CharField( + max_length=500, + blank=True, + null=True, + verbose_name="Цель", + help_text="Главная цель проекта (до 500 симв.)", + ) + problem = models.TextField( + blank=True, + null=True, + validators=[MaxLengthValidator(1000)], + verbose_name="Проблема", + help_text="Какую проблему решает проект (до 1000 симв.)", + ) + industry = models.ForeignKey( Industry, on_delete=models.SET_NULL, From 8e85f18718350e8f117ea40cf0b1ba6c58c4ac58 Mon Sep 17 00:00:00 2001 From: Toksi86 Date: Fri, 4 Jul 2025 15:48:50 +0500 Subject: [PATCH 2/3] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B5=D1=80=D0=B0=D0=B1?= =?UTF-8?q?=D0=BE=D1=82=D0=B0=D0=BD=20ProjectDetailSerializer=20=D0=B2=20?= =?UTF-8?q?=D1=81=D0=BE=D0=BE=D1=82=D0=B2=D0=B5=D1=82=D1=81=D1=82=D0=B2?= =?UTF-8?q?=D0=B8=D0=B8=20=D1=81=20=D0=BD=D0=BE=D0=B2=D1=8B=D0=BC=D0=B8=20?= =?UTF-8?q?=D0=BF=D0=BE=D0=BB=D1=8F=D0=BC=D0=B8=20=D0=B2=20=D0=BC=D0=BE?= =?UTF-8?q?=D0=B4=D0=B5=D0=BB=D0=B8=20Project?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- projects/serializers.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/projects/serializers.py b/projects/serializers.py index a68cadb4..098dcad8 100644 --- a/projects/serializers.py +++ b/projects/serializers.py @@ -130,6 +130,12 @@ class Meta: "cover", "cover_image_address", "partner_programs_tags", + "track", + "direction", + "specialty", + "actuality", + "goal", + "problem", ] read_only_fields = [ "leader", From 99c392e8906d5ac247a5ba9ff26e81b24ba0edde Mon Sep 17 00:00:00 2001 From: Toksi86 Date: Fri, 4 Jul 2025 15:52:32 +0500 Subject: [PATCH 3/3] =?UTF-8?q?=D0=9A=D0=BE=D0=B4=20=D0=BF=D1=80=D0=B8?= =?UTF-8?q?=D0=B2=D0=B4=D1=91=D0=BD=20=D0=B2=20=D1=81=D0=BE=D0=BE=D1=82?= =?UTF-8?q?=D0=B2=D0=B5=D1=82=D1=81=D1=82=D0=B2=D0=B8=D0=B5=20=D1=81=20?= =?UTF-8?q?=D0=BF=D1=80=D0=B0=D0=B2=D0=B8=D0=BB=D0=B0=D0=BC=D0=B8=20=D0=BE?= =?UTF-8?q?=D1=84=D0=BE=D1=80=D0=BC=D0=BB=D0=B5=D0=BD=D0=B8=D1=8F;=20?= =?UTF-8?q?=D0=9E=D1=82=D1=81=D0=BE=D1=80=D1=82=D0=B8=D1=80=D0=BE=D0=B2?= =?UTF-8?q?=D0=B0=D0=BD=D1=8B=20=D0=B8=D0=BC=D0=BF=D0=BE=D1=80=D1=82=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- projects/admin.py | 90 +++++++++++++++++++++++------------------ projects/models.py | 12 ++++-- projects/serializers.py | 8 ++-- 3 files changed, 63 insertions(+), 47 deletions(-) diff --git a/projects/admin.py b/projects/admin.py index ffc35da6..70f42356 100644 --- a/projects/admin.py +++ b/projects/admin.py @@ -1,10 +1,10 @@ from django.contrib import admin from projects.models import ( - DefaultProjectCover, - Project, Achievement, Collaborator, + DefaultProjectCover, + Project, ProjectLink, ProjectNews, ) @@ -39,43 +39,55 @@ class ProjectAdmin(admin.ModelAdmin): ) fieldsets = ( - ("Основная информация", { - "fields": ( - "name", - "description", - "leader", - "industry", - "region", - "step", - "draft", - "is_company", - ) - }), - ("Для проектов ПД МосПолитеха", { - "fields": ( - "track", - "direction", - "specialty", - "actuality", - "goal", - "problem", - ) - }), - ("Медиа и обложка", { - "fields": ( - "presentation_address", - "image_address", - "cover", - "cover_image_address", - ) - }), - ("Служебные поля", { - "fields": ( - "hidden_score", - "datetime_created", - "datetime_updated", - ) - }), + ( + "Основная информация", + { + "fields": ( + "name", + "description", + "leader", + "industry", + "region", + "step", + "draft", + "is_company", + ) + }, + ), + ( + "Для проектов ПД МосПолитеха", + { + "fields": ( + "track", + "direction", + "specialty", + "actuality", + "goal", + "problem", + ) + }, + ), + ( + "Медиа и обложка", + { + "fields": ( + "presentation_address", + "image_address", + "cover", + "cover_image_address", + ) + }, + ), + ( + "Служебные поля", + { + "fields": ( + "hidden_score", + "datetime_created", + "datetime_updated", + ) + }, + ), ) readonly_fields = ("datetime_created", "datetime_updated") diff --git a/projects/models.py b/projects/models.py index 7e1f9973..d66cefda 100644 --- a/projects/models.py +++ b/projects/models.py @@ -6,11 +6,9 @@ from django.db import models from django.db.models import UniqueConstraint - from core.models import Like, View from files.models import UserFile from industries.models import Industry - from projects.constants import VERBOSE_STEPS from projects.managers import AchievementManager, CollaboratorManager, ProjectManager from users.models import CustomUser @@ -55,7 +53,11 @@ def get_random_file(cls): @classmethod def get_random_file_link(cls): # FIXME: this is not efficient, but for ~10 default covers it should be ok - return cls.objects.order_by("?").first().image.link if cls.objects.order_by("?").first().image else None + return ( + cls.objects.order_by("?").first().image.link + if cls.objects.order_by("?").first().image + else None + ) class Meta: verbose_name = "Обложка проекта" @@ -87,7 +89,9 @@ class Project(models.Model): name = models.CharField(max_length=256, null=True, blank=True) description = models.TextField(null=True, blank=True) region = models.CharField(max_length=256, null=True, blank=True) - step = models.PositiveSmallIntegerField(choices=VERBOSE_STEPS, null=True, blank=True) + step = models.PositiveSmallIntegerField( + choices=VERBOSE_STEPS, null=True, blank=True + ) hidden_score = models.PositiveSmallIntegerField(default=100) track = models.CharField( diff --git a/projects/serializers.py b/projects/serializers.py index 098dcad8..95757559 100644 --- a/projects/serializers.py +++ b/projects/serializers.py @@ -1,12 +1,13 @@ from django.contrib.auth import get_user_model -from rest_framework import serializers from django.core.cache import cache +from rest_framework import serializers + from core.serializers import SkillToObjectSerializer -from core.services import get_views_count, get_likes_count, is_fan +from core.services import get_likes_count, get_views_count, is_fan from core.utils import get_user_online_cache_key from files.serializers import UserFileSerializer from industries.models import Industry -from projects.models import Project, Achievement, Collaborator, ProjectNews +from projects.models import Achievement, Collaborator, Project, ProjectNews from projects.validators import validate_project from vacancy.serializers import ProjectVacancyListSerializer @@ -64,7 +65,6 @@ class Meta: class ProjectDetailSerializer(serializers.ModelSerializer): - achievements = AchievementListSerializer(many=True, read_only=True) cover = UserFileSerializer(required=False) collaborators = CollaboratorSerializer(