models
This commit is contained in:
17
.idea/dataSources.xml
generated
Normal file
17
.idea/dataSources.xml
generated
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
|
||||||
|
<data-source source="LOCAL" name="db" uuid="018e0f6c-5916-4f25-8264-dc6301fd54fd">
|
||||||
|
<driver-ref>sqlite.xerial</driver-ref>
|
||||||
|
<synchronize>true</synchronize>
|
||||||
|
<jdbc-driver>org.sqlite.JDBC</jdbc-driver>
|
||||||
|
<jdbc-url>jdbc:sqlite:C:\Users\Mikan\PycharmProjects\tisbiProFi\db.sqlite3</jdbc-url>
|
||||||
|
<working-dir>$ProjectFileDir$</working-dir>
|
||||||
|
<libraries>
|
||||||
|
<library>
|
||||||
|
<url>file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.43.0/org/xerial/sqlite-jdbc/3.43.0.0/sqlite-jdbc-3.43.0.0.jar</url>
|
||||||
|
</library>
|
||||||
|
</libraries>
|
||||||
|
</data-source>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
from django.db import models
|
|
||||||
|
|
||||||
class ContactMixin(models.Model):
|
|
||||||
first_name = models.CharField(max_length=100, verbose_name="Имя")
|
|
||||||
last_name = models.CharField(max_length=100, verbose_name="Фамилия")
|
|
||||||
middle_name = models.CharField(max_length=100, blank=True, null=True, verbose_name="Отчество")
|
|
||||||
phone = models.CharField(max_length=20, blank=True, null=True, verbose_name="Телефон")
|
|
||||||
email = models.EmailField(blank=True, null=True, verbose_name="Почта")
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return f"{self.last_name} {self.first_name}"
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
abstract = True
|
|
||||||
|
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
from django.db import models
|
||||||
|
|
||||||
|
class ContactMixin(models.Model):
|
||||||
|
first_name = models.CharField(max_length=100, verbose_name="Имя")
|
||||||
|
last_name = models.CharField(max_length=100, verbose_name="Фамилия", blank=True, null=True)
|
||||||
|
middle_name = models.CharField(max_length=100, blank=True, null=True, verbose_name="Отчество")
|
||||||
|
phone = models.CharField(max_length=20, blank=True, null=True, verbose_name="Телефон")
|
||||||
|
email = models.EmailField(blank=True, null=True, verbose_name="Почта")
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.last_name} {self.first_name}"
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
abstract = True
|
||||||
|
|
||||||
|
|||||||
0
education/__init__.py
Normal file
0
education/__init__.py
Normal file
3
education/admin.py
Normal file
3
education/admin.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
# Register your models here.
|
||||||
6
education/apps.py
Normal file
6
education/apps.py
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class EducationConfig(AppConfig):
|
||||||
|
default_auto_field = 'django.db.models.BigAutoField'
|
||||||
|
name = 'education'
|
||||||
84
education/migrations/0001_initial.py
Normal file
84
education/migrations/0001_initial.py
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
# Generated by Django 4.2.21 on 2025-05-18 18:14
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='AcademicYear',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('year', models.CharField(max_length=9, verbose_name='Год')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Учебный год',
|
||||||
|
'verbose_name_plural': 'Учебные годы',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Department',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=100, verbose_name='Название отделения')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Учебное отделение',
|
||||||
|
'verbose_name_plural': 'Учебные отделения',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='DepartmentHead',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Руководитель отделения',
|
||||||
|
'verbose_name_plural': 'Руководители отделений',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Group',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=20, verbose_name='Название группы')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Группа',
|
||||||
|
'verbose_name_plural': 'Группы',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Specialty',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=200, verbose_name='Название специальности')),
|
||||||
|
('code', models.CharField(max_length=20, verbose_name='Код специальности')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Специальность',
|
||||||
|
'verbose_name_plural': 'Специальности',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Student',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('first_name', models.CharField(max_length=100, verbose_name='Имя')),
|
||||||
|
('last_name', models.CharField(blank=True, max_length=100, null=True, verbose_name='Фамилия')),
|
||||||
|
('middle_name', models.CharField(blank=True, max_length=100, null=True, verbose_name='Отчество')),
|
||||||
|
('phone', models.CharField(blank=True, max_length=20, null=True, verbose_name='Телефон')),
|
||||||
|
('email', models.EmailField(blank=True, max_length=254, null=True, verbose_name='Почта')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Студент',
|
||||||
|
'verbose_name_plural': 'Студенты',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
58
education/migrations/0002_initial.py
Normal file
58
education/migrations/0002_initial.py
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
# Generated by Django 4.2.21 on 2025-05-18 18:14
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('employees', '0001_initial'),
|
||||||
|
('education', '0001_initial'),
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='student',
|
||||||
|
name='account',
|
||||||
|
field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Аккаунт'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='student',
|
||||||
|
name='group',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='education.group', verbose_name='Группа'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='specialty',
|
||||||
|
name='department',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='education.department', verbose_name='Учебное отделение'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='group',
|
||||||
|
name='curator',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='employees.employee', verbose_name='Куратор'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='group',
|
||||||
|
name='specialty',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='education.specialty', verbose_name='Специальность'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='departmenthead',
|
||||||
|
name='department',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='education.department', verbose_name='Учебное отделение'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='departmenthead',
|
||||||
|
name='head',
|
||||||
|
field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='employees.employee', verbose_name='Руководитель'),
|
||||||
|
),
|
||||||
|
migrations.AlterUniqueTogether(
|
||||||
|
name='departmenthead',
|
||||||
|
unique_together={('department', 'head')},
|
||||||
|
),
|
||||||
|
]
|
||||||
0
education/migrations/__init__.py
Normal file
0
education/migrations/__init__.py
Normal file
93
education/models.py
Normal file
93
education/models.py
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
from django.db import models
|
||||||
|
from core.models import ContactMixin # Предполагается, что ContactMixin находится в приложении core
|
||||||
|
from employees.models import Employee # Предполагается, что модель Employee находится в приложении employees
|
||||||
|
from users.models import Account # Предполагается, что модель Account находится в приложении users
|
||||||
|
|
||||||
|
## Учебный процесс (название приложения: education)
|
||||||
|
|
||||||
|
class AcademicYear(models.Model):
|
||||||
|
year = models.CharField(max_length=9, verbose_name="Год") # Например, "2023-2024"
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.year
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = "Учебный год"
|
||||||
|
verbose_name_plural = "Учебные годы"
|
||||||
|
|
||||||
|
|
||||||
|
class Department(models.Model):
|
||||||
|
name = models.CharField(max_length=100, verbose_name="Название отделения")
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = "Учебное отделение"
|
||||||
|
verbose_name_plural = "Учебные отделения"
|
||||||
|
|
||||||
|
|
||||||
|
class DepartmentHead(models.Model):
|
||||||
|
department = models.ForeignKey(
|
||||||
|
Department, on_delete=models.CASCADE, verbose_name="Учебное отделение"
|
||||||
|
)
|
||||||
|
head = models.OneToOneField(
|
||||||
|
Employee, on_delete=models.CASCADE, verbose_name="Руководитель"
|
||||||
|
)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.head} - {self.department}"
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = "Руководитель отделения"
|
||||||
|
verbose_name_plural = "Руководители отделений"
|
||||||
|
unique_together = ("department", "head")
|
||||||
|
|
||||||
|
|
||||||
|
class Specialty(models.Model):
|
||||||
|
name = models.CharField(max_length=200, verbose_name="Название специальности")
|
||||||
|
code = models.CharField(max_length=20, verbose_name="Код специальности")
|
||||||
|
department = models.ForeignKey(
|
||||||
|
Department, on_delete=models.CASCADE, verbose_name="Учебное отделение"
|
||||||
|
)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.code} - {self.name}"
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = "Специальность"
|
||||||
|
verbose_name_plural = "Специальности"
|
||||||
|
|
||||||
|
|
||||||
|
class Group(models.Model):
|
||||||
|
name = models.CharField(max_length=20, verbose_name="Название группы")
|
||||||
|
curator = models.ForeignKey(
|
||||||
|
Employee, on_delete=models.SET_NULL, null=True, blank=True, verbose_name="Куратор"
|
||||||
|
)
|
||||||
|
specialty = models.ForeignKey(
|
||||||
|
Specialty, on_delete=models.CASCADE, verbose_name="Специальность"
|
||||||
|
)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = "Группа"
|
||||||
|
verbose_name_plural = "Группы"
|
||||||
|
|
||||||
|
|
||||||
|
class Student(ContactMixin):
|
||||||
|
group = models.ForeignKey(
|
||||||
|
Group, on_delete=models.CASCADE, verbose_name="Группа"
|
||||||
|
)
|
||||||
|
account = models.OneToOneField(
|
||||||
|
Account, on_delete=models.CASCADE, unique=True, verbose_name="Аккаунт"
|
||||||
|
)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.last_name} {self.first_name} - {self.group}"
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = "Студент"
|
||||||
|
verbose_name_plural = "Студенты"
|
||||||
|
|
||||||
3
education/tests.py
Normal file
3
education/tests.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
||||||
3
education/views.py
Normal file
3
education/views.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from django.shortcuts import render
|
||||||
|
|
||||||
|
# Create your views here.
|
||||||
0
employees/__init__.py
Normal file
0
employees/__init__.py
Normal file
3
employees/admin.py
Normal file
3
employees/admin.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
# Register your models here.
|
||||||
6
employees/apps.py
Normal file
6
employees/apps.py
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class EmployeesConfig(AppConfig):
|
||||||
|
default_auto_field = 'django.db.models.BigAutoField'
|
||||||
|
name = 'employees'
|
||||||
51
employees/migrations/0001_initial.py
Normal file
51
employees/migrations/0001_initial.py
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
# Generated by Django 4.2.21 on 2025-05-18 18:14
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Department',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=100, verbose_name='Название подразделения')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Подразделение',
|
||||||
|
'verbose_name_plural': 'Подразделения',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Employee',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('first_name', models.CharField(max_length=100, verbose_name='Имя')),
|
||||||
|
('last_name', models.CharField(blank=True, max_length=100, null=True, verbose_name='Фамилия')),
|
||||||
|
('middle_name', models.CharField(blank=True, max_length=100, null=True, verbose_name='Отчество')),
|
||||||
|
('phone', models.CharField(blank=True, max_length=20, null=True, verbose_name='Телефон')),
|
||||||
|
('email', models.EmailField(blank=True, max_length=254, null=True, verbose_name='Почта')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Сотрудник',
|
||||||
|
'verbose_name_plural': 'Сотрудники',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Position',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=100, verbose_name='Название должности')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Должность',
|
||||||
|
'verbose_name_plural': 'Должности',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
33
employees/migrations/0002_initial.py
Normal file
33
employees/migrations/0002_initial.py
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# Generated by Django 4.2.21 on 2025-05-18 18:14
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('employees', '0001_initial'),
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='employee',
|
||||||
|
name='account',
|
||||||
|
field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Аккаунт'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='employee',
|
||||||
|
name='department',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='employees.department', verbose_name='Подразделение'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='employee',
|
||||||
|
name='position',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='employees.position', verbose_name='Должность'),
|
||||||
|
),
|
||||||
|
]
|
||||||
0
employees/migrations/__init__.py
Normal file
0
employees/migrations/__init__.py
Normal file
45
employees/models.py
Normal file
45
employees/models.py
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
from django.db import models
|
||||||
|
from core.models import ContactMixin # Предполагается, что ContactMixin находится в приложении core
|
||||||
|
|
||||||
|
## Учет сотрудников (название приложения: employees)
|
||||||
|
|
||||||
|
class Position(models.Model):
|
||||||
|
name = models.CharField(max_length=100, verbose_name="Название должности")
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = "Должность"
|
||||||
|
verbose_name_plural = "Должности"
|
||||||
|
|
||||||
|
|
||||||
|
class Department(models.Model):
|
||||||
|
name = models.CharField(max_length=100, verbose_name="Название подразделения")
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = "Подразделение"
|
||||||
|
verbose_name_plural = "Подразделения"
|
||||||
|
|
||||||
|
|
||||||
|
class Employee(ContactMixin):
|
||||||
|
department = models.ForeignKey(
|
||||||
|
Department, on_delete=models.CASCADE, verbose_name="Подразделение"
|
||||||
|
)
|
||||||
|
position = models.ForeignKey(
|
||||||
|
Position, on_delete=models.SET_NULL, null=True, blank=True, verbose_name="Должность"
|
||||||
|
)
|
||||||
|
account = models.OneToOneField(
|
||||||
|
"users.Account", on_delete=models.CASCADE, unique=True, verbose_name="Аккаунт"
|
||||||
|
)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.last_name} {self.first_name} - {self.position}"
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = "Сотрудник"
|
||||||
|
verbose_name_plural = "Сотрудники"
|
||||||
|
|
||||||
3
employees/tests.py
Normal file
3
employees/tests.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
||||||
3
employees/views.py
Normal file
3
employees/views.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from django.shortcuts import render
|
||||||
|
|
||||||
|
# Create your views here.
|
||||||
0
events/__init__.py
Normal file
0
events/__init__.py
Normal file
3
events/admin.py
Normal file
3
events/admin.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
# Register your models here.
|
||||||
6
events/apps.py
Normal file
6
events/apps.py
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class EventsConfig(AppConfig):
|
||||||
|
default_auto_field = 'django.db.models.BigAutoField'
|
||||||
|
name = 'events'
|
||||||
125
events/migrations/0001_initial.py
Normal file
125
events/migrations/0001_initial.py
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
# Generated by Django 4.2.21 on 2025-05-18 18:14
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('employees', '0001_initial'),
|
||||||
|
('education', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='ActivityType',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=100, verbose_name='Название вида деятельности')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Деятельность мероприятия',
|
||||||
|
'verbose_name_plural': 'Деятельности мероприятий',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Event',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=200, verbose_name='Название')),
|
||||||
|
('location', models.CharField(blank=True, max_length=255, null=True, verbose_name='Место проведения')),
|
||||||
|
('date', models.DateField(verbose_name='Дата проведения')),
|
||||||
|
('description', models.TextField(blank=True, null=True, verbose_name='Описание')),
|
||||||
|
('academic_year', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='education.academicyear', verbose_name='Учебный год')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Мероприятие',
|
||||||
|
'verbose_name_plural': 'Мероприятия',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='EventStatus',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=100, verbose_name='Название статуса')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Статус проведения',
|
||||||
|
'verbose_name_plural': 'Статусы проведения',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='MethodicalFile',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=200, verbose_name='Название')),
|
||||||
|
('file_path', models.FileField(max_length=500, upload_to='', verbose_name='Файл')),
|
||||||
|
('upload_date', models.DateField(auto_now_add=True, verbose_name='Дата добавления')),
|
||||||
|
('employee', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='employees.employee', verbose_name='Сотрудник')),
|
||||||
|
('specialty', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='education.specialty', verbose_name='Специальность')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Методический файл',
|
||||||
|
'verbose_name_plural': 'Методические файлы',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='RelevantMethodicalFile',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('activity_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='events.activitytype', verbose_name='Вид деятельности')),
|
||||||
|
('methodical_file', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='events.methodicalfile', verbose_name='Методический файл')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Релевантный методический файл',
|
||||||
|
'verbose_name_plural': 'Релевантные методические файлы',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='EventParticipant',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('points', models.PositiveIntegerField(blank=True, default=0, verbose_name='Баллы за участие')),
|
||||||
|
('event', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='events.event', verbose_name='Мероприятие')),
|
||||||
|
('student', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='education.student', verbose_name='Студент')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Участник мероприятия',
|
||||||
|
'verbose_name_plural': 'Участники мероприятий',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='event',
|
||||||
|
name='status',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='events.eventstatus', verbose_name='Статус мероприятия'),
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='EventOrganizer',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('employee', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='employees.employee', verbose_name='Сотрудник-организатор')),
|
||||||
|
('event', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='events.event', verbose_name='Мероприятие')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Организатор мероприятия',
|
||||||
|
'verbose_name_plural': 'Организаторы мероприятий',
|
||||||
|
'unique_together': {('employee', 'event')},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='EventDetail',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('activity_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='events.activitytype', verbose_name='Вид деятельности')),
|
||||||
|
('event', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='events.event', verbose_name='Мероприятие')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Деталь мероприятия',
|
||||||
|
'verbose_name_plural': 'Детали мероприятий',
|
||||||
|
'unique_together': {('activity_type', 'event')},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
0
events/migrations/__init__.py
Normal file
0
events/migrations/__init__.py
Normal file
133
events/models.py
Normal file
133
events/models.py
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
from django.db import models
|
||||||
|
from education.models import AcademicYear, Specialty, Student # Предполагается, что модели находятся в приложении education
|
||||||
|
from employees.models import Employee # Предполагается, что модель Employee находится в приложении employees
|
||||||
|
|
||||||
|
## Учет мероприятий (название приложения: events)
|
||||||
|
|
||||||
|
class EventStatus(models.Model):
|
||||||
|
name = models.CharField(max_length=100, verbose_name="Название статуса")
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = "Статус проведения"
|
||||||
|
verbose_name_plural = "Статусы проведения"
|
||||||
|
|
||||||
|
|
||||||
|
class ActivityType(models.Model):
|
||||||
|
name = models.CharField(max_length=100, verbose_name="Название вида деятельности")
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = "Деятельность мероприятия"
|
||||||
|
verbose_name_plural = "Деятельности мероприятий"
|
||||||
|
|
||||||
|
|
||||||
|
class Event(models.Model):
|
||||||
|
academic_year = models.ForeignKey(
|
||||||
|
AcademicYear, on_delete=models.CASCADE, verbose_name="Учебный год"
|
||||||
|
)
|
||||||
|
status = models.ForeignKey(
|
||||||
|
EventStatus, on_delete=models.SET_NULL, null=True, blank=True, verbose_name="Статус мероприятия"
|
||||||
|
)
|
||||||
|
name = models.CharField(max_length=200, verbose_name="Название")
|
||||||
|
location = models.CharField(max_length=255, blank=True, null=True, verbose_name="Место проведения")
|
||||||
|
date = models.DateField(verbose_name="Дата проведения")
|
||||||
|
description = models.TextField(blank=True, null=True, verbose_name="Описание")
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.name} ({self.date})"
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = "Мероприятие"
|
||||||
|
verbose_name_plural = "Мероприятия"
|
||||||
|
|
||||||
|
|
||||||
|
class EventOrganizer(models.Model):
|
||||||
|
employee = models.ForeignKey(
|
||||||
|
Employee, on_delete=models.CASCADE, verbose_name="Сотрудник-организатор"
|
||||||
|
)
|
||||||
|
event = models.ForeignKey(
|
||||||
|
Event, on_delete=models.CASCADE, verbose_name="Мероприятие"
|
||||||
|
)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.employee} - {self.event}"
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = "Организатор мероприятия"
|
||||||
|
verbose_name_plural = "Организаторы мероприятий"
|
||||||
|
unique_together = ("employee", "event")
|
||||||
|
|
||||||
|
|
||||||
|
class EventDetail(models.Model):
|
||||||
|
activity_type = models.ForeignKey(
|
||||||
|
ActivityType, on_delete=models.CASCADE, verbose_name="Вид деятельности"
|
||||||
|
)
|
||||||
|
event = models.ForeignKey(
|
||||||
|
Event, on_delete=models.CASCADE, verbose_name="Мероприятие"
|
||||||
|
)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.activity_type} - {self.event}"
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = "Деталь мероприятия"
|
||||||
|
verbose_name_plural = "Детали мероприятий"
|
||||||
|
unique_together = ("activity_type", "event")
|
||||||
|
|
||||||
|
|
||||||
|
class EventParticipant(models.Model):
|
||||||
|
student = models.ForeignKey(
|
||||||
|
Student, on_delete=models.CASCADE, verbose_name="Студент"
|
||||||
|
)
|
||||||
|
event = models.ForeignKey(
|
||||||
|
Event, on_delete=models.CASCADE, verbose_name="Мероприятие"
|
||||||
|
)
|
||||||
|
points = models.PositiveIntegerField(blank=True, default=0, verbose_name="Баллы за участие")
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.student} - {self.event}"
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = "Участник мероприятия"
|
||||||
|
verbose_name_plural = "Участники мероприятий"
|
||||||
|
|
||||||
|
|
||||||
|
class MethodicalFile(models.Model):
|
||||||
|
specialty = models.ForeignKey(
|
||||||
|
Specialty, on_delete=models.CASCADE, verbose_name="Специальность"
|
||||||
|
)
|
||||||
|
name = models.CharField(max_length=200, verbose_name="Название")
|
||||||
|
file_path = models.FileField(max_length=500, verbose_name="Файл")
|
||||||
|
upload_date = models.DateField(auto_now_add=True, verbose_name="Дата добавления")
|
||||||
|
employee = models.ForeignKey(
|
||||||
|
Employee, on_delete=models.SET_NULL, null=True, blank=True, verbose_name="Сотрудник"
|
||||||
|
)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.name} ({self.specialty})"
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = "Методический файл"
|
||||||
|
verbose_name_plural = "Методические файлы"
|
||||||
|
|
||||||
|
|
||||||
|
class RelevantMethodicalFile(models.Model):
|
||||||
|
methodical_file = models.ForeignKey(
|
||||||
|
MethodicalFile, on_delete=models.CASCADE, verbose_name="Методический файл"
|
||||||
|
)
|
||||||
|
activity_type = models.ForeignKey(
|
||||||
|
ActivityType, on_delete=models.CASCADE, verbose_name="Вид деятельности"
|
||||||
|
)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.methodical_file} - {self.activity_type}"
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = "Релевантный методический файл"
|
||||||
|
verbose_name_plural = "Релевантные методические файлы"
|
||||||
|
|
||||||
3
events/tests.py
Normal file
3
events/tests.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
||||||
3
events/views.py
Normal file
3
events/views.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from django.shortcuts import render
|
||||||
|
|
||||||
|
# Create your views here.
|
||||||
0
outreach/__init__.py
Normal file
0
outreach/__init__.py
Normal file
3
outreach/admin.py
Normal file
3
outreach/admin.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
# Register your models here.
|
||||||
6
outreach/apps.py
Normal file
6
outreach/apps.py
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class OutreachConfig(AppConfig):
|
||||||
|
default_auto_field = 'django.db.models.BigAutoField'
|
||||||
|
name = 'outreach'
|
||||||
96
outreach/migrations/0001_initial.py
Normal file
96
outreach/migrations/0001_initial.py
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
# Generated by Django 4.2.21 on 2025-05-18 18:14
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('employees', '0001_initial'),
|
||||||
|
('education', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='InstitutionType',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=50, verbose_name='Название вида учебного заведения')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Вид учебного заведения',
|
||||||
|
'verbose_name_plural': 'Виды учебных заведений',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Partner',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=200, verbose_name='Название')),
|
||||||
|
('description', models.TextField(blank=True, null=True, verbose_name='Описание')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Партнер',
|
||||||
|
'verbose_name_plural': 'Партнеры',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Representative',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('first_name', models.CharField(max_length=100, verbose_name='Имя')),
|
||||||
|
('last_name', models.CharField(blank=True, max_length=100, null=True, verbose_name='Фамилия')),
|
||||||
|
('middle_name', models.CharField(blank=True, max_length=100, null=True, verbose_name='Отчество')),
|
||||||
|
('phone', models.CharField(blank=True, max_length=20, null=True, verbose_name='Телефон')),
|
||||||
|
('email', models.EmailField(blank=True, max_length=254, null=True, verbose_name='Почта')),
|
||||||
|
('position', models.CharField(blank=True, max_length=100, null=True, verbose_name='Должность')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Представитель',
|
||||||
|
'verbose_name_plural': 'Представители',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='School',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=200, verbose_name='Название')),
|
||||||
|
('address', models.CharField(max_length=300, verbose_name='Адрес')),
|
||||||
|
('director', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='outreach.representative', verbose_name='Директор')),
|
||||||
|
('institution_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='outreach.institutiontype', verbose_name='Вид учебного заведения')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Школа',
|
||||||
|
'verbose_name_plural': 'Школы',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='SchoolResponsibility',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('academic_year', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='education.academicyear', verbose_name='Учебный год')),
|
||||||
|
('responsible', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='employees.employee', verbose_name='Ответственный сотрудник')),
|
||||||
|
('school', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='outreach.school', verbose_name='Школа')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Ответственный за школу',
|
||||||
|
'verbose_name_plural': 'Ответственные за школы',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='PartnerRepresentative',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('partner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='outreach.partner', verbose_name='Партнер')),
|
||||||
|
('representative', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='outreach.representative', verbose_name='Представитель')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Представитель партнера',
|
||||||
|
'verbose_name_plural': 'Представители партнеров',
|
||||||
|
'unique_together': {('representative', 'partner')},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
0
outreach/migrations/__init__.py
Normal file
0
outreach/migrations/__init__.py
Normal file
94
outreach/models.py
Normal file
94
outreach/models.py
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
from django.db import models
|
||||||
|
from core.models import ContactMixin # Предполагается, что ContactMixin находится в приложении core
|
||||||
|
from education.models import AcademicYear # Предполагается, что AcademicYear находится в приложении education
|
||||||
|
from employees.models import Employee # Предполагается, что модель Employee находится в приложении employees
|
||||||
|
|
||||||
|
## Профориентационная деятельность (название приложения: outreach)
|
||||||
|
|
||||||
|
class InstitutionType(models.Model):
|
||||||
|
name = models.CharField(max_length=50, verbose_name="Название вида учебного заведения")
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = "Вид учебного заведения"
|
||||||
|
verbose_name_plural = "Виды учебных заведений"
|
||||||
|
|
||||||
|
|
||||||
|
class Representative(ContactMixin):
|
||||||
|
position = models.CharField(max_length=100, blank=True, null=True, verbose_name="Должность")
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.last_name} {self.first_name} - {self.position}"
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = "Представитель"
|
||||||
|
verbose_name_plural = "Представители"
|
||||||
|
|
||||||
|
|
||||||
|
class School(models.Model):
|
||||||
|
director = models.ForeignKey(
|
||||||
|
Representative, on_delete=models.SET_NULL, null=True, blank=True, verbose_name="Директор"
|
||||||
|
)
|
||||||
|
institution_type = models.ForeignKey(
|
||||||
|
InstitutionType, on_delete=models.CASCADE, verbose_name="Вид учебного заведения"
|
||||||
|
)
|
||||||
|
name = models.CharField(max_length=200, verbose_name="Название")
|
||||||
|
address = models.CharField(max_length=300, verbose_name="Адрес")
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.name} ({self.institution_type})"
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = "Школа"
|
||||||
|
verbose_name_plural = "Школы"
|
||||||
|
|
||||||
|
|
||||||
|
class Partner(models.Model):
|
||||||
|
name = models.CharField(max_length=200, verbose_name="Название")
|
||||||
|
description = models.TextField(blank=True, null=True, verbose_name="Описание")
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = "Партнер"
|
||||||
|
verbose_name_plural = "Партнеры"
|
||||||
|
|
||||||
|
|
||||||
|
class PartnerRepresentative(models.Model):
|
||||||
|
representative = models.OneToOneField(
|
||||||
|
Representative, on_delete=models.CASCADE, verbose_name="Представитель"
|
||||||
|
)
|
||||||
|
partner = models.ForeignKey(
|
||||||
|
Partner, on_delete=models.CASCADE, verbose_name="Партнер"
|
||||||
|
)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.representative} - {self.partner}"
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = "Представитель партнера"
|
||||||
|
verbose_name_plural = "Представители партнеров"
|
||||||
|
unique_together = ("representative", "partner")
|
||||||
|
|
||||||
|
|
||||||
|
class SchoolResponsibility(models.Model):
|
||||||
|
academic_year = models.ForeignKey(
|
||||||
|
AcademicYear, on_delete=models.CASCADE, verbose_name="Учебный год"
|
||||||
|
)
|
||||||
|
responsible = models.ForeignKey(
|
||||||
|
Employee, on_delete=models.CASCADE, verbose_name="Ответственный сотрудник"
|
||||||
|
)
|
||||||
|
school = models.ForeignKey(
|
||||||
|
School, on_delete=models.CASCADE, verbose_name="Школа"
|
||||||
|
)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.responsible} - {self.school} ({self.academic_year})"
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = "Ответственный за школу"
|
||||||
|
verbose_name_plural = "Ответственные за школы"
|
||||||
|
|
||||||
3
outreach/tests.py
Normal file
3
outreach/tests.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
||||||
3
outreach/views.py
Normal file
3
outreach/views.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from django.shortcuts import render
|
||||||
|
|
||||||
|
# Create your views here.
|
||||||
0
surveys/__init__.py
Normal file
0
surveys/__init__.py
Normal file
3
surveys/admin.py
Normal file
3
surveys/admin.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
# Register your models here.
|
||||||
6
surveys/apps.py
Normal file
6
surveys/apps.py
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class SurveysConfig(AppConfig):
|
||||||
|
default_auto_field = 'django.db.models.BigAutoField'
|
||||||
|
name = 'surveys'
|
||||||
143
surveys/migrations/0001_initial.py
Normal file
143
surveys/migrations/0001_initial.py
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
# Generated by Django 4.2.21 on 2025-05-18 18:14
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='EducationalInstitution',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=256, verbose_name='Название учреждения')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Образовательное учреждение',
|
||||||
|
'verbose_name_plural': 'Образовательные учреждения',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Profession',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=256, verbose_name='Название профессии')),
|
||||||
|
('description', models.TextField(blank=True, null=True, verbose_name='Описание')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Профессия',
|
||||||
|
'verbose_name_plural': 'Профессии',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='ScoreVariable',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=30, verbose_name='Имя переменной')),
|
||||||
|
('title', models.CharField(max_length=70, verbose_name='Название переменной')),
|
||||||
|
('description', models.TextField(verbose_name='Описание')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Переменная оценки',
|
||||||
|
'verbose_name_plural': 'Переменные оценки',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Survey',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('title', models.CharField(max_length=70, verbose_name='Название опроса')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Опрос',
|
||||||
|
'verbose_name_plural': 'Опросы',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Statement',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('statement', models.CharField(max_length=256, verbose_name='Утверждение')),
|
||||||
|
('score_variable', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='surveys.scorevariable', verbose_name='Переменная оценки')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Утверждение',
|
||||||
|
'verbose_name_plural': 'Утверждения',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Specialty',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=256, verbose_name='Название специальности')),
|
||||||
|
('link', models.URLField(blank=True, null=True, verbose_name='Ссылка')),
|
||||||
|
('institution', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='surveys.educationalinstitution', verbose_name='Образовательное учреждение')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Специальность',
|
||||||
|
'verbose_name_plural': 'Специальности',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='scorevariable',
|
||||||
|
name='survey',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='surveys.survey', verbose_name='Опрос'),
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='QuestionPair',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('statement_a', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='pair_a', to='surveys.statement', verbose_name='Утверждение A')),
|
||||||
|
('statement_b', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='pair_b', to='surveys.statement', verbose_name='Утверждение B')),
|
||||||
|
('survey', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='surveys.survey', verbose_name='Опрос')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Пара вопросов',
|
||||||
|
'verbose_name_plural': 'Пары вопросов',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='ProfessionTestResult',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('profession', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='surveys.profession', verbose_name='Профессия')),
|
||||||
|
('survey_score_variable', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='surveys.scorevariable', verbose_name='Переменная оценки')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Результат теста по профессии',
|
||||||
|
'verbose_name_plural': 'Результаты тестов по профессиям',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='AgreementQuestion',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('question', models.CharField(max_length=256, verbose_name='Вопрос')),
|
||||||
|
('score_variable', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='surveys.scorevariable', verbose_name='Переменная оценки')),
|
||||||
|
('survey', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='surveys.survey', verbose_name='Опрос')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Вопрос на согласие',
|
||||||
|
'verbose_name_plural': 'Вопросы на согласие',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='ProfessionSpecialtyLink',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('profession', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='surveys.profession', verbose_name='Профессия')),
|
||||||
|
('specialty', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='surveys.specialty', verbose_name='Специальность')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Связь между профессией и специальностью',
|
||||||
|
'verbose_name_plural': 'Связи между профессиями и специальностями',
|
||||||
|
'unique_together': {('profession', 'specialty')},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
0
surveys/migrations/__init__.py
Normal file
0
surveys/migrations/__init__.py
Normal file
151
surveys/models.py
Normal file
151
surveys/models.py
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
from django.db import models
|
||||||
|
|
||||||
|
## Модуль Анкетирование (название приложения: surveys)
|
||||||
|
|
||||||
|
class Survey(models.Model):
|
||||||
|
title = models.CharField(max_length=70, verbose_name="Название опроса")
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.title
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = "Опрос"
|
||||||
|
verbose_name_plural = "Опросы"
|
||||||
|
|
||||||
|
|
||||||
|
class ScoreVariable(models.Model):
|
||||||
|
name = models.CharField(max_length=30, verbose_name="Имя переменной")
|
||||||
|
title = models.CharField(max_length=70, verbose_name="Название переменной")
|
||||||
|
description = models.TextField(verbose_name="Описание")
|
||||||
|
survey = models.ForeignKey(
|
||||||
|
Survey, on_delete=models.CASCADE, verbose_name="Опрос"
|
||||||
|
)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.title} ({self.survey})"
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = "Переменная оценки"
|
||||||
|
verbose_name_plural = "Переменные оценки"
|
||||||
|
|
||||||
|
|
||||||
|
class Statement(models.Model):
|
||||||
|
statement = models.CharField(max_length=256, verbose_name="Утверждение")
|
||||||
|
score_variable = models.ForeignKey(
|
||||||
|
ScoreVariable, on_delete=models.SET_NULL, blank=True, null=True, verbose_name="Переменная оценки"
|
||||||
|
)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.statement
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = "Утверждение"
|
||||||
|
verbose_name_plural = "Утверждения"
|
||||||
|
|
||||||
|
|
||||||
|
class QuestionPair(models.Model):
|
||||||
|
survey = models.ForeignKey(
|
||||||
|
Survey, on_delete=models.CASCADE, verbose_name="Опрос"
|
||||||
|
)
|
||||||
|
statement_a = models.OneToOneField(
|
||||||
|
Statement, on_delete=models.CASCADE, related_name="pair_a", verbose_name="Утверждение A"
|
||||||
|
)
|
||||||
|
statement_b = models.OneToOneField(
|
||||||
|
Statement, on_delete=models.CASCADE, related_name="pair_b", verbose_name="Утверждение B"
|
||||||
|
)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"Пара: {self.statement_a} - {self.statement_b}"
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = "Пара вопросов"
|
||||||
|
verbose_name_plural = "Пары вопросов"
|
||||||
|
|
||||||
|
|
||||||
|
class AgreementQuestion(models.Model):
|
||||||
|
survey = models.ForeignKey(
|
||||||
|
Survey, on_delete=models.CASCADE, verbose_name="Опрос"
|
||||||
|
)
|
||||||
|
question = models.CharField(max_length=256, verbose_name="Вопрос")
|
||||||
|
score_variable = models.ForeignKey(
|
||||||
|
ScoreVariable, on_delete=models.CASCADE, verbose_name="Переменная оценки"
|
||||||
|
)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.question
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = "Вопрос на согласие"
|
||||||
|
verbose_name_plural = "Вопросы на согласие"
|
||||||
|
|
||||||
|
|
||||||
|
class EducationalInstitution(models.Model):
|
||||||
|
name = models.CharField(max_length=256, verbose_name="Название учреждения")
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = "Образовательное учреждение"
|
||||||
|
verbose_name_plural = "Образовательные учреждения"
|
||||||
|
|
||||||
|
|
||||||
|
class Profession(models.Model):
|
||||||
|
name = models.CharField(max_length=256, verbose_name="Название профессии")
|
||||||
|
description = models.TextField(blank=True, null=True, verbose_name="Описание")
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = "Профессия"
|
||||||
|
verbose_name_plural = "Профессии"
|
||||||
|
|
||||||
|
|
||||||
|
class Specialty(models.Model):
|
||||||
|
name = models.CharField(max_length=256, verbose_name="Название специальности")
|
||||||
|
institution = models.ForeignKey(
|
||||||
|
EducationalInstitution, on_delete=models.CASCADE, verbose_name="Образовательное учреждение"
|
||||||
|
)
|
||||||
|
link = models.URLField(verbose_name="Ссылка", null=True, blank=True)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.name} ({self.institution})"
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = "Специальность"
|
||||||
|
verbose_name_plural = "Специальности"
|
||||||
|
|
||||||
|
|
||||||
|
class ProfessionSpecialtyLink(models.Model):
|
||||||
|
profession = models.ForeignKey(
|
||||||
|
Profession, on_delete=models.CASCADE, verbose_name="Профессия"
|
||||||
|
)
|
||||||
|
specialty = models.ForeignKey(
|
||||||
|
Specialty, on_delete=models.CASCADE, verbose_name="Специальность"
|
||||||
|
)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.profession} - {self.specialty}"
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = "Связь между профессией и специальностью"
|
||||||
|
verbose_name_plural = "Связи между профессиями и специальностями"
|
||||||
|
unique_together = ("profession", "specialty")
|
||||||
|
|
||||||
|
|
||||||
|
class ProfessionTestResult(models.Model):
|
||||||
|
profession = models.ForeignKey(
|
||||||
|
Profession, on_delete=models.CASCADE, verbose_name="Профессия"
|
||||||
|
)
|
||||||
|
survey_score_variable = models.ForeignKey(
|
||||||
|
ScoreVariable, on_delete=models.CASCADE, verbose_name="Переменная оценки"
|
||||||
|
)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.profession} - {self.survey_score_variable}"
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = "Результат теста по профессии"
|
||||||
|
verbose_name_plural = "Результаты тестов по профессиям"
|
||||||
|
|
||||||
3
surveys/tests.py
Normal file
3
surveys/tests.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
||||||
3
surveys/views.py
Normal file
3
surveys/views.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from django.shortcuts import render
|
||||||
|
|
||||||
|
# Create your views here.
|
||||||
@@ -41,6 +41,11 @@ INSTALLED_APPS = [
|
|||||||
'django.contrib.staticfiles',
|
'django.contrib.staticfiles',
|
||||||
"core.apps.CoreConfig",
|
"core.apps.CoreConfig",
|
||||||
'users.apps.UsersConfig',
|
'users.apps.UsersConfig',
|
||||||
|
"employees.apps.EmployeesConfig",
|
||||||
|
"education.apps.EducationConfig",
|
||||||
|
"events.apps.EventsConfig",
|
||||||
|
"outreach.apps.OutreachConfig",
|
||||||
|
"surveys.apps.SurveysConfig"
|
||||||
]
|
]
|
||||||
|
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
@@ -143,4 +148,4 @@ MEDIA_ROOT = BASE_DIR / 'media'
|
|||||||
|
|
||||||
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
||||||
|
|
||||||
AUTH_USER_MODEL = "users.UserAccount"
|
AUTH_USER_MODEL = "users.Account"
|
||||||
|
|||||||
@@ -1,3 +1,85 @@
|
|||||||
|
from django import forms
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
# Register your models here.
|
from .models import Account, Role
|
||||||
|
|
||||||
|
|
||||||
|
class AccountChangeForm(forms.ModelForm):
|
||||||
|
password = forms.CharField(
|
||||||
|
label=_("Password"),
|
||||||
|
widget=forms.PasswordInput,
|
||||||
|
required=False,
|
||||||
|
help_text=_("Raw passwords are not stored, so there is no way to see this user's password.")
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Account
|
||||||
|
fields = '__all__'
|
||||||
|
|
||||||
|
def save(self, commit=True):
|
||||||
|
password = self.cleaned_data.get('password')
|
||||||
|
if password:
|
||||||
|
self.instance.set_password(password)
|
||||||
|
return super().save(commit=commit)
|
||||||
|
|
||||||
|
|
||||||
|
class AccountCreationForm(forms.ModelForm):
|
||||||
|
password1 = forms.CharField(label=_("Password"), widget=forms.PasswordInput)
|
||||||
|
password2 = forms.CharField(label=_("Password confirmation"), widget=forms.PasswordInput)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Account
|
||||||
|
fields = ('login',)
|
||||||
|
|
||||||
|
def clean_password2(self):
|
||||||
|
password1 = self.cleaned_data.get("password1")
|
||||||
|
password2 = self.cleaned_data.get("password2")
|
||||||
|
if password1 and password2 and password1 != password2:
|
||||||
|
raise forms.ValidationError(_("Passwords don't match"))
|
||||||
|
return password2
|
||||||
|
|
||||||
|
def save(self, commit=True):
|
||||||
|
user = super().save(commit=False)
|
||||||
|
user.set_password(self.cleaned_data["password1"])
|
||||||
|
if commit:
|
||||||
|
user.save()
|
||||||
|
return user
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(Account)
|
||||||
|
class AccountAdmin(BaseUserAdmin):
|
||||||
|
form = AccountChangeForm
|
||||||
|
add_form = AccountCreationForm
|
||||||
|
|
||||||
|
list_display = ('login', 'full_name', 'role', 'is_staff', 'is_active')
|
||||||
|
list_filter = ('is_staff', 'is_active', 'role')
|
||||||
|
search_fields = ('login', 'first_name', 'last_name', 'middle_name', 'phone', 'email')
|
||||||
|
ordering = ('login',)
|
||||||
|
filter_horizontal = ('groups', 'user_permissions')
|
||||||
|
|
||||||
|
fieldsets = (
|
||||||
|
(None, {'fields': ('login', 'password')}),
|
||||||
|
(_('Personal info'), {'fields': ('first_name', 'last_name', 'middle_name', 'phone', 'email')}),
|
||||||
|
(_('Permissions'), {
|
||||||
|
'fields': ('is_active', 'is_staff', 'is_superuser', 'groups', 'user_permissions'),
|
||||||
|
}),
|
||||||
|
(_('Role'), {'fields': ('role',)}),
|
||||||
|
)
|
||||||
|
add_fieldsets = (
|
||||||
|
(None, {
|
||||||
|
'classes': ('wide',),
|
||||||
|
'fields': ('login', 'password1', 'password2'),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
@admin.display(description=_('Full name'))
|
||||||
|
def full_name(self, obj):
|
||||||
|
return str(obj)
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(Role)
|
||||||
|
class RoleAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ('name',)
|
||||||
|
search_fields = ('name',)
|
||||||
@@ -4,3 +4,4 @@ from django.apps import AppConfig
|
|||||||
class UsersConfig(AppConfig):
|
class UsersConfig(AppConfig):
|
||||||
default_auto_field = 'django.db.models.BigAutoField'
|
default_auto_field = 'django.db.models.BigAutoField'
|
||||||
name = 'users'
|
name = 'users'
|
||||||
|
verbose_name = "Пользователи"
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Generated by Django 4.2.21 on 2025-05-14 16:31
|
# Generated by Django 4.2.21 on 2025-05-18 18:21
|
||||||
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
@@ -17,35 +17,35 @@ class Migration(migrations.Migration):
|
|||||||
name='Role',
|
name='Role',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
('name', models.CharField(max_length=20, unique=True, verbose_name='Название роли')),
|
('name', models.CharField(max_length=100, verbose_name='Название роли')),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'Роль',
|
'verbose_name': 'Роль пользователя',
|
||||||
'verbose_name_plural': 'Роли',
|
'verbose_name_plural': 'Роли пользователей',
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='UserAccount',
|
name='Account',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
('password', models.CharField(max_length=128, verbose_name='password')),
|
('password', models.CharField(max_length=128, verbose_name='password')),
|
||||||
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
|
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
|
||||||
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
|
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
|
||||||
('first_name', models.CharField(max_length=100, verbose_name='Имя')),
|
('first_name', models.CharField(max_length=100, verbose_name='Имя')),
|
||||||
('last_name', models.CharField(max_length=100, verbose_name='Фамилия')),
|
('last_name', models.CharField(blank=True, max_length=100, null=True, verbose_name='Фамилия')),
|
||||||
('middle_name', models.CharField(blank=True, max_length=100, null=True, verbose_name='Отчество')),
|
('middle_name', models.CharField(blank=True, max_length=100, null=True, verbose_name='Отчество')),
|
||||||
('phone', models.CharField(blank=True, max_length=20, null=True, verbose_name='Телефон')),
|
('phone', models.CharField(blank=True, max_length=20, null=True, verbose_name='Телефон')),
|
||||||
('email', models.EmailField(blank=True, max_length=254, null=True, verbose_name='Почта')),
|
('email', models.EmailField(blank=True, max_length=254, null=True, verbose_name='Почта')),
|
||||||
('username', models.CharField(max_length=150, unique=True, verbose_name='Имя пользователя')),
|
('login', models.CharField(max_length=150, unique=True, verbose_name='Логин')),
|
||||||
('is_active', models.BooleanField(default=True, verbose_name='Активен')),
|
|
||||||
('is_staff', models.BooleanField(default=False, verbose_name='Сотрудник')),
|
('is_staff', models.BooleanField(default=False, verbose_name='Сотрудник')),
|
||||||
|
('is_active', models.BooleanField(default=True, verbose_name='Активен')),
|
||||||
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')),
|
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')),
|
||||||
('role', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='users.role', verbose_name='Роль')),
|
('role', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='users.role', verbose_name='Роль пользователя')),
|
||||||
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')),
|
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'Пользователь',
|
'verbose_name': 'Аккаунт',
|
||||||
'verbose_name_plural': 'Пользователи',
|
'verbose_name_plural': 'Аккаунты',
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,48 +1,54 @@
|
|||||||
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin
|
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
from core.mixins import ContactMixin
|
from core.models import ContactMixin
|
||||||
|
|
||||||
|
|
||||||
|
## Пользователи
|
||||||
|
|
||||||
class Role(models.Model):
|
class Role(models.Model):
|
||||||
name = models.CharField(max_length=20, unique=True, verbose_name='Название роли')
|
name = models.CharField(max_length=100, verbose_name="Название роли")
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = 'Роль'
|
verbose_name = "Роль пользователя"
|
||||||
verbose_name_plural = 'Роли'
|
verbose_name_plural = "Роли пользователей"
|
||||||
|
|
||||||
class UserAccountManager(BaseUserManager):
|
|
||||||
def create_user(self, username, password=None, role=None, **extra_fields):
|
class AccountManager(BaseUserManager):
|
||||||
if not username:
|
def create_user(self, login, password=None, **extra_fields):
|
||||||
raise ValueError('Имя пользователя должно быть указано')
|
if not login:
|
||||||
user = self.model(username=username, role=role, **extra_fields)
|
raise ValueError("Login must be set")
|
||||||
|
user = self.model(login=login, **extra_fields)
|
||||||
user.set_password(password)
|
user.set_password(password)
|
||||||
user.save(using=self._db)
|
user.save(using=self._db)
|
||||||
return user
|
return user
|
||||||
|
|
||||||
def create_superuser(self, username, password=None, **extra_fields):
|
def create_superuser(self, login, password=None, **extra_fields):
|
||||||
admin_role, _ = Role.objects.get_or_create(name='admin')
|
extra_fields.setdefault("is_staff", True)
|
||||||
extra_fields.setdefault('is_staff', True)
|
extra_fields.setdefault("is_superuser", True)
|
||||||
extra_fields.setdefault('is_superuser', True)
|
return self.create_user(login, password, **extra_fields)
|
||||||
return self.create_user(username, password, role=admin_role, **extra_fields)
|
|
||||||
|
|
||||||
class UserAccount(ContactMixin, AbstractBaseUser, PermissionsMixin):
|
|
||||||
username = models.CharField(max_length=150, unique=True, verbose_name='Имя пользователя')
|
|
||||||
role = models.ForeignKey(Role, on_delete=models.SET_NULL, null=True, blank=True, verbose_name='Роль')
|
|
||||||
is_active = models.BooleanField(default=True, verbose_name='Активен')
|
|
||||||
is_staff = models.BooleanField(default=False, verbose_name='Сотрудник')
|
|
||||||
|
|
||||||
objects = UserAccountManager()
|
class Account(ContactMixin, AbstractBaseUser, PermissionsMixin):
|
||||||
|
login = models.CharField(max_length=150, unique=True, verbose_name="Логин")
|
||||||
|
role = models.ForeignKey(
|
||||||
|
Role, on_delete=models.SET_NULL, null=True, blank=True, verbose_name="Роль пользователя"
|
||||||
|
)
|
||||||
|
is_staff = models.BooleanField(default=False, verbose_name="Сотрудник")
|
||||||
|
is_active = models.BooleanField(default=True, verbose_name="Активен")
|
||||||
|
|
||||||
USERNAME_FIELD = 'username'
|
USERNAME_FIELD = "login"
|
||||||
REQUIRED_FIELDS = []
|
REQUIRED_FIELDS = []
|
||||||
|
|
||||||
|
objects = AccountManager()
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.username+" ("+ContactMixin.__str__(self)+")"
|
return self.login
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = 'Пользователь'
|
verbose_name = "Аккаунт"
|
||||||
verbose_name_plural = 'Пользователи'
|
verbose_name_plural = "Аккаунты"
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user