banner
raye~

Raye's Journey

且趁闲身未老,尽放我、些子疏狂。
medium
tg_channel
telegram
twitter
douban
github
email
nintendo switch
playstation
steam_profiles
zhihu

[Django Backend Development Part 2] Model Design and Creation

【Django Backend Development 1】Environment Deployment and Project Initialization

Requirement Abstraction and Model Design#

Isn't backend development essentially CRUD? 😂 /doge, so let's start with the design of the data model.

As mentioned earlier, the main functions include publishing learning content, student management, creating study plans, and student check-ins.

There are three roles here:

  • Administrator: has all the functions
  • Study Committee: one study committee per class, responsible for creating study push plans for the class
  • Student: can receive learning content and check in

Therefore, let's consider abstracting the following tables:

  • Study Content table, which records the learning content
  • Class table, which needs to have a study committee role
  • Student table, with three roles
  • Check-in table, which records the check-in records of each student
  • Push Strategy, which is associated with both the study content and the class

Study Content table, including the learning content, title, brief, and study link. To avoid direct deletion, we added a flag to indicate whether it is online or not.

class StudyContent(models.Model):
    """
    Study content, including title, brief, and study link
    """
    title = models.CharField(max_length=100, verbose_name='Title')
    brief = models.TextField(verbose_name='Brief')
    url = models.URLField(verbose_name='Page Link')
    is_online = models.BooleanField(default=False, verbose_name='Is the study content online')
    class Meta:
        verbose_name = 'Study Content'
        verbose_name_plural = 'Study Content'

    def __str__(self):
        return self.title

verbose_name is for clearer display in the backend, otherwise it will be an Object

Student table, Class table, the Student table needs to reference the Class table as a foreign key, and the Class table also needs to reference the Student table as a foreign key.

Here we encounter the first challenge, based on the description above, there is actually a circular dependency here, which causes the creation of new users to fail.

Therefore, we add black=True to allow the creation of a class without a study committee, and also allow the creation of a student without specifying a class.

class SchoolClass(models.Model):
    """
    Class table, each student belongs to a class, and each class has a study committee
    """
    name = models.CharField(max_length=100, verbose_name='Class Name')
    study_committee = models.OneToOneField(
        'Student', 
        on_delete=models.SET_NULL, 
        null=True, 
        blank=True,  # Allow the creation of a class without a study committee
        related_name='managed_class',
        verbose_name='Study Committee'
    )
    class Meta:
        verbose_name = 'Class Management'
        verbose_name_plural = 'Class Management'

    def __str__(self):
        return self.name


class Student(AbstractUser):
    """
    Role table
    """
    STUDENT = 'ST'
    ADMIN = 'AD'
    STUDY_COMMITTEE = 'SC'
    ROLE_CHOICES = [
        (STUDENT, 'Student'),
        (ADMIN, 'Administrator'),
        (STUDY_COMMITTEE, 'Study Committee')
    ]
    role = models.CharField(
        max_length=2, choices=ROLE_CHOICES, default=STUDENT, verbose_name='Role Type')
    class_group = models.ForeignKey(SchoolClass, on_delete=models.SET_NULL, null=True, blank=True, related_name='students', verbose_name='Belongs to Class')
    is_staff = models.BooleanField(default=True) # Allow login to the backend by default

    def __str__(self):
        return self.username

    class Meta:
        verbose_name = 'User Management'
        verbose_name_plural = 'User Management'

To reuse the user management functionality of Django backend, we let the Student class inherit from the AbstractUser class.
The following code needs to be added in the admin later, but that's another story

@admin.register(Student)
class StudentAdmin(UserAdmin):
  pass

Push Strategy table, Check-in table

The Check-in table is associated with the study content as a foreign key.
The Push Strategy table is associated with the study content and class as foreign keys.

class Checkin(models.Model):
    """
    Student check-in table
    """
    student = models.ForeignKey(Student, on_delete=models.CASCADE, verbose_name='Student')
    study_content = models.ForeignKey(
        StudyContent, on_delete=models.CASCADE, related_name='checkins', verbose_name='Study Content')
    checkin_time = models.DateTimeField(auto_now_add=True, verbose_name='Check-in Time')
    is_valid = models.BooleanField(default=True, verbose_name='Is the check-in record valid') # Default is marked as valid
    class Meta:
        verbose_name = 'Student Check-in Record Management'
        verbose_name_plural = 'Student Check-in Record Management'

    def __str__(self):
        return f"{self.student} checked in {self.study_content} at {self.checkin_time}"

class PushStrategy(models.Model):
    """
    Push strategy, foreign keys associated with content, class, push frequency, and push time
    """
    study_content = models.ForeignKey(
        StudyContent, on_delete=models.CASCADE, related_name='push_strategy', verbose_name='Study Content')
    class_group = models.ForeignKey('SchoolClass', on_delete=models.CASCADE, related_name='push_strategies', verbose_name='Class')
    frequency = models.CharField(max_length=20, verbose_name='Push Frequency')
    push_time = models.DateTimeField(verbose_name='Push Start Time')
    is_online = models.BooleanField(default=False, verbose_name='Is the push strategy online')

    class Meta:
        verbose_name = 'Push Strategy Management'
        verbose_name_plural = 'Push Strategy Management'
        unique_together = [['study_content', 'class_group']] # Ensure that these two keys are unique

    def __str__(self):
        return self.study_content.title

At this point, our models are basically developed. Every time you modify the model, you need to run

python manage.py makemigrations
python manage.py migrate
Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.