校園集市小程式開發-系統架構與Django後端

Sherioc發表於2024-08-10

引子: 爛尾就爛尾吧,大不了以後自己創業。唉,也算給自己一個警戒。

E-R模型

介面設計

資料模型設計

基本模型放在models.py中

class School(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=100, verbose_name='學校名稱')
# 學校校區
class SchoolRegion(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=100, verbose_name='校區名稱')

    school = models.ForeignKey(School, on_delete=models.CASCADE, related_name='regions', verbose_name='所屬學校')

    def __str__(self):
        return f"{self.school.name} {self.name}"

# 使用者
class CustomUser(models.Model):
    wechat_openid = models.CharField(max_length=255, unique=True, verbose_name='微信OpenID', null=True, blank=True)
    id = models.BigAutoField(primary_key=True, editable=False)
    phone = models.CharField(max_length=11, unique=True, verbose_name='手機號')
    gender = models.CharField(max_length=10, choices=(('male', '男'), ('female', '女'),('unknow','未知')), verbose_name='性別')
    avatar = models.URLField(verbose_name='頭像URL')
    nickname = models.CharField(max_length=50, verbose_name='暱稱')

    signature = models.CharField(null=True, blank=True, max_length=200, verbose_name='個性簽名')
    email = models.EmailField(null=True, blank=True, unique=True, verbose_name='郵箱')
    birthday = models.DateField(null=True, blank=True, verbose_name='生日')
    height = models.IntegerField(null=True, blank=True, verbose_name='身高')
    background_image = models.URLField(null=True, blank=True, verbose_name='背景圖URL')
    hometown = models.CharField(null=True, blank=True, max_length=50, verbose_name='家鄉')

    created_at = models.DateTimeField(auto_now_add=True, verbose_name='建立時間')
    updated_at = models.DateTimeField(auto_now=True, verbose_name='更新時間')
    is_verified = models.BooleanField(default=False, verbose_name='是否透過認證')
    is_frozen = models.BooleanField(default=False, verbose_name='是否凍結')

    school = models.ForeignKey('School', on_delete=models.CASCADE, related_name='students', verbose_name='所在學校', null=True, blank=True)
    region = models.ForeignKey('SchoolRegion', on_delete=models.CASCADE, related_name='students', verbose_name='所在校區', null=True, blank=True)

    like_number = models.IntegerField(default=0, verbose_name='點贊數')
    fan_number = models.IntegerField(default=0, verbose_name='粉絲數') # 使用者被關注
    follow_number = models.IntegerField(default=0, verbose_name='關注數') # 使用者關注數

    def __str__(self):
        return self.nickname


# 圈子
class Circle(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=100, verbose_name='圈子名稱')
    description = models.TextField(verbose_name='圈子描述')
    avatar = models.URLField(verbose_name='圈子頭像URL')

    notice = models.TextField(null=True, blank=True, verbose_name='圈子公告')

    created_at = models.DateTimeField(auto_now_add=True, verbose_name='建立時間')
    is_verified = models.BooleanField(default=False, verbose_name='是否透過認證')
    is_frozen = models.BooleanField(default=False, verbose_name='是否凍結')

    creator = models.ForeignKey(CustomUser, on_delete=models.CASCADE, related_name='circles', verbose_name='建立者')
    school = models.ForeignKey(School, on_delete=models.CASCADE, related_name='circles', verbose_name='所屬學校')

    like_number = models.IntegerField(default=0, verbose_name='點贊數')
    collect_number = models.IntegerField(default=0, verbose_name='收藏數')
    fan_number = models.IntegerField(default=0, verbose_name='粉絲數')

    def __str__(self):
        return f"{self.name} (建立者:{self.creator.nickname})"

# 帖子
class Post(models.Model):
    id = models.BigAutoField(primary_key=True)
    title = models.CharField(max_length=200, verbose_name='標題') 
    content = models.TextField(verbose_name='內容')

    created_at = models.DateTimeField(auto_now_add=True, verbose_name='建立時間')
    is_frozen = models.BooleanField(default=False, verbose_name='是否凍結')

    circle = models.ForeignKey(Circle, on_delete=models.CASCADE, related_name='posts', verbose_name='所屬圈子')
    author = models.ForeignKey(CustomUser, on_delete=models.CASCADE, related_name='posts', verbose_name='作者')

    like_number = models.IntegerField(default=0, verbose_name='點贊數')
    collect_number = models.IntegerField(default=0, verbose_name='收藏數')
    comment_number = models.IntegerField(default=0, verbose_name='評論數')

    def __str__(self):
        return f"{self.author.nickname}釋出的{self.title}"
    

# 評論
class Comment(models.Model):
    id = models.BigAutoField(primary_key=True)
    content = models.TextField(verbose_name='評論內容')
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='建立時間')

    post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='comments', verbose_name='所屬帖子')
    reply_to = models.ForeignKey('self', on_delete=models.SET_NULL,  related_name='replies', verbose_name='回覆目標', null=True, blank=True)
    author = models.ForeignKey(CustomUser, on_delete=models.CASCADE, related_name='comments', verbose_name='作者')

    like_number = models.IntegerField(default=0, verbose_name='點贊數')
    reply_number = models.IntegerField(default=0, verbose_name='回覆數')

    def __str__(self):
        return f"{self.author.nickname}的{self.content}"

    def delete(self, *args, **kwargs):
        # 當刪除一個評論時,將指向它的所有回覆評論的reply_to欄位設定為NULL
        if self.reply_to:
            self.reply_to.replies.update(reply_to=None)
        super().delete(*args, **kwargs)


# 通知
class Notification(models.Model):
    id = models.BigAutoField(primary_key=True)
    sender = models.ForeignKey(CustomUser, on_delete=models.CASCADE, related_name='sent_notifications', verbose_name='事件傳送者')
    receiver = models.ForeignKey(CustomUser, on_delete=models.CASCADE, related_name='notifications', verbose_name='接收使用者')
    content = models.TextField(verbose_name='通知內容', null=True, blank=True)
    status = models.BooleanField(default=False, verbose_name='狀態')  # True 表示已讀,False 表示未讀
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='建立時間')

# 上傳的圖片
class Image(models.Model):
    id = models.BigAutoField(primary_key=True)
    image = models.CharField(max_length=255, verbose_name='圖片url')
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='建立時間')

    uploader = models.ForeignKey(CustomUser, on_delete=models.CASCADE, related_name='images', verbose_name='上傳者')

關係模型另外放在relations.py

"""帖子圖片"""
class PostImage(models.Model):
    post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='post_images')
    image = models.ForeignKey(Image, on_delete=models.CASCADE, related_name='post_images')
    # 額外排序欄位
    order = models.PositiveIntegerField(default=0)

    class Meta:
        # 確保圖片的順序是按照升序排列的
        ordering = ['order']
        # 確保不會有重複的帖子-圖片對
        unique_together = ('post', 'image')

"""使用者舉報(帖子、圈子、評論、使用者)"""
class Report(models.Model):
    id = models.BigAutoField(primary_key=True)
    report_type = models.CharField(max_length=50, choices=[('post', '帖子'), ('circle', '圈子'), ('comment', '評論'), ('user', '使用者')], verbose_name='舉報型別')
    reason = models.TextField(verbose_name='舉報理由', null=True, blank=True)
    status = models.CharField(max_length=50, choices=[('pending', '待處理'), ('approved', '已批准'), ('rejected', '已拒絕')], default='pending', verbose_name='舉報狀態')
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='建立時間')

    reporter = models.ForeignKey(CustomUser, on_delete=models.CASCADE, related_name='reports', verbose_name='舉報者')
    reported_object = models.ForeignKey(Post if report_type == 'post' else Circle if report_type == 'circle' else Comment if report_type == 'comment' else CustomUser, on_delete=models.CASCADE, related_name='reporters', verbose_name='被舉報物件')

    def __str__(self):
        if self.report_type == 'post':
            return f"{self.reporter.nickname}:id({self.reporter.id})舉報了帖子{self.reported_object.title}:id({self.reported_object.id})"
        elif self.report_type == 'circle':
            return f"{self.reporter.nickname}:id({self.reporter.id})舉報了{self.reported_object.name}:id({self.reported_object.id})"
        elif self.report_type == 'comment':
            return f"{self.reporter.nickname}:id({self.reporter.id})舉報了{self.reported_object.content}:id({self.reported_object.id})"
        elif self.report_type == 'user':
            return f"{self.reporter.nickname}:id({self.reporter.id})舉報了使用者{self.reported_object.nickname}:id({self.reported_object.id})"

"""使用者點贊(帖子、評論、圈子、使用者)"""
class UserLikePost(models.Model):
    user = models.ForeignKey(CustomUser, on_delete=models.CASCADE, related_name='liked_posts')
    post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='likers')
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='點贊時間')

    class Meta:
        unique_together = ('user', 'post')

    def __str__(self):
        return f"{self.user.nickname} 點讚了 {self.post.title}"

class UserLikeComment(models.Model):
    user = models.ForeignKey(CustomUser, on_delete=models.CASCADE, related_name='liked_comments')
    comment = models.ForeignKey(Comment, on_delete=models.CASCADE, related_name='likers')
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='點贊時間')

    class Meta:
        unique_together = ('user', 'comment')

    def __str__(self):
        return f"{self.user.nickname} 點讚了 {self.comment.content}"

class UserLikeCircle(models.Model):
    user = models.ForeignKey(CustomUser, on_delete=models.CASCADE, related_name='liked_circles')
    circle = models.ForeignKey(Circle, on_delete=models.CASCADE, related_name='likers')
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='點贊時間')

    class Meta:
        unique_together = ('user', 'circle')

    def __str__(self):
        return f"{self.user.nickname} 點讚了 {self.circle.name}"

class UserLikeUser(models.Model):
    user = models.ForeignKey(CustomUser, on_delete=models.CASCADE, related_name='liked_users')
    liked_user = models.ForeignKey(CustomUser, on_delete=models.CASCADE, related_name='likers')
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='點贊時間')

    class Meta:
        unique_together = ('user', 'liked_user')

    def __str__(self):
        return f"{self.user.nickname} 點讚了 {self.liked_user.nickname}"


"""使用者收藏(帖子、圈子、評論)"""
class UserCollectPost(models.Model):
    user = models.ForeignKey(CustomUser, on_delete=models.CASCADE, related_name='collected_posts')
    post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='collecters')
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='收藏時間')

    class Meta:
        unique_together = ('user', 'post')

    def __str__(self):
        return f"{self.user.nickname} 收藏了 {self.post.title}"

class UserCollectCircle(models.Model):
    user = models.ForeignKey(CustomUser, on_delete=models.CASCADE, related_name='collected_circles')
    circle = models.ForeignKey(Circle, on_delete=models.CASCADE, related_name='collecters')
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='收藏時間')

    class Meta:
        unique_together = ('user', 'circle')

    def __str__(self):
        return f"{self.user.nickname} 收藏了 {self.circle.name}"

class UserCollectComment(models.Model):
    user = models.ForeignKey(CustomUser, on_delete=models.CASCADE, related_name='collected_comments')
    comment = models.ForeignKey(Comment, on_delete=models.CASCADE, related_name='collecters')
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='收藏時間')

    class Meta:
        unique_together = ('user', 'comment')

    def __str__(self):
        return f"{self.user.nickname} 收藏了 {self.comment.content}"


"""使用者關注(使用者、圈子)"""
class UserFollowUser(models.Model):
    follower = models.ForeignKey(CustomUser, on_delete=models.CASCADE, related_name='following_users')
    following = models.ForeignKey(CustomUser, on_delete=models.CASCADE, related_name='followers')
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='關注時間')

    class Meta:
        unique_together = ('follower', 'following')  # 確保關注關係是唯一的,防止重複關注

    def __str__(self):
        return f"{self.follower.nickname} 關注 {self.following.nickname}"

class UserFollowCircle(models.Model):
    follower = models.ForeignKey(CustomUser, on_delete=models.CASCADE, related_name='following_circles')
    following = models.ForeignKey(Circle, on_delete=models.CASCADE, related_name='followers')
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='關注時間')

    class Meta:
        unique_together = ('follower', 'following')

    def __str__(self):
        return f"{self.follower.nickname} 關注 {self.following.name}"

前端響應模型設計

對前端響應模型進行封裝,resfront.py

異常處理配置中介軟體

CMarket/app/middleware.py

CMarket/cmarket/settings.py

相關文章