diff --git a/README.md b/README.md index e093dec8..2eb9ee12 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ 1. [БРИФ](https://docs.google.com/document/d/1iHkA4Al-H-ppALPJDLMhb_Dl-ciRHH2npM6YRa2HQwg/edit) + 1.2. [ER - диаграмма сущностей](docs/ER_Diagram.jpg) 1.1. [Инструкции и ритуалы на проекте](docs/materials/instructions.md) diff --git a/adaptive_hockey_federation/main/admin.py b/adaptive_hockey_federation/main/admin.py index 7cc80a82..133c5ea0 100644 --- a/adaptive_hockey_federation/main/admin.py +++ b/adaptive_hockey_federation/main/admin.py @@ -1,104 +1,186 @@ from django.contrib import admin from main.models import ( - Anamnesis, + City, + Competition, + Diagnosis, Discipline, - Health, - Location, + Gender, Player, + PlayerTeam, Position, - RespiratoryFailure, - Role, + Qualification, Team, + TeamCompetition, + Trainer, + TrainerTeam, ) -class TeamInline(admin.TabularInline): - model = Team.players.through - extra = 0 - verbose_name = 'Команда' - verbose_name_plural = 'Команды' - autocomplete_fields = ['team'] - - -class HealthInline(admin.TabularInline): - model = Health - extra = 0 - verbose_name = 'Медицинская карта' - verbose_name_plural = 'Медицинская карта' - - class PlayerInline(admin.TabularInline): - model = Player.team.through - extra = 0 - verbose_name = 'Игрок' - verbose_name_plural = 'Игроки' - autocomplete_fields = ['player'] + model = PlayerTeam -@admin.register(Player) -class PlayerAdmin(admin.ModelAdmin): - inlines = [TeamInline, HealthInline] - fields = ['name', 'surname', 'patronymic', 'birth_date'] - list_display = ['name', 'surname'] - search_fields = ['surname', 'name'] - +class TrainerInline(admin.TabularInline): + model = TrainerTeam -@admin.register(Anamnesis) -class AnamnesisAdmin(admin.ModelAdmin): - search_fields = ['name'] - def get_model_perms(self, request): - """Прячем из меню админки данную модель""" - return {} +class CityAdmin(admin.ModelAdmin): + list_display = ( + 'pk', + 'name' + ) + search_fields = ('name',) -@admin.register(Discipline) -class DisciplineAdmin(admin.ModelAdmin): - search_fields = ['name'] - - def get_model_perms(self, request): - """Прячем из меню админки данную модель""" - return {} +class GenderAdmin(admin.ModelAdmin): + list_display = ( + 'pk', + 'name' + ) + search_fields = ('name',) -@admin.register(Team) -class TeamAdmin(admin.ModelAdmin): - search_fields = ['name'] - autocomplete_fields = ['location', 'discipline'] - inlines = [PlayerInline] +class DisciplineAdmin(admin.ModelAdmin): + list_display = ( + 'pk', + 'name' + ) + search_fields = ('name',) -@admin.register(Location) -class LocationAdmin(admin.ModelAdmin): - search_fields = ['name'] +class PositionAdmin(admin.ModelAdmin): + list_display = ( + 'pk', + 'name' + ) + search_fields = ('name',) - def get_model_perms(self, request): - """Прячем из меню админки данную модель""" - return {} +class QualificationAdmin(admin.ModelAdmin): + list_display = ( + 'pk', + 'name' + ) + search_fields = ('name',) -@admin.register(Position) -class PositionAdmin(admin.ModelAdmin): - search_fields = ['name'] - def get_model_perms(self, request): - """Прячем из меню админки данную модель""" - return {} +class TrainerTeamAdmin(admin.ModelAdmin): + list_display = ( + 'trainer', + 'team', + ) + search_fields = ('trainer', 'team',) -@admin.register(Role) -class RoleAdmin(admin.ModelAdmin): - search_fields = ['name'] +class TrainerAdmin(admin.ModelAdmin): + list_display = ( + 'pk', + 'surname', + 'name', + 'patronymic', + 'description', + ) + search_fields = ('pk', 'surname', 'name', 'patronymic', 'description',) - def get_model_perms(self, request): - """Прячем из меню админки данную модель""" - return {} +class PlayerAdmin(admin.ModelAdmin): + list_display = ( + 'pk', + 'surname', + 'name', + 'patronymic', + 'date_of_birth', + 'diagnosis', + 'gender', + 'identification_card', + ) + search_fields = ( + 'pk', + 'surname', + 'name', + 'patronymic', + 'date_of_birth', + 'diagnosis', + 'gender', + 'identification_card', + ) + + +class DiagnosisAdmin(admin.ModelAdmin): + list_display = ( + 'pk', + 'class_name', + 'is_wheeled', + 'description', + ) + search_fields = ( + 'pk', 'class_name', 'description',) + + +class PlayerTeamAdmin(admin.ModelAdmin): + list_display = ( + 'pk', + 'player', + 'team', + 'qualification', + 'number', + 'is_captain', + 'is_assistent', + ) + search_fields = ( + 'pk', 'player', 'team', 'qualification',) + + +class CompetitionAdmin(admin.ModelAdmin): + list_display = ( + 'pk', + 'city', + 'number', + 'date', + 'duration', + 'is_active', + ) + search_fields = ( + 'pk', 'city', 'number', 'duration',) + list_filter = ('date',) + + +class TeamCompetitionAdmin(admin.ModelAdmin): + list_display = ( + 'pk', + 'team', + 'competition', + ) + search_fields = ( + 'pk', 'team', 'competition',) -@admin.register(RespiratoryFailure) -class RespiratoryFailureAdmin(admin.ModelAdmin): - search_fields = ['name'] - def get_model_perms(self, request): - """Прячем из меню админки данную модель""" - return {} +@admin.register(Team) +class TeamAdmin(admin.ModelAdmin): + list_display = ( + 'name', + 'city', + 'discipline', + 'composition', + 'age', + 'pk', + ) + search_fields = [ + 'pk', 'name', 'city', 'discipline', 'composition', 'age'] + autocomplete_fields = ['city', 'discipline'] + inlines = [PlayerInline, TrainerInline] + + +admin.site.register(Diagnosis, DiagnosisAdmin) +admin.site.register(Discipline, DisciplineAdmin) +admin.site.register(Gender, GenderAdmin) +admin.site.register(City, CityAdmin) +admin.site.register(Player, PlayerAdmin) +admin.site.register(Position, PositionAdmin) +# admin.site.register(Team, TeamAdmin) +admin.site.register(Qualification, QualificationAdmin) +admin.site.register(PlayerTeam, PlayerTeamAdmin) +admin.site.register(Trainer, TrainerAdmin) +admin.site.register(TrainerTeam, TrainerTeamAdmin) +admin.site.register(Competition, CompetitionAdmin) +admin.site.register(TeamCompetition, TeamCompetitionAdmin) diff --git a/adaptive_hockey_federation/main/migrations/0001_initial.py b/adaptive_hockey_federation/main/migrations/0001_initial.py index d5f05415..4a85acf3 100644 --- a/adaptive_hockey_federation/main/migrations/0001_initial.py +++ b/adaptive_hockey_federation/main/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2.6 on 2023-11-25 14:50 +# Generated by Django 4.2.8 on 2023-12-14 14:00 import django.db.models.deletion from django.db import migrations, models @@ -13,53 +13,78 @@ class Migration(migrations.Migration): operations = [ migrations.CreateModel( - name='Anamnesis', + name='City', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=256, unique=True, verbose_name='Название')), + ('name', models.CharField(help_text='Название', max_length=256, unique=True, verbose_name='Название')), + ], + options={ + 'verbose_name': 'Город', + 'verbose_name_plural': 'Города', + }, + ), + migrations.CreateModel( + name='Competition', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(help_text='Название', max_length=256, unique=True, verbose_name='Название')), + ('number', models.CharField(help_text='Номер соревнований', max_length=256, verbose_name='Номер соревнований')), + ('date', models.DateField(help_text='Дата соревнований', verbose_name='Дата соревнований')), + ('duration', models.IntegerField(default=0, help_text='Длительность', verbose_name='Длительность')), + ('is_active', models.BooleanField(default=True, help_text='Активно', verbose_name='Активно')), + ('city', models.ForeignKey(blank=True, help_text='Город', null=True, on_delete=django.db.models.deletion.SET_NULL, to='main.city', verbose_name='Город')), + ], + options={ + 'verbose_name': 'Соревнование', + 'verbose_name_plural': 'Соревнования', + }, + ), + migrations.CreateModel( + name='Diagnosis', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('class_name', models.CharField(help_text='Класс', max_length=10, unique=True, verbose_name='Класс')), + ('is_wheeled', models.BooleanField(default=False, help_text='На коляске', verbose_name='На коляске')), + ('description', models.TextField(blank=True, help_text='Описание', verbose_name='Описание')), ], options={ 'verbose_name': 'Диагноз', 'verbose_name_plural': 'Диагнозы', - 'ordering': ('name',), - 'abstract': False, }, ), migrations.CreateModel( name='Discipline', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=256, unique=True, verbose_name='Название')), + ('name', models.CharField(help_text='Название', max_length=256, unique=True, verbose_name='Название')), ], options={ 'verbose_name': 'Дисциплина', 'verbose_name_plural': 'Дисциплины', - 'ordering': ('name',), - 'abstract': False, }, ), migrations.CreateModel( - name='Location', + name='Gender', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=256, unique=True, verbose_name='Название')), + ('name', models.CharField(help_text='Название', max_length=256, unique=True, verbose_name='Название')), ], options={ - 'verbose_name': 'Территория', - 'verbose_name_plural': 'Территории', - 'ordering': ('name',), - 'abstract': False, + 'verbose_name': 'Пол', + 'verbose_name_plural': 'Пол', }, ), migrations.CreateModel( name='Player', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=256, verbose_name='Имя')), - ('surname', models.CharField(max_length=256, verbose_name='Фамилия')), - ('patronymic', models.CharField(blank=True, max_length=256, null=True, verbose_name='Отчество')), - ('birth_date', models.DateField()), - ('sex', models.CharField(blank=True, choices=[('male', 'Мужской'), ('female', 'Женский')], max_length=6, null=True, verbose_name='Пол')), + ('surname', models.CharField(default='--пусто--', help_text='Фамилия', max_length=256, verbose_name='Фамилия')), + ('name', models.CharField(default='--пусто--', help_text='Имя', max_length=256, verbose_name='Имя')), + ('patronymic', models.CharField(blank=True, default='--пусто--', help_text='Отчество', max_length=256, verbose_name='Отчество')), + ('date_of_birth', models.DateField(blank=True, help_text='Дата рождения', null=True, verbose_name='Дата рождения')), + ('identification_card', models.TextField(default=0, help_text='Удостоверение личности', verbose_name='Удостоверение личности')), + ('diagnosis', models.ForeignKey(default=0, help_text='Диагноз', on_delete=django.db.models.deletion.CASCADE, related_name='diagnosis', to='main.diagnosis', verbose_name='Диагноз')), + ('gender', models.ForeignKey(default=0, help_text='Пол', on_delete=django.db.models.deletion.CASCADE, related_name='gender', to='main.gender', verbose_name='Пол')), ], options={ 'verbose_name': 'Игрок', @@ -73,89 +98,116 @@ class Migration(migrations.Migration): name='Position', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=256, unique=True, verbose_name='Название')), + ('name', models.CharField(help_text='Название', max_length=256, unique=True, verbose_name='Название')), ], options={ - 'verbose_name': 'Игровая позиция', + 'verbose_name': 'Игоровая позиция', 'verbose_name_plural': 'Игровые позиции', - 'ordering': ('name',), - 'abstract': False, }, ), migrations.CreateModel( - name='RespiratoryFailure', + name='Qualification', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=256, unique=True, verbose_name='Название')), + ('name', models.CharField(help_text='Название', max_length=256, unique=True, verbose_name='Название')), ], options={ - 'verbose_name': 'Класс ХДН', - 'verbose_name_plural': 'Классы ХДН', - 'ordering': ('name',), - 'abstract': False, + 'verbose_name': 'Квалификация', + 'verbose_name_plural': 'Квалификации', }, ), migrations.CreateModel( - name='Role', + name='Team', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=256, unique=True, verbose_name='Название')), + ('name', models.CharField(help_text='Название', max_length=256, verbose_name='Название')), + ('composition', models.CharField(default='--пусто--', help_text='Состав', max_length=256, verbose_name='Состав')), + ('age', models.CharField(default='--пусто--', help_text='Возраст', max_length=256, verbose_name='Возраст')), + ('city', models.ForeignKey(blank=True, help_text='Город откуда команда', null=True, on_delete=django.db.models.deletion.SET_NULL, to='main.city', verbose_name='Город откуда команда')), + ('discipline', models.ForeignKey(blank=True, help_text='Дисциплина команды', null=True, on_delete=django.db.models.deletion.SET_NULL, to='main.discipline', verbose_name='Дисциплина команды')), ], options={ - 'verbose_name': 'Игровая позиция', - 'verbose_name_plural': 'Игровые позиции', - 'ordering': ('name',), - 'abstract': False, + 'verbose_name': 'Команда', + 'verbose_name_plural': 'Команды', + 'default_related_name': 'teams', }, ), migrations.CreateModel( - name='Team', + name='Trainer', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=256)), - ('discipline', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='main.discipline', verbose_name='Дисциплина команды')), - ('location', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='main.location', verbose_name='Локация команды')), + ('surname', models.CharField(default='--пусто--', help_text='Фамилия', max_length=256, verbose_name='Фамилия')), + ('name', models.CharField(default='--пусто--', help_text='Имя', max_length=256, verbose_name='Имя')), + ('patronymic', models.CharField(blank=True, default='--пусто--', help_text='Отчество', max_length=256, verbose_name='Отчество')), + ('date_of_birth', models.DateField(blank=True, help_text='Дата рождения', null=True, verbose_name='Дата рождения')), + ('description', models.TextField(help_text='Описание', verbose_name='Описание')), ], options={ - 'verbose_name': 'Команда', - 'verbose_name_plural': 'Команды', - 'default_related_name': 'teams', + 'verbose_name': 'Тренер', + 'verbose_name_plural': 'Тренеры', }, ), migrations.CreateModel( - name='PlayerTeam', + name='TrainerTeam', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('number', models.CharField(max_length=256, verbose_name='Игровой номер')), - ('player', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='player_teams', to='main.player', verbose_name='Игрок')), - ('position', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='main.position', verbose_name='Позиция игрока')), - ('role', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='main.role', verbose_name='Статус игрока')), - ('team', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='team_players', to='main.team', verbose_name='Команда')), + ('team', models.ForeignKey(help_text='Команда', on_delete=django.db.models.deletion.CASCADE, to='main.team', verbose_name='Команда')), + ('trainer', models.ForeignKey(help_text='Тренер команды', on_delete=django.db.models.deletion.CASCADE, to='main.trainer', verbose_name='Тренер команды')), ], + options={ + 'verbose_name': 'Тренер --> команда', + 'verbose_name_plural': 'Тренер --> команды', + 'default_related_name': 'trainer_teams', + }, ), - migrations.AddField( - model_name='player', - name='team', - field=models.ManyToManyField(through='main.PlayerTeam', to='main.team', verbose_name='Команда'), + migrations.CreateModel( + name='TeamCompetition', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('competition', models.ForeignKey(help_text='Соревнование', on_delete=django.db.models.deletion.CASCADE, to='main.competition', verbose_name='Соревнование')), + ('team', models.ForeignKey(help_text='Команда', on_delete=django.db.models.deletion.CASCADE, to='main.team', verbose_name='Команда')), + ], + options={ + 'verbose_name': 'Соревнование --> команда', + 'verbose_name_plural': 'Совревнования --> команды', + 'default_related_name': 'team_competitions', + }, ), migrations.CreateModel( - name='Health', + name='PlayerTeam', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('is_permanent', models.BooleanField(default=False, verbose_name='Класс ХДН подтверждён перманентно')), - ('revision', models.CharField(blank=True, max_length=256, null=True, verbose_name='Пересмотр класса ХДН')), - ('wheelchair', models.BooleanField(default=False, verbose_name='На коляске')), - ('anamnesis', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='main.anamnesis', verbose_name='Диагноз')), - ('player', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='health', to='main.player', verbose_name='Игрок')), - ('respiratory_failure', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='respiratory_failure_players', to='main.respiratoryfailure', verbose_name='Класс ХДН')), + ('number', models.CharField(help_text='Номер игорока', max_length=256, verbose_name='Номер игорока')), + ('is_captain', models.BooleanField(default=False, help_text='Капитан', verbose_name='Капитан')), + ('is_assistent', models.BooleanField(default=False, help_text='Ассистент', verbose_name='Ассистент')), + ('player', models.ForeignKey(help_text='Игрок', on_delete=django.db.models.deletion.CASCADE, related_name='player_teams', to='main.player', verbose_name='Игрок')), + ('position', models.ForeignKey(blank=True, help_text='Позиция игрока', null=True, on_delete=django.db.models.deletion.SET_NULL, to='main.position', verbose_name='Позиция игрока')), + ('qualification', models.ForeignKey(blank=True, help_text='Квалификация игрока', null=True, on_delete=django.db.models.deletion.SET_NULL, to='main.qualification', verbose_name='Квалификация игрока')), + ('team', models.ForeignKey(help_text='Команда', on_delete=django.db.models.deletion.CASCADE, related_name='team_players', to='main.team', verbose_name='Команда')), ], + options={ + 'verbose_name': 'Игрок команды', + 'verbose_name_plural': 'Игроки команды', + }, + ), + migrations.AddConstraint( + model_name='trainerteam', + constraint=models.UniqueConstraint(fields=('trainer', 'team'), name='trainer_teams_unique'), + ), + migrations.AddConstraint( + model_name='teamcompetition', + constraint=models.UniqueConstraint(fields=('team', 'competition'), name='competition_teams_unique'), ), migrations.AddConstraint( model_name='team', - constraint=models.UniqueConstraint(fields=('name', 'location', 'discipline'), name='team_location_unique'), + constraint=models.UniqueConstraint(fields=('name', 'city', 'discipline'), name='team_city_unique'), ), migrations.AddConstraint( model_name='player', - constraint=models.UniqueConstraint(fields=('name', 'surname', 'patronymic', 'birth_date'), name='player_unique'), + constraint=models.UniqueConstraint(fields=('name', 'surname', 'patronymic', 'date_of_birth'), name='player_unique'), + ), + migrations.AddConstraint( + model_name='competition', + constraint=models.UniqueConstraint(fields=('city', 'number', 'date'), name='competitions_unique'), ), ] diff --git a/adaptive_hockey_federation/main/migrations/0002_alter_player_patronymic.py b/adaptive_hockey_federation/main/migrations/0002_alter_player_patronymic.py deleted file mode 100644 index ffafb0be..00000000 --- a/adaptive_hockey_federation/main/migrations/0002_alter_player_patronymic.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 4.2.7 on 2023-12-06 21:06 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('main', '0001_initial'), - ] - - operations = [ - migrations.AlterField( - model_name='player', - name='patronymic', - field=models.CharField(blank=True, default='', max_length=256, verbose_name='Отчество'), - ), - ] diff --git a/adaptive_hockey_federation/main/migrations/0003_alter_health_revision_alter_player_sex.py b/adaptive_hockey_federation/main/migrations/0003_alter_health_revision_alter_player_sex.py deleted file mode 100644 index 11528fc1..00000000 --- a/adaptive_hockey_federation/main/migrations/0003_alter_health_revision_alter_player_sex.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 4.2.7 on 2023-12-08 22:05 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('main', '0002_alter_player_patronymic'), - ] - - operations = [ - migrations.AlterField( - model_name='health', - name='revision', - field=models.CharField(blank=True, max_length=256, verbose_name='Пересмотр класса ХДН'), - ), - migrations.AlterField( - model_name='player', - name='sex', - field=models.CharField(blank=True, choices=[('male', 'Мужской'), ('female', 'Женский')], max_length=6, verbose_name='Пол'), - ), - ] diff --git a/adaptive_hockey_federation/main/models.py b/adaptive_hockey_federation/main/models.py index ed7d57b2..1fee1306 100644 --- a/adaptive_hockey_federation/main/models.py +++ b/adaptive_hockey_federation/main/models.py @@ -1,32 +1,16 @@ from django.db import models -from django.db.models import ( - CASCADE, - SET_NULL, - BooleanField, - CharField, - DateField, - ForeignKey, - ManyToManyField, - Model, - UniqueConstraint, -) - -SEX_CHOICES = ( - ('male', 'Мужской'), - ('female', 'Женский'), -) +from django.utils.translation import gettext_lazy as _ NAME_FIELD_LENGTH = 256 -BASE_PERSON_FIELD_LENGTH = 256 +EMPTY_VALUE_DISPLAY = '--пусто--' +CLASS_FIELD_LENGTH = 10 -class BaseUniqueName(Model): - """ - Абстрактный класс с уникальным полем "Название" и методом отображения - """ - name: models.CharField = CharField( +class BaseUniqueName(models.Model): + name = models.CharField( max_length=NAME_FIELD_LENGTH, - verbose_name='Название', + verbose_name=_('Название'), + help_text=_('Название'), unique=True, ) @@ -38,152 +22,131 @@ def __str__(self): return self.name -class Location(BaseUniqueName): - """ - Локация привязки команды (город, область, край) - или места проведения соревнования - """ - - class Meta(BaseUniqueName.Meta): - verbose_name = 'Территория' - verbose_name_plural = 'Территории' - - def __str__(self): - return super().__str__() - - -class Discipline(BaseUniqueName): +class BasePerson(models.Model): """ - Классификация дисциплины (следж-хоккей, хоккей для незрячих, спец. хоккей) + Абстрактная модель с базовой персональной информацией. """ + surname = models.CharField( + max_length=NAME_FIELD_LENGTH, + verbose_name=_('Фамилия'), + help_text=_('Фамилия'), + default=EMPTY_VALUE_DISPLAY + ) + name = models.CharField( + max_length=NAME_FIELD_LENGTH, + verbose_name=_('Имя'), + help_text=_('Имя'), + default=EMPTY_VALUE_DISPLAY + ) + patronymic = models.CharField( + max_length=NAME_FIELD_LENGTH, + blank=True, + verbose_name=_('Отчество'), + help_text=_('Отчество'), + default=EMPTY_VALUE_DISPLAY + ) + date_of_birth = models.DateField( + verbose_name=_('Дата рождения'), + help_text=_('Дата рождения'), + null=True, + blank=True + ) - class Meta(BaseUniqueName.Meta): - verbose_name = 'Дисциплина' - verbose_name_plural = 'Дисциплины' + class Meta: + ordering = ('surname', 'name', 'patronymic') + abstract = True def __str__(self): - return super().__str__() + return ' '.join([self.surname, self.name, self.patronymic]) -class Team(Model): +class Diagnosis(models.Model): """ - Модель команды. + Модель Диагноз. """ - name: models.CharField = CharField(max_length=NAME_FIELD_LENGTH, ) - location: models.ForeignKey = ForeignKey( - to=Location, - on_delete=SET_NULL, - blank=True, - null=True, - verbose_name='Локация команды', + class_name = models.CharField( + verbose_name=_('Класс'), + help_text=_('Класс'), + max_length=CLASS_FIELD_LENGTH, + unique=True ) - discipline: models.ForeignKey = ForeignKey( - to=Discipline, - on_delete=SET_NULL, - blank=True, - null=True, - verbose_name='Дисциплина команды', + is_wheeled = models.BooleanField( + default=False, + verbose_name=_('На коляске'), + help_text=_('На коляске') ) - players: models.ManyToManyField = ManyToManyField( - to='Player', - through='PlayerTeam', - verbose_name='Игроки', + description = models.TextField( + verbose_name=_('Описание'), + help_text=_('Описание'), + blank=True ) class Meta: - default_related_name = 'teams' - verbose_name = 'Команда' - verbose_name_plural = 'Команды' - constraints = [ - UniqueConstraint( - name='team_location_unique', - fields=['name', 'location', 'discipline'], - ) - ] + verbose_name = 'Диагноз' + verbose_name_plural = 'Диагнозы' def __str__(self): - if self.location: - return f'{self.name} - {self.location}' - return self.name + return self.class_name -class Position(BaseUniqueName): +class Gender(BaseUniqueName): """ - Игровая позиция игрока в команде + Модель Пол. """ - - class Meta(BaseUniqueName.Meta): - verbose_name = 'Игровая позиция' - verbose_name_plural = 'Игровые позиции' + class Meta: + verbose_name = 'Пол' + verbose_name_plural = 'Пол' def __str__(self): - return super().__str__() + return self.name -class Role(BaseUniqueName): +class Position(BaseUniqueName): """ - Роль игрока в команде (капитан, ассистент) + Модель Игоровая позиция. """ - - class Meta(BaseUniqueName.Meta): - verbose_name = 'Игровая позиция' + class Meta: + verbose_name = 'Игоровая позиция' verbose_name_plural = 'Игровые позиции' def __str__(self): - return super().__str__() + return self.name -class Anamnesis(BaseUniqueName): +class Qualification(BaseUniqueName): """ - Диагноз общий + Модель Квалификация. """ - - class Meta(BaseUniqueName.Meta): - verbose_name = 'Диагноз' - verbose_name_plural = 'Диагнозы' + class Meta: + verbose_name = 'Квалификация' + verbose_name_plural = 'Квалификации' def __str__(self): - return super().__str__() + return self.name -class RespiratoryFailure(BaseUniqueName): +class Discipline(BaseUniqueName): """ - Класс хронической дыхательной недостаточности + Модель Дисциплина. """ - - class Meta(BaseUniqueName.Meta): - verbose_name = 'Класс ХДН' - verbose_name_plural = 'Классы ХДН' + class Meta: + verbose_name = 'Дисциплина' + verbose_name_plural = 'Дисциплины' def __str__(self): - return super().__str__() + return self.name -class BasePerson(Model): +class City(BaseUniqueName): """ - Абстрактная модель с базовой персональной информацией + Модель Город. """ - name: models.CharField = CharField( - max_length=BASE_PERSON_FIELD_LENGTH, - verbose_name='Имя', - ) - surname: models.CharField = CharField( - max_length=BASE_PERSON_FIELD_LENGTH, - verbose_name='Фамилия', - ) - patronymic: models.CharField = CharField( - max_length=BASE_PERSON_FIELD_LENGTH, - blank=True, - default='', - verbose_name='Отчество', - ) - class Meta: - ordering = ('surname', 'name', 'patronymic') - abstract = True + verbose_name = 'Город' + verbose_name_plural = 'Города' def __str__(self): - return ' '.join([self.surname, self.name, self.patronymic]) + return self.name class Player(BasePerson): @@ -191,17 +154,26 @@ class Player(BasePerson): Модель игрока. Связь с командой "многие ко многим" на случай включения игрока в сборную, помимо основного состава. """ - birth_date: models.DateField = DateField() - sex: models.CharField = CharField( - max_length=max(len(sex) for sex, _ in SEX_CHOICES), - choices=SEX_CHOICES, - blank=True, - verbose_name='Пол' + diagnosis = models.ForeignKey( + Diagnosis, + on_delete=models.CASCADE, + related_name='diagnosis', + verbose_name=_('Диагноз'), + help_text=_('Диагноз'), + default=0 ) - team: models.ManyToManyField = ManyToManyField( - to=Team, - through='PlayerTeam', - verbose_name='Команда' + gender = models.ForeignKey( + Gender, + on_delete=models.CASCADE, + related_name='gender', + verbose_name=_('Пол'), + help_text=_('Пол'), + default=0 + ) + identification_card = models.TextField( + verbose_name=_('Удостоверение личности'), + help_text=_('Удостоверение личности'), + default=0 ) class Meta(BasePerson.Meta): @@ -209,94 +181,253 @@ class Meta(BasePerson.Meta): verbose_name = 'Игрок' verbose_name_plural = 'Игроки' constraints = [ - UniqueConstraint( + models.UniqueConstraint( name='player_unique', - fields=['name', 'surname', 'patronymic', 'birth_date'], + fields=['name', 'surname', 'patronymic', 'date_of_birth'] ) ] def __str__(self): - return f"{self.name} {self.surname}" + return ' '.join([self.surname, self.name, self.patronymic]) -class Health(Model): +class Trainer(BasePerson): """ - Информация по хронической дыхательной недостаточности. + Модель Тренер. """ - player: models.ForeignKey = ForeignKey( - to=Player, - related_name='health', - on_delete=CASCADE, - verbose_name='Игрок', + description = models.TextField( + verbose_name=_('Описание'), + help_text=_('Описание') ) - respiratory_failure: models.ForeignKey = ForeignKey( - to=RespiratoryFailure, - related_name='respiratory_failure_players', - on_delete=CASCADE, - verbose_name='Класс ХДН', - ) - is_permanent: models.BooleanField = BooleanField( - default=False, - verbose_name='Класс ХДН подтверждён перманентно', - ) - revision: models.CharField = CharField( + + class Meta: + verbose_name = 'Тренер' + verbose_name_plural = 'Тренеры' + + def __str__(self): + return ' '.join([self.surname, self.name, self.patronymic]) + + +class Team(models.Model): + """ + Модель команды. + """ + name = models.CharField( max_length=NAME_FIELD_LENGTH, + verbose_name=_('Название'), + help_text=_('Название') + ) + city = models.ForeignKey( + to=City, + on_delete=models.SET_NULL, blank=True, - verbose_name='Пересмотр класса ХДН', + null=True, + verbose_name=_('Город откуда команда'), + help_text=_('Город откуда команда') ) - anamnesis: models.ForeignKey = ForeignKey( - to=Anamnesis, - on_delete=SET_NULL, + discipline = models.ForeignKey( + to=Discipline, + on_delete=models.SET_NULL, blank=True, null=True, - verbose_name='Диагноз', + verbose_name=_('Дисциплина команды'), + help_text=_('Дисциплина команды') ) - wheelchair: models.BooleanField = BooleanField( - default=False, - verbose_name='На коляске' + composition = models.CharField( + max_length=NAME_FIELD_LENGTH, + verbose_name=_('Состав'), + help_text=_('Состав'), + default=EMPTY_VALUE_DISPLAY + ) + age = models.CharField( + max_length=NAME_FIELD_LENGTH, + verbose_name=_('Возраст'), + help_text=_('Возраст'), + default=EMPTY_VALUE_DISPLAY + ) + + class Meta: + default_related_name = 'teams' + verbose_name = 'Команда' + verbose_name_plural = 'Команды' + constraints = [ + models.UniqueConstraint( + name='team_city_unique', + fields=['name', 'city', 'discipline'], + ) + ] + + def __str__(self): + if self.city: + return f'{self.name} - {self.city}' + return self.name + + +class TrainerTeam(models.Model): + """ + Модель тренер - команда. + """ + trainer = models.ForeignKey( + to=Trainer, + on_delete=models.CASCADE, + verbose_name=_('Тренер команды'), + help_text=_('Тренер команды') ) + team = models.ForeignKey( + to=Team, + on_delete=models.CASCADE, + verbose_name=_('Команда'), + help_text=_('Команда') + ) + + class Meta: + default_related_name = 'trainer_teams' + verbose_name = 'Тренер --> команда' + verbose_name_plural = 'Тренер --> команды' + constraints = [ + models.UniqueConstraint( + name='trainer_teams_unique', + fields=['trainer', 'team'] + ) + ] def __str__(self): - return (f'Медицинские показатели' - f' игрока {self.player.surname} {self.player.name}') + return str(self.trainer.id) -class PlayerTeam(Model): +class PlayerTeam(models.Model): """ Связь "многие ко многим" игрока с командой с добавлением данных игрока в этой команде. """ - player: models.ForeignKey = ForeignKey( + player = models.ForeignKey( to=Player, related_name='player_teams', - on_delete=CASCADE, - verbose_name='Игрок', + on_delete=models.CASCADE, + verbose_name=_('Игрок'), + help_text=_('Игрок') ) - team: models.ForeignKey = ForeignKey( + team = models.ForeignKey( to=Team, related_name='team_players', - on_delete=CASCADE, - verbose_name='Команда', + on_delete=models.CASCADE, + verbose_name=_('Команда'), + help_text=_('Команда') ) - position: models.ForeignKey = ForeignKey( + position = models.ForeignKey( to=Position, - on_delete=SET_NULL, + on_delete=models.SET_NULL, blank=True, null=True, - verbose_name='Позиция игрока', + verbose_name=_('Позиция игрока'), + help_text=_('Позиция игрока') ) - role: models.ForeignKey = ForeignKey( - to=Role, - on_delete=SET_NULL, + qualification = models.ForeignKey( + to=Qualification, + on_delete=models.SET_NULL, blank=True, null=True, - verbose_name='Статус игрока', + verbose_name=_('Квалификация игрока'), + help_text=_('Квалификация игрока') ) - number: models.CharField = CharField( + number = models.CharField( max_length=NAME_FIELD_LENGTH, - verbose_name='Игровой номер', + verbose_name=_('Номер игорока'), + help_text=_('Номер игорока') + ) + is_captain = models.BooleanField( + default=False, + verbose_name=_('Капитан'), + help_text=_('Капитан') + ) + is_assistent = models.BooleanField( + default=False, + verbose_name=_('Ассистент'), + help_text=_('Ассистент') + ) + + class Meta: + verbose_name = 'Игрок команды' + verbose_name_plural = 'Игроки команды' + + def __str__(self): + return str(self.player.id) + + +class Competition(BaseUniqueName): + """ + Модель Соревнования. + """ + city = models.ForeignKey( + to=City, + on_delete=models.SET_NULL, + blank=True, + null=True, + verbose_name=_('Город'), + help_text=_('Город') + ) + number = models.CharField( + max_length=NAME_FIELD_LENGTH, + verbose_name=_('Номер соревнований'), + help_text=_('Номер соревнований') + ) + date = models.DateField( + verbose_name=_('Дата соревнований'), + help_text=_('Дата соревнований') + ) + duration = models.IntegerField( + default=0, + verbose_name=_('Длительность'), + help_text=_('Длительность') + ) + is_active = models.BooleanField( + default=True, + verbose_name=_('Активно'), + help_text=_('Активно') ) - def __str__(self) -> str: - return f"{self.team} {self.player}" + class Meta: + verbose_name = 'Соревнование' + verbose_name_plural = 'Соревнования' + constraints = [ + models.UniqueConstraint( + name='competitions_unique', + fields=['city', 'number', 'date'] + ) + ] + + def __str__(self): + return str(self.city.id) + + +class TeamCompetition(models.Model): + """ + Модель команда - соревнование. + """ + team = models.ForeignKey( + to=Team, + on_delete=models.CASCADE, + verbose_name=_('Команда'), + help_text=_('Команда') + ) + competition = models.ForeignKey( + to=Competition, + on_delete=models.CASCADE, + verbose_name=_('Соревнование'), + help_text=_('Соревнование') + ) + + class Meta: + default_related_name = 'team_competitions' + verbose_name = 'Соревнование --> команда' + verbose_name_plural = 'Совревнования --> команды' + constraints = [ + models.UniqueConstraint( + name='competition_teams_unique', + fields=['team', 'competition'] + ) + ] + + def __str__(self): + return str(self.team.id) diff --git a/docs/ER_Diagram.drawio b/docs/ER_Diagram.drawio new file mode 100644 index 00000000..b74121d9 --- /dev/null +++ b/docs/ER_Diagram.drawio @@ -0,0 +1,968 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/ER_Diagram.jpg b/docs/ER_Diagram.jpg new file mode 100644 index 00000000..c96f813c Binary files /dev/null and b/docs/ER_Diagram.jpg differ