Проверка сложных взаимосвязей в Django

#django #django-models #relationship

Вопрос:

Я разрабатываю приложение Django, которое помогает учителям наблюдать за учениками во время уроков. Я определил модели для Lesson и Student , а FocusGroup также модель для студентов , которые будут наблюдаться во время заданного Lesson , FocusGroup Объект имеет поля для наблюдения Student за поведением Lesson . Во время этого наблюдения за выборкой студентов проводится наблюдение Lesson , и наблюдения должны быть зарегистрированы в FocusGroup полях. В рамках подготовки учителя к заданному Lesson он назначает это Lesson нескольким FocusGroup экземплярам (представляющим Student s). Теперь приложение должно гарантировать , что то же Student самое будет назначено не более одного раза заданному Lesson . Я уже делаю это в своем шаблоне, но я также хочу обеспечить уникальность на стороне сервера.

Диаграмма должна проиллюстрировать это: UML-схема взаимоотношений урока, фокус-группы и учащихсяМой вопрос в том, как я должен гарантировать Lesson , что назначается одно и то же Student не более одного раза.

Должен ли я сделать это в FocusGroup модели или в представлении получателя? И как я должен обеспечить безопасность этих отношений в Django?

Моя нынешняя реализация проверяет FocusGroup Lesson уникальность, но при FocusGroup создании новых экземпляров есть вероятность, что то же Student самое представлено несколькими FocusGroup экземплярами, назначенными для этого Lesson .

models.py

 from django.db.models.functions      import Random
from django.db                       import models
from django.db.models.fields.related import ForeignKey
from django.db.models.fields         import AutoField, BooleanField, CharField, DateField, DateTimeField, IntegerField, TextField, URLField

class Student(models.Model):
    id = models.UUIDField(
        primary_key=True, 
        default=uuid.uuid4, 
        editable=False
    )
    name = models.CharField()

class Lesson(models.Model):
    id = AutoField(primary_key=True)
    afholdt = DateField(help_text='Planlagt / faktisk dato for modulet')

class FocusGroup(models.Model):
    id = AutoField(primary_key=True)
    student = models.ForeignKey('Student', on_delete=models.RESTRICT, null=True)
    lesson = models.ForeignKey(
        'Lesson', 
        models.SET_NULL,
        blank=True, 
        null=True, 
    )
    rand_rank = models.FloatField( # Used to randomize sampling of Students
        validators=[MinValueValidator(0.0), MaxValueValidator(1.0)],
        default=Random(),
        editable=False,
        null=False
    )
    score    = IntegerField(blank=True, null=True)
 

Комментарии:

1. Модели, по-видимому, предполагают, что в каждой фокус-группе может быть только 1 студент.

2. @bdbd: Правильно, так что проверка пройдет без проблем. Проблема возникает, когда я назначил одного и того же студента нескольким экземплярам FocusGroup-проверка не поймает эту личность. Т. Е. моя модель как есть не проверяет идентификатор связанного объекта Студента (другого экземпляра FocusGroup, уже назначенного этой лекцией) при назначении лекции в FocusGroup.

3. В таком случае, я думаю, что использования UniqueConstraint будет достаточно. Итак: UniqueConstraint(fields=['student', 'lesson'], name='unique_lesson_to_student') добавлено FocusGroup . Это гарантирует, что урок будет назначен учащемуся только один раз, независимо от того, в какой фокус-группе.

4. @bdbd Выглядит хорошо. Результат здесь для обратной связи, когда я его опробую.

5. Я выполнил заявление, рекомендованное @bdbd. Затем, после запуска python manage.py makemigrations , а затем ... migrate в приложении, я действительно получаю ожидаемую реакцию (приложение выдает django.db.utils.IntegrityError: UNIQUE constraint failed: myapp_focusgroup.student_id, myapp_focusgroup.lecture_id ошибку). Сделайте это ответом, и я приму его.

Ответ №1:

В этом случае должно быть достаточно определить a UniqueConstraint , чтобы гарантировать, что учащимся будет назначен урок только один раз, независимо от фокус-группы, поэтому:

 class FocusGroup(models.Model):
    ...
    class Meta:
        constraints = [
            models.UniqueConstraint(fields=['student', 'lesson'], name='unique_lesson_to_student')
        ]