Модели
Нам необходимо описать БД средствами Django ORM, для этого перейдём в файл models.py
в наших приложениях и
создадим несколько классов, наследуемых от django.db.models.Model
.
Также внутри каждого класса создадим мета-класс с 3 полями:
db_table
- название таблицы в БД;verbose_name
- человекочитаемое название объекта;verbose_name_plural
- человекочитаемое название во множественном числе.
Кроме того, переопределим дандер-метод __str__
в каждом классе, чтобы объекты имели более понятное текстовое представление.
from django.db import models
class Adapter(models.Model):
class Meta:
db_table = "adapter"
verbose_name = "адаптер"
verbose_name_plural = "адаптеры"
first_name = models.CharField(max_length=50, verbose_name="Имя")
last_name = models.CharField(max_length=50, verbose_name="Фамилия")
def __str__(self):
return f"{self.last_name} {self.first_name}"
В этой модели определим только два текстовых поля: фамилию и имя. Остальная информация этого приложения уже имеется на проде, и она не нужна для работы опроса.
from django.contrib.auth.models import User
from django.db import models
class ItmoIdProfile(models.Model):
class Meta:
db_table = "itmo_id_profile"
verbose_name = "профиль ITMO.ID"
verbose_name_plural = "профили ITMO.ID"
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="profile", verbose_name="Пользователь")
isu = models.PositiveIntegerField(null=True, blank=True, verbose_name="ИСУ")
course = models.PositiveSmallIntegerField(null=True, blank=True, verbose_name="Курс")
faculty = models.CharField(blank=True, max_length=50, verbose_name="Факультет")
group = models.CharField(blank=True, max_length=7, verbose_name="Группа")
def __str__(self):
return f"{self.user.last_name} {self.user.first_name} {'(' + str(self.isu) + ')' if self.isu else ''}"
В этой модели определим O2O связь к встроенной модели auth.User, чтобы расширить её дополнительной необязательной информацией. Здесь будет храниться необходимая информация, полученная с ITMO.ID.
from django.db import models
class SurveyGroup(models.Model):
class Meta:
db_table = "survey_group"
verbose_name = "группа"
verbose_name_plural = "группы"
name = models.CharField(max_length=7, verbose_name="Название")
students_count = models.PositiveSmallIntegerField(null=True, blank=True, verbose_name="Количество студентов")
adapters = models.ManyToManyField("adapter.Adapter", blank=True, related_name="groups", verbose_name="Адаптеры")
def __str__(self):
return self.name
В этой модели определим поле name
, значения которого должны совпадать с тем, что возвращает ITMO.ID, для
дальнейшего сопоставления. Также укажем поле students_count
, необходимое для дальнейшего подсчёта баллов для
каждого адаптера для оценивания на ПГАС. И привяжем с помощью M2M связи модель адаптеров так же для подсчёта
баллов и чтобы в опросе выводить только необходимых адаптеров.
from django.db import models
class SurveyFaculty(models.Model):
class Meta:
db_table = "survey_faculty"
verbose_name = "факультет"
verbose_name_plural = "факультеты"
name = models.CharField(max_length=50, verbose_name="Название")
is_active = models.BooleanField(default=False, verbose_name="Активен?")
def __str__(self):
return self.name
В этой модели определим поле name
, значения которого должны совпадать с тем, что возвращает ITMO.ID. И определим
булеое поле is_active
, на которое будем ориентироваться для постепенного открытия опроса.
from django.db import models
class SurveyQuestion(models.Model):
class Meta:
db_table = "survey_question"
verbose_name = "вопрос"
verbose_name_plural = "вопросы"
class Type(models.TextChoices):
TEXT_AREA = "text_area", "TextArea"
ADAPTER_SLIDER = "adapter_slider", "AdapterSlider"
SLIDER = "slider", "Slider"
SELECT = "select", "Select"
TRAINING_SELECT = "training_select", "TrainingSelect"
component = models.CharField(max_length=15, choices=Type.choices, verbose_name="Виджет")
text = models.CharField(max_length=200, verbose_name="Основной текст")
help_text = models.CharField(max_length=200, blank=True, verbose_name="Дополнительный текст")
training_text = models.CharField(
max_length=200,
blank=True,
verbose_name="Второй основной текст",
help_text="Используется для слайдера в TrainingSelect виджете",
)
training_help_text = models.CharField(
max_length=200,
blank=True,
verbose_name="Второй дополнительный текст",
help_text="Используется для слайдера в TrainingSelect виджете",
)
order = models.PositiveSmallIntegerField(verbose_name="Порядок")
def __str__(self):
return f"{self.component} - {self.text}"
В этой модели определим текстовое поле 'component', допустимыми значениями которого будут названия кастомных
Vue.js компонентов, вынесенные в Djang Enum - TextChoices. Благодаря этому полю фронтенд сможет понять, какой
компонент отрисовывать для каждого вопроса.
Даже добавим поля text
и help_text
для отображения надписи над компонентом крупным и мелким шрифтом, и
дополнительные поля training_text
и training_help_text
в случае использования компонента AdapterSelect, который
внутри себя создаёт два компонента, каждый из который нуждается в надписи.
Также определим поле order
, необходимое для сортировки в необходимом порядке.
from django.db import models
class SurveyAnswer(models.Model):
class Meta:
db_table = "survey_answer"
verbose_name = "ответ"
verbose_name_plural = "ответы"
user = models.ForeignKey("auth.User", on_delete=models.CASCADE, verbose_name="Пользователь", related_name="answers")
adapter = models.ForeignKey(
"adapter.Adapter", blank=True, null=True, on_delete=models.CASCADE, verbose_name="Адаптер"
)
question = models.ForeignKey(
SurveyQuestion, on_delete=models.CASCADE, verbose_name="Вопрос", related_name="answers"
)
value = models.CharField(max_length=1000, verbose_name="Ответ")
score = models.FloatField(blank=True, null=True, verbose_name="Балл")
def __str__(self):
return f"{self.value} {self.question.text}"
В этой модели укажем три внешних ключа: к встроенной модели auth.User, чтобы понимать, какой пользователь отправил
ответ, к модели Adapter, чтобы в случае компонента AdapterSlider понимать, какому именно адаптеру была поставлена оценка,
и к модели SurveyQuestion, чтобы понимать, на какой именно вопрос пришёл ответ.
Также укажем два поля для хранения значений ответов, текстовое value
, хранящее прямой ответ с "формы", и численное
score
, хранящее адаптированное значение баллов.
После создания всех моделей нужно обязательно сделать миграции:
А так же создать суперпользователя: