BBS项目-表设计及创建

一个项目中最最最重要的不是业务逻辑的书写,而是前期的表设计,只要将表设计好了,后续的功能书写才会一帆风顺。

BBS项目参考分析博客园网站,提取功能,分析需要用到哪些表。

 

1 用户表

首页右上角模块分析,包含用户注册和登录,用户个人中心,设置等功能。因此需要建用户表。

我们要利用django框架的auth组件,并且需要扩展字段,如 avatar用户头像字段,因此需要自己建用户表,并继承AbstractUser。

 

2 个人站点表

通过点击文章下的头像框跳转到博主的主页

每个用户有一个博客主页,这个主页就是个人站点。我们点击多个主页,发现规律:url后输入用户名跳转到该用户主页。

其他表都围绕个人站点表展开,都会与之关联。

 

3 文章标签表

进入个人站点(博主主页)分析页面,一般由3部分构成,顶部的导航条,左侧是分类、标签、统计等导航条,右侧是文章或随笔。

一篇文章可以有多个标签。

 

4 文章分类表

一篇文章只能归于一类。

 

5 文章表

个人站点主题是一篇篇文章

 

6 点赞点踩表

每篇文章下记录了点赞点踩,用来记录哪个用户给哪篇文章点了赞还是点了踩。

 

7 文章评论表

每篇文章下可以发表评论,用来记录哪个用户给哪篇文章写了哪些评论内容。

 

8 表模型分析与创建

通过参考博客园网站模块,我们初步分析出需要上述7张表,接下来利用django ORM创建表模型,在创建过程中,先依次创建普通字段,然后分析表与表之间的关系,创建外键字段。

1、由于django自带的sqlite数据库对日期不敏感,所以我们换成MySQL。

setting.py

init.py

2、创建表模型:用户表,用auth模块,继承 AbstractUser

models.py 

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


# Create your models here.

class UserInfo(AbstractUser):
    phone = models.BigIntegerField(verbose_name='电话号码', null=True)
    avatar = models.FileField(verbose_name='用户头像', upload_to='avatar/', default='avatar/default.npg')
    create_time = models.DateField(verbose_name='创建时间', auto_now_add=True)
    blog = models.OneToOneField(to='Blog', null=True, on_delete=models.CASCADE)

在auth_user表基础上扩展字段,在项目根路径下创建一个avatar文件夹用来保存用户上传的头像文件, 给avatar字段传文件对象,该文件会自动存储到avatar文件夹下,然后avatar字段只保存文件路径,如 avatar/default.png(用户没有上传头像,用默认头像)。

blog外键字段,用户表与个人站点表一对一关系,为了创建表时方便,该字段可以为空,即在没有创建站点表的情况下,可以先创建用户。外键字段设置级联删除,即关联的主表(站点表)数据删除时,同步删除对应的从表(用户表)里的数据。

由于扩展替代了auth_user表,需要在settings.py中进行设置 

AUTH_USER_MODEL = 'app01.UserInfo'

 

个人站点表

class Blog(models.Model):
    site_name = models.CharField(verbose_name='站点名称', max_length=32)  # url输入的用户名,用来跳转到用户站点
    site_title = models.CharField(verbose_name='站点标题', max_length=32)
    site_theme = models.CharField(verbose_name='站点样式',max_length=64)  # 用来存css/js的文件路径,用户自定义站点样式保存到文件中

site_theme字段只做简单模拟,不实现该功能。


 

文章标签和文章分类表 

class Tag(models.Model):
    name = models.CharField(verbose_name='标签名称', max_length=32)
    blog = models.ForeignKey(to='Blog', null=True, on_delete=models.CASCADE)


class Categorize(models.Model):
    name = models.CharField(verbose_name='分类名称', max_length=32)
    blog = models.ForeignKey(to='Blog', null=True, on_delete=models.CASCADE)

 一个站点下可以建多个标签和分类,一个标签和分类只能对应一个站点(因为每个站点下建的是该用户唯一的标签和分类),因此标签和分类,与站点都是一对多关系,blog外键字段,为了创建表时方便,该字段可以为空,即在没有创建站点表的情况下,可以先创建标签和分类。外键字段设置级联删除,即关联的主表(站点表)数据删除时,同步删除对应的从表(标签表、分类表)里的数据。


 

文章表

class Article(models.Model):
    title = models.CharField(verbose_name='文章标题', max_length=64)
    desc = models.CharField(verbose_name='文章摘要', max_length=255)
    content = models.TextField(verbose_name='文章内容')
    create_time = models.DateField(verbose_name='发布日期', auto_now_add=True)
    up_num = models.BigIntegerField(verbose_name='点赞数', default=0)
    down_num = models.BigIntegerField(verbose_name='点踩数', default=0)
    comment_num = models.BigIntegerField(verbose_name='评论数', default=0)
    tags = models.ManyToManyField(to='Tag',
                                  through='Article2Tag',
                                  through_fields=('article', 'tag')
                                  )
    categorize = models.ForeignKey(to='Categorize', null=True, on_delete=models.SET_NULL)
    blog = models.ForeignKey(to='Blog', null=True, on_delete=models.CASCADE)


class Article2Tag(models.Model):
    article = models.ForeignKey(to='Article', on_delete=models.CASCADE)
    tage = models.ForeignKey(to='Tag', on_delete=models.CASCADE)

up_num、down_num、comment_num这三个字段是为了优化数据库设计的。因为文章需要展示这三个数据,每次查文章表,都需要跨表查询才能拿到数据,设计了这三个字段,避免频繁跨表操作。注意,在点赞和评论表创建数据时,同步更新这3个字段数据即可,并且初始默认值都为0。

tags外键字段,文章和标签多对多关系,我们用半自动方式,自己创建了第三张关系表,便于后续扩展字段。

categorize外键字段,文章和分类一对多关系(一篇文章只能归于一类)。在关联的主表(分类表)数据删除时,对应的从表(文章表)数据设置为空,这里用级联删除不合理,因为删除分类时会把对应的文章一起删除掉。

blog外键字段,文章和站点一对多,设置级联删除,同样,为了创建表时方便,该字段可以为空,即在没有创建站点表的情况下,可以先创建文章。


 

点赞点踩表 

用来记录哪个用户给哪篇文章点了赞还是点了踩,类似于UserInfo2Article 第三方关系表,绑定的用户与文章的关系,还有一个字段存布尔值(存0/1),用来记录点赞还是点踩。

class UpAndDown(models.Model):
    is_up = models.BooleanField()
    user = models.ForeignKey(to='UserInfo', on_delete=models.CASCADE)
    article = models.ForeignKey(to='Article', on_delete=models.CASCADE)

表结构如下:

id user_id article_id is_up
1 1 1 1
2 1 2 1
3 1 3 0
4 2 1 1

 

评论表

用来记录哪个用户给哪篇文章写了哪些评论内容,类似UserInfo2Article 第三方关系表,绑定用户与文章的关系,推导如点赞点踩表。

class Comment(models.Model):
    content = models.CharField(verbose_name='评论内容', max_length=255)
    comment_time = models.DateTimeField(verbose_name='评论时间', auto_now_add=True)
    user = models.ForeignKey(to='UserInfo', on_delete=models.CASCADE)
    article = models.ForeignKey(to='Article', on_delete=models.CASCADE)
    parent = models.ForeignKey(to='self', null=True, on_delete=models.CASCADE)

根评论与子评论概念:根评论就是直接评论当前发布的内容的评论,子评论是评论别人的评论(回复),很明显,根评论与子评论是一对多的关系,外键字段建在多的一方,但是根评论和子评论用的是同一张表。

parent外键字段,自关联外键字段,to='Comment',ORM提供的自关联写法,to='self' 语义更明确。 

表结构如下:

id user_id article_id parent_id
1 1 1  
2 2 1 1

外键字段相当于建在子评论,关联的是根评论的主键值,意味着,外键字段有值代表它是一条子评论。

如上面的表结构,id为1的评论是根评论,parent_id字段为空,记录的是id为1的用户与id为1的文章的绑定关系。

id为2的评论是一条子评论,parent_id=1,表示它关联的是id为1的根评论。

表创建完成后,最后执行两条数据库迁移命令。

posted @   不会钓鱼的猫  阅读(180)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
点击右上角即可分享
微信分享提示