Skip to content

Commit 2cf2708

Browse files
authored
Merge pull request #520 from PROCOLLAB-github/feature/user-mospolytech-data
Пользователю добавлены новые поля в соответствии с требованиями МосПолитеха
2 parents 70f3d31 + 614db3d commit 2cf2708

4 files changed

Lines changed: 91 additions & 45 deletions

File tree

users/admin.py

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,10 @@ class CustomUserAdmin(admin.ModelAdmin):
124124
"Важные даты",
125125
{"fields": ("last_login", "date_joined")},
126126
),
127+
(
128+
"Студенты мосполитеха",
129+
{"fields": ("is_mospolytech_student", "study_group")},
130+
),
127131
)
128132

129133
list_display = (
@@ -296,10 +300,7 @@ def get_export_users_emails(self, users):
296300
users = (
297301
CustomUser.objects.all()
298302
.select_related("v2_speciality")
299-
.filter(
300-
birthday__lte=date_limit_18,
301-
birthday__gte=date_limit_22
302-
)
303+
.filter(birthday__lte=date_limit_18, birthday__gte=date_limit_22)
303304
)
304305
# little_mans = users.filter(birthday__lte=date_limit_18)
305306
# big_mans = users.exclude(id__in=little_mans.values_list("id", flat=True))
@@ -312,13 +313,9 @@ def get_export_users_emails(self, users):
312313
response_data.append(
313314
[
314315
user.first_name + " " + user.last_name,
315-
(today.year - user.birthday.year)
316-
if user.birthday.year
317-
else None,
316+
(today.year - user.birthday.year) if user.birthday.year else None,
318317
user.city,
319-
user.v2_speciality
320-
if user.v2_speciality
321-
else user.speciality,
318+
user.v2_speciality if user.v2_speciality else user.speciality,
322319
user.email,
323320
]
324321
)
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Generated by Django 4.2.11 on 2025-07-02 08:47
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
("users", "0052_remove_customuser_organization"),
10+
]
11+
12+
operations = [
13+
migrations.AddField(
14+
model_name="customuser",
15+
name="is_mospolytech_student",
16+
field=models.BooleanField(
17+
default=False,
18+
help_text="Флаг, указывающий, является ли пользователь студентом МосПолитеха",
19+
verbose_name="Студент Московского Политеха",
20+
),
21+
),
22+
migrations.AddField(
23+
model_name="customuser",
24+
name="study_group",
25+
field=models.CharField(
26+
blank=True,
27+
help_text="Краткое обозначение учебной группы (до 10 символов)",
28+
max_length=10,
29+
null=True,
30+
verbose_name="Учебная группа",
31+
),
32+
),
33+
]

users/models.py

Lines changed: 40 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,24 @@
1+
from django.contrib.auth.models import AbstractUser
2+
from django.contrib.contenttypes.fields import GenericRelation
3+
from django.core.exceptions import ValidationError
14
from django.db import models
25
from django.db.models import QuerySet
36
from django.utils import timezone
4-
from django.core.exceptions import ValidationError
5-
from django.contrib.auth.models import AbstractUser
6-
from django.contrib.contenttypes.fields import GenericRelation
7-
87
from django_stubs_ext.db.models import TypedModelMeta
98

109
from users import constants
1110
from users.managers import (
1211
CustomUserManager,
13-
UserAchievementManager,
1412
LikesOnProjectManager,
13+
UserAchievementManager,
1514
)
15+
from users.utils import normalize_user_phone
1616
from users.validators import (
1717
user_birthday_validator,
18-
user_name_validator,
1918
user_experience_years_range_validator,
19+
user_name_validator,
2020
user_phone_number_validation,
2121
)
22-
from users.utils import normalize_user_phone
2322

2423

2524
def get_default_user_type():
@@ -102,7 +101,7 @@ class CustomUser(AbstractUser):
102101
null=True,
103102
blank=True,
104103
verbose_name="Номер телефона",
105-
help_text="Пример: +7 XXX XX-XX-XX | +7XXXXXXXXX | +7 (XXX) XX-XX-XX"
104+
help_text="Пример: +7 XXX XX-XX-XX | +7XXXXXXXXX | +7 (XXX) XX-XX-XX",
106105
)
107106
v2_speciality = models.ForeignKey(
108107
on_delete=models.SET_NULL,
@@ -138,7 +137,19 @@ class CustomUser(AbstractUser):
138137
blank=True,
139138
default=False,
140139
verbose_name="Временная мера для переноса навыка",
141-
help_text="Yes если оба поля `v2_speciality` и `skills` есть, No если поля не перенеслись"
140+
help_text="Yes если оба поля `v2_speciality` и `skills` есть, No если поля не перенеслись",
141+
)
142+
is_mospolytech_student = models.BooleanField(
143+
default=False,
144+
verbose_name="Студент Московского Политеха",
145+
help_text="Флаг, указывающий, является ли пользователь студентом МосПолитеха",
146+
)
147+
study_group = models.CharField(
148+
max_length=10,
149+
null=True,
150+
blank=True,
151+
verbose_name="Учебная группа",
152+
help_text="Краткое обозначение учебной группы (до 10 символов)",
142153
)
143154

144155
USERNAME_FIELD = "email"
@@ -181,7 +192,9 @@ def calculate_ordering_score(self) -> int:
181192
def get_project_chats(self) -> QuerySet:
182193
from chats.models import ProjectChat
183194

184-
user_project_ids = self.collaborations.all().values_list("project_id", flat=True)
195+
user_project_ids = self.collaborations.all().values_list(
196+
"project_id", flat=True
197+
)
185198
return ProjectChat.objects.filter(project__in=user_project_ids)
186199

187200
def get_full_name(self) -> str:
@@ -192,7 +205,11 @@ def get_user_age(self) -> int:
192205
return None
193206
today = timezone.now()
194207
birthday = self.birthday
195-
return today.year - birthday.year - ((today.month, today.day) < (birthday.month, birthday.day))
208+
return (
209+
today.year
210+
- birthday.year
211+
- ((today.month, today.day) < (birthday.month, birthday.day))
212+
)
196213

197214
def __str__(self) -> str:
198215
return f"User<{self.id}> - {self.first_name} {self.last_name}"
@@ -442,6 +459,7 @@ class Meta(TypedModelMeta):
442459

443460
class AbstractUserExperience(models.Model):
444461
"""Abstact help model for user work|education experience."""
462+
445463
organization_name = models.CharField(
446464
max_length=255,
447465
verbose_name="Наименование организации",
@@ -469,9 +487,7 @@ class Meta:
469487
abstract = True
470488

471489
def __str__(self) -> str:
472-
return (
473-
f"id: {self.id} - ({self.user.first_name} {self.user.last_name} user_id: {self.user.id})"
474-
)
490+
return f"id: {self.id} - ({self.user.first_name} {self.user.last_name} user_id: {self.user.id})"
475491

476492
def clean(self) -> None:
477493
"""Validate both years `entry` <`completion`"""
@@ -541,6 +557,7 @@ class UserWorkExperience(AbstractUserExperience):
541557
entry_year: PositiveSmallIntegerField Year of admission.
542558
completion_year: PositiveSmallIntegerField Year of dismissal.
543559
"""
560+
544561
user = models.ForeignKey(
545562
to=CustomUser,
546563
on_delete=models.CASCADE,
@@ -570,6 +587,7 @@ class UserLanguages(models.Model):
570587
language: CharField(choise) languages.
571588
language_level: CharField(choise) language level.
572589
"""
590+
573591
user = models.ForeignKey(
574592
to=CustomUser,
575593
on_delete=models.CASCADE,
@@ -604,17 +622,17 @@ def clean(self) -> None:
604622
"""
605623
super().clean()
606624
user_languages = self.user.user_languages.values_list("language", flat=True)
607-
if (self.language not in user_languages) and len(user_languages) == constants.USER_MAX_LANGUAGES_COUNT:
625+
if (self.language not in user_languages) and len(
626+
user_languages
627+
) == constants.USER_MAX_LANGUAGES_COUNT:
608628
raise ValidationError(constants.COUNT_LANGUAGES_VALIDATION_MESSAGE)
609629

610630
def save(self, *args, **kwargs):
611631
self.clean()
612632
super().save(*args, **kwargs)
613633

614634
def __str__(self) -> str:
615-
return (
616-
f"id: {self.id} - ({self.user.first_name} {self.user.last_name} user_id: {self.user.id})"
617-
)
635+
return f"id: {self.id} - ({self.user.first_name} {self.user.last_name} user_id: {self.user.id})"
618636

619637

620638
class UserSkillConfirmation(models.Model):
@@ -626,23 +644,20 @@ class UserSkillConfirmation(models.Model):
626644
confirmed_by: FK CustomUser.
627645
confirmed_at: DateTimeField.
628646
"""
647+
629648
skill_to_object = models.ForeignKey(
630-
"core.SkillToObject",
631-
on_delete=models.CASCADE,
632-
related_name="confirmations"
649+
"core.SkillToObject", on_delete=models.CASCADE, related_name="confirmations"
633650
)
634651
confirmed_by = models.ForeignKey(
635-
CustomUser,
636-
on_delete=models.CASCADE,
637-
related_name="skill_confirmations"
652+
CustomUser, on_delete=models.CASCADE, related_name="skill_confirmations"
638653
)
639654
confirmed_at = models.DateTimeField(auto_now_add=True)
640655

641656
class Meta:
642657
constraints = [
643658
models.UniqueConstraint(
644659
fields=["skill_to_object", "confirmed_by"],
645-
name="unique_skill_confirmed_by"
660+
name="unique_skill_confirmed_by",
646661
)
647662
]
648663
verbose_name = "Подтверждение навыка"

users/serializers.py

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,22 @@
11
from typing import Any
22

3-
from django.db import transaction
43
from django.contrib.contenttypes.models import ContentType
5-
from django.forms.models import model_to_dict
64
from django.core.cache import cache
75
from django.core.exceptions import ValidationError as DjangoValidationError
6+
from django.db import transaction
7+
from django.forms.models import model_to_dict
88
from rest_framework import serializers
99
from rest_framework.exceptions import ValidationError
10+
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
1011

12+
from core.models import Skill, SkillToObject, Specialization, SpecializationCategory
1113
from core.serializers import SkillToObjectSerializer
12-
from core.models import SpecializationCategory, Specialization, Skill, SkillToObject
1314
from core.services import get_views_count
1415
from core.utils import get_user_online_cache_key
1516
from partner_programs.models import PartnerProgram, PartnerProgramUserProfile
16-
from projects.models import Project, Collaborator
17+
from projects.models import Collaborator, Project
1718
from projects.validators import validate_project
1819
from users import constants
19-
from users.utils import normalize_user_phone
20-
from users.validators import specialization_exists_validator
2120
from users.models import (
2221
CustomUser,
2322
Expert,
@@ -26,12 +25,12 @@
2625
Mentor,
2726
UserAchievement,
2827
UserEducation,
29-
UserWorkExperience,
30-
UserSkillConfirmation,
3128
UserLanguages,
29+
UserSkillConfirmation,
30+
UserWorkExperience,
3231
)
33-
34-
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
32+
from users.utils import normalize_user_phone
33+
from users.validators import specialization_exists_validator
3534

3635

3736
class AchievementListSerializer(serializers.ModelSerializer[UserAchievement]):
@@ -451,6 +450,8 @@ class Meta:
451450
"projects",
452451
"programs",
453452
"dataset_migration_applied",
453+
"is_mospolytech_student", # новое булево поле
454+
"study_group",
454455
]
455456

456457
@transaction.atomic

0 commit comments

Comments
 (0)