【引入】BBS表设计
- 一个项目最最最重要的不是业务逻辑的书写
- 而是前期的表设计,只要将表设计好,后续的功能就会相对顺利一些
【1】用户表(UserInfo)
字段名 |
类型 |
注释 |
phone |
BigIntegerField |
电话 |
avatar |
FileField |
头像链接 |
create_time |
DateField |
创建时间 |
blog |
OneToOneField(to="Blog") |
外键字段,一对一,个人站点表 |
【2】个人站点表(Blog)
字段名 |
类型 |
注释 |
site_name |
CharField |
站点名称 |
site_title |
CharField |
站点标题 |
site_theme |
CharField |
站点样式 |
【3】文章分类表(Category)
字段名 |
类型 |
注释 |
name |
CharField |
分类名 |
blog |
ForeignKey(to="Blog") |
外键字段,一对多,个人站点 |
【4】文章标签表(CategoryTag)
字段名 |
类型 |
注释 |
name |
CharField |
标签名 |
【5】文章表(Article)
字段名 |
类型 |
注释 |
title |
CharField |
文章标题 |
desc |
CharField |
文章摘要/文章简介 |
content |
TextField |
文章内容 |
create_time |
DateField |
发布时间 |
up_num |
BigIntegerField |
点赞数 |
down_num |
BigIntegerField |
点踩数 |
comment_num |
BigIntegerField |
评论数 |
blog |
ForeignKey(to="Blog") |
外键字段,一对多,个人站点 |
category |
ForeignKey(to="Category") |
外键字段,多对多,文章标签 |
tags |
ManyToManyField(to="CategoryTag") |
外键字段,一对多,文章分类 |
- 虚拟出第三张表作为多对多字段(ArticleToTag)
字段名 |
类型 |
注释 |
article |
ForeignKey(to="Article") |
外键字段,一对多,文章 |
tag |
ForeignKey(to="CategoryTag") |
外键字段,一对多,标签 |
- 数据库字段设计优化
- 虽然点赞数、点踩数和评论数都能从单独的表中查询得出
- 但是频繁地跨表查询效率很低
- 在上表内增加普通字段记录相关的数据
【6】点赞点踩表(UpAndDown)
字段名 |
类型 |
注释 |
user |
ForeignKey(to="UserInfo") |
用户主键值 |
article |
ForeignKey(to="Article") |
文章主键值 |
is_up |
BooleanField() |
是否点赞 |
字段名 |
类型 |
注释 |
user |
ForeignKey(to='UserInfo') |
用户主键值 |
article |
ForeignKey(to="Article") |
文章主键值 |
content |
CharField() |
评论内容 |
comment_time |
DateTimeField |
评论时间 |
parent |
ForeignKey(to="self",null=True) |
自关联 |
- 根评论
- 子评论
- 跟评论可以有多个子评论(一对多关系)
# ORM 自带的自关联 写法
ForeignKey(to="self",null=True)
【8】表结构图解
【9】数据库建表
# 默认用户模型指定
AUTH_USER_MODEL = 'book.UserInfo'
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'bbs_sys', # 需提前创建数据库名
'USER': 'root', # 自己的用户名
'PASSWORD': '1314521', # 自己的数据库密码
'HOST': '127.0.0.1', # 自己的IP
'PORT': 3306,# 自己的端口
'CHARSET': 'utf8',
}
}
import pymysql
pymysql.install_as_MySQLdb()
from django.db import models
# Create your models here.
'''
先写普通字段
再写外键字段
'''
from django.contrib.auth.models import AbstractUser, User
# 用户表
class UserInfo(AbstractUser):
phone = models.BigIntegerField(verbose_name="手机号", help_text="手机号", null=True, blank=True)
'''
null=True 数据库该字段可以为空
blank=True admin后台管理可以为空
'''
avatar = models.FileField(verbose_name="用户头像",
help_text="用户头像",
upload_to='avatar/',
default='book/static/img/default.png')
# 给avatar字段传文件对象,该文件会自动存储到 avatar 文件夹下,然后avatar字段只保存文件路径 例如 avatar/default.png(不上传文件的默认头像文件)
create_time = models.DateField(verbose_name="创建时间", help_text="创建时间", auto_now_add=True)
blog = models.OneToOneField(verbose_name="关联博客", to="Blog", on_delete=models.CASCADE, null=True)
class Meta:
verbose_name = "用户表"
verbose_name_plural = verbose_name
def __str__(self):
return self.username
# 个人站点表
class Blog(models.Model):
site_name = models.CharField(verbose_name="站点名称", help_text="站点名称", max_length=32)
site_title = models.CharField(verbose_name="站点标题", help_text="站点标题", max_length=32)
site_theme = models.CharField(verbose_name="站点样式", help_text="站点样式", max_length=64) # css/js的文件路径
class Meta:
verbose_name = "个人站点表"
verbose_name_plural = verbose_name
def __str__(self):
return self.site_name
# 文章分类表
class Category(models.Model):
name = models.CharField(verbose_name="文章分类", max_length=32)
blog = models.ForeignKey(verbose_name="关联博客", to="Blog", on_delete=models.CASCADE, null=True)
class Meta:
verbose_name = "文章分类表"
verbose_name_plural = verbose_name
def __str__(self):
return self.name
# 文章标签
class CategoryTag(models.Model):
name = models.CharField(verbose_name="文章标签", max_length=32)
blog = models.ForeignKey(verbose_name="文章标签关联个人站点mi", to="Blog", null=True, blank=True,
on_delete=models.CASCADE)
class Meta:
verbose_name = "文章标签表"
verbose_name_plural = verbose_name
def __str__(self):
return self.name
# 文章表
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)
blog = models.ForeignKey(verbose_name="关联博客", to="Blog", on_delete=models.CASCADE, null=True)
category = models.ForeignKey(verbose_name="关联分类", to="Category", on_delete=models.CASCADE, null=True)
tags = models.ManyToManyField(verbose_name="关联文章和标签",
to="CategoryTag",
through='ArticleToTag',
through_fields=("article", "tag")
)
class Meta:
verbose_name = "文章表"
verbose_name_plural = verbose_name
def __str__(self):
return self.title
class ArticleToTag(models.Model):
article = models.ForeignKey(verbose_name="关联文章", to="Article", on_delete=models.CASCADE, null=True)
tag = models.ForeignKey(verbose_name="关联标签", to="CategoryTag", on_delete=models.CASCADE, null=True)
class Meta:
verbose_name = "文章关联标签"
verbose_name_plural = verbose_name
# 点赞点踩表
class UpAndDown(models.Model):
user = models.ForeignKey(verbose_name="关联用户", to='UserInfo', on_delete=models.CASCADE)
article = models.ForeignKey(verbose_name="关联文章", to='Article', on_delete=models.CASCADE)
is_up = models.BooleanField(verbose_name="是否点赞点踩")
class Meta:
verbose_name = "点赞点踩表"
verbose_name_plural = verbose_name
# 评论表
class Comment(models.Model):
user = models.ForeignKey(verbose_name="关联用户", to='UserInfo', on_delete=models.CASCADE)
article = models.ForeignKey(verbose_name="关联文章", to='Article', on_delete=models.CASCADE)
content = models.CharField(verbose_name="评论内容", max_length=255)
comment_time = models.DateTimeField(verbose_name="评论时间", auto_now_add=True)
parent = models.ForeignKey(verbose_name="自关联主评论", to="self", on_delete=models.CASCADE, null=True) # 有些评论就是根评论
class Meta:
verbose_name = "用户评论表"
verbose_name_plural = verbose_name