banner
raye~

Raye's Journey

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

【Djangoバックエンド開発2】モデルの設計と作成

【Django 後台開發一】環境部署和初始化項目

需求抽象與模型設計#

後台開發本質不就是 CRUD 嗎 😂 /doge ,因此先從資料模型上進行設計

上文有提到過需求,主要功能包括發布學習內容,學生管理,制定學習計劃,學生打卡

這裡有三種角色,

  • 管理員:可以有所有的功能
  • 學習委員:每個班級一個學習委員,負責制定本班的學習推送計劃
  • 學生:可以接收學習內容,並打卡

因此我們可以思考下,抽象出表

  • 學習內容表,記錄學習內容
  • 班級表,需要有個學委的角色
  • 學生表,三種角色
  • 打卡表,每個學生的打卡記錄
  • 推送策略,同時關聯學習內容和班級

學習內容表,包含學習內容、標題、簡介、學習鏈接,為了避免直接刪除,加了一個是否上線的判斷來標記刪除

class StudyContent(models.Model):
    """
    學習內容,包含標題,簡介,學習鏈接
    """
    title = models.CharField(max_length=100, verbose_name='標題')
    brief = models.TextField(verbose_name='簡介')
    url = models.URLField(verbose_name='頁面鏈接')
    is_online = models.BooleanField(default=False, verbose_name='學習內容是否上線')
    class Meta:
        verbose_name = '學習內容'
        verbose_name_plural = '學習內容'

    def __str__(self):
        return self.title

verbose_name 是為了能在後台展示的更清晰,不然就是一個 Object

學生表、班級表,學生表是需要引用班級表的外鍵,並且班級表也需要引用學生表作為外鍵

這裡就遇到了第一個坑,根據上文描述這裡其實存在循環依賴,導致後續新建用戶失敗

因此加上 black=True 來允許創建一個沒有學委的班級,也允許創建一個學生,但是不指定班級

class SchoolClass(models.Model):
    """
    班級表,每個學生屬於班級,每個班級一個學委
    """
    name = models.CharField(max_length=100, verbose_name='班級名')
    study_committee = models.OneToOneField(
        'Student', 
        on_delete=models.SET_NULL, 
        null=True, 
        blank=True,  # 允許先創建一個沒有學委的班級
        related_name='managed_class',
        verbose_name='學習委員'
    )
    class Meta:
        verbose_name = '班級管理'
        verbose_name_plural = '班級管理'

    def __str__(self):
        return self.name


class Student(AbstractUser):
    """
    角色表
    """
    STUDENT = 'ST'
    ADMIN = 'AD'
    STUDY_COMMITTEE = 'SC'
    ROLE_CHOICES = [
        (STUDENT, '學生'),
        (ADMIN, '管理員'),
        (STUDY_COMMITTEE, '學習委員')
    ]
    role = models.CharField(
        max_length=2, choices=ROLE_CHOICES, default=STUDENT, verbose_name='角色類型')
    class_group = models.ForeignKey(SchoolClass, on_delete=models.SET_NULL, null=True, blank=True, related_name='students', verbose_name='所屬班級')
    is_staff = models.BooleanField(default=True) # 默認允許登錄後台

    def __str__(self):
        return self.username

    class Meta:
        verbose_name = '用戶管理'
        verbose_name_plural = '用戶管理'

為了複用 Django 後台的用戶管理功能,我們讓 Student 類繼承自 AbstractUser
後續在 admin 中還需要添加如下代碼,這是後話

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

推送策略表,打卡記錄表

打卡表關聯了學習內容做外鍵
推送策略表同時關聯了學習內容、班級做外鍵

class Checkin(models.Model):
    """
    學生打卡表
    """
    student = models.ForeignKey(Student, on_delete=models.CASCADE, verbose_name='學生')
    study_content = models.ForeignKey(
        StudyContent, on_delete=models.CASCADE, related_name='checkins', verbose_name='學習內容')
    checkin_time = models.DateTimeField(auto_now_add=True, verbose_name='打卡時間')
    is_valid = models.BooleanField(default=True, verbose_name='打卡記錄是否有效') # 默認標記為有效
    class Meta:
        verbose_name = '學生打卡記錄管理'
        verbose_name_plural = '學生打卡記錄管理'

    def __str__(self):
        return f"{self.student}{self.checkin_time} 打卡了 {self.study_content}"

class PushStrategy(models.Model):
    """
    推送策略,外鍵關聯內容,班級、推送頻率和推送時間
    """
    study_content = models.ForeignKey(
        StudyContent, on_delete=models.CASCADE, related_name='push_strategy', verbose_name='學習內容')
    class_group = models.ForeignKey('SchoolClass', on_delete=models.CASCADE, related_name='push_strategies', verbose_name='班級')
    frequency = models.CharField(max_length=20, verbose_name='推送頻率')
    push_time = models.DateTimeField(verbose_name='推送開始時間')
    is_online = models.BooleanField(default=False, verbose_name='推送策略是否上線')

    class Meta:
        verbose_name = '推送策略管理'
        verbose_name_plural = '推送策略管理'
        unique_together = [['study_content', 'class_group']] # 保證這兩個鍵唯一

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

至此我們的模型就基本開發完了,每次修改完模型,都需要運行

python manage.py makemigrations
python manage.py migrate
読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。