Создание отношений между студентом и классом в Django

Я пытаюсь создать модель, в которой я могу иметь отношения между таблицами Students и ClassName, чтобы я мог получить всех пользователей, используя метод ClassName.objects.get() и ClassName, используя метод Student.objects.get()? Я совсем запутался. Должен ли я добавить больше полей в модель Student?

from django.contrib.auth.models import AbstractUser
from django.db import models


# Create your models here.
class User(AbstractUser):
    pass


class ClassName(models.Model):
    grade = models.IntegerField()
    section = models.CharField(max_length=1)

    def __str__(self):
        return f"{self.grade} - {self.section}"


class Student(models.Model):
    first_name = models.CharField(max_length=124, null=False)
    middle_name = models.CharField(max_length=124, default='')
    last_name = models.CharField(max_length=124, null=False)
    name = models.CharField(max_length=124, default=f"{first_name} {middle_name} {last_name}")
    father_name = models.CharField(max_length=124, null=False)
    phone_number = models.CharField(max_length=20, null=False)
    date_of_birth = models.DateField()
    national_id= models.CharField(max_length=15, null=False)
    student_class = models.ForeignKey(ClassName, on_delete=models.DO_NOTHING)

    def __str__(self):
        return f"{self.first_name} {self.middle_name} {self.last_name}"

Я пытаюсь найти метод для получения всех пользователей, используя метод ClassName.objects.get() и ClassName using Student.objects.get()?

from django.contrib.auth.models import AbstractUser
from django.db import models


# Create your models here.
class User(AbstractUser):
    pass


class ClassName(models.Model):
    grade = models.IntegerField()
    section = models.CharField(max_length=1)

    def __str__(self):
        return f"{self.grade} - {self.section}"


class Student(models.Model):
    first_name = models.CharField(max_length=124, null=False)
    middle_name = models.CharField(max_length=124, default='')
    last_name = models.CharField(max_length=124, null=False)
    name = models.CharField(max_length=124, default=f"{first_name} {middle_name} {last_name}")
    father_name = models.CharField(max_length=124, null=False)
    phone_number = models.CharField(max_length=20, null=False)
    date_of_birth = models.DateField()
    national_id= models.CharField(max_length=15, null=False)
    classname = models.ForeignKey(
          ClassName, 
          on_delete=models.CASCADE
  )

    def __str__(self):
        return f"{self.first_name} {self.middle_name} {self.last_name}"

Итак, похоже, что вы пытаетесь установить отношения many-to-many (m2m) между пользователями и классами. Это имеет смысл, поскольку пользователь записан в несколько классов, и каждый класс посещают несколько студентов.

Тогда вы решили создать свои собственные пользовательские модели, это также имеет смысл, поскольку открывает дверь для возможных будущих изменений в кодовой базе без необходимости выполнять рискованные ручные операции над БД.

Вы расширили AbstractUser. Теперь потратьте минуту, чтобы проверить в кодовой базе Django, с какими атрибутами и методами поставляется AbstractUser: >> AbstractUser <<

Вы можете видеть, что она поставляется с username, first_name, last_name, email, is_staff, is_active и т.д.. Так что все это уже встроено в Django, если вы используете эту модель как базовую (как и должно быть), вам не нужно заново объявлять все эти атрибуты.

Теперь спросите себя: Сколько студентов может представлять каждый пользователь? Обычно ответ на этот вопрос должен быть "только 1", так что это говорит о том, что между пользователем и студентом вам, вероятно, нужны отношения one-to-one.

Итак, вкратце, вам нужна модель User с отношениями 1to1 с моделью Student, затем вам нужны отношения m2m между Student и ClassName. Давайте посмотрим, как это реализовать:

# User and Student
class User(AbstractUser):
    middle_name = models.CharField(max_length=124, default='')
    father_name = models.CharField(max_length=124, null=False)
    phone_number = models.CharField(max_length=20, null=False)
    date_of_birth = models.DateField()
    national_id= models.CharField(max_length=15, null=False)

class Student(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="student")

Теперь вы, вероятно, заметили, как некоторые поля отсутствуют в вашей первоначальной реализации и как я переместил некоторые другие из Student в User.

Я не включил некоторые поля, которые уже существуют в модели AbstractUser, которые вы наследуете при объявлении User, потому что у вас уже есть к ним доступ. Так, например, если вы выполните:

user = User.objects.get(id=1) 
print(user.first_name)

Это будет работать нормально.

Причина, по которой я переместил поля Student в User, заключается в том, что это атрибуты, принадлежащие модели User. Если бы, например, вы хотели хранить average_grade, то он бы точно принадлежал модели Student. Например, father_name, вероятно, принадлежит модели Student. Предположим, что позже вы захотите добавить модель Teacher, я не могу представить, чтобы для учителей было обязательным указывать имя своего отца. Но я предоставляю вам решать это! Для получения дополнительной информации об этом вы можете ознакомиться с этим ответом , который я написал некоторое время назад об этой конкретной структуре модели, которую вы пытаетесь реализовать.

Теперь давайте рассмотрим m2m отношения между Student и ClassName. Для этого я очень рекомендую вам прочитать вводный материал по базам данных и отношениям в базах данных. Отношения "многие ко многим" - самые сложные для понимания, и вам, возможно, придется потратить некоторое время на это, прежде чем вы продолжите работу над своим проектом Django.

Вы можете посмотреть это видео для краткого изложения многих важных концепций баз данных. Это помогло мне в прошлом.

Вот как это можно реализовать:

class Student(models.Model)
    user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="student")
    class_names = models.ManyToManyField(ClassName, related_name="students")

class ClassName(models.Model):
    grade = models.IntegerField()
    section = models.CharField(max_length=1)

Я рекомендую вам прочитать очень хорошую документацию django по отношениям "многие-ко-многим", чтобы составить представление о том, что вы можете с ними делать.

В простых терминах это означает, что каждый Student может иметь много ClassName, а каждый ClassNames может иметь много Students.

Вы можете манипулировать отношениями с обеих сторон. Например:

class_name_1 = ClassName.objects.get(id=1)
class_name_2 = ClassName.objects.get(id=2)
user.class_names.add(class_name_1)
user.class_names.add(class_name_2)
print(user.class_names.all()). # will print: [class_name1, class_name2]

print(class_name_1.students.all()). # will print: [user, ]
Вернуться на верх