本渣渣不专注技术,只专注使用技术,不是一个资深的coder,是一个不折不扣的copier |
1、功能分析
对于初学者数据库设计是建站比较难的点,数据库表的产生是有网站功能决定的,但是不能有一个功能就创建一张表吧,所以这里需要一点数据库的基础知识
推荐阅读:Mysql数据库基础知识 数据库表设计
我们先从功能上分析,看看这个博客网站需要建立哪些表,每个表中都需要什么字段
首先,最主要的是我们的博文表,名字可以直接叫做 article,这个表中,肯定要包括以下几点:
博文的标题、博文的内容、博文的发表时间、博文的修改时间、博文的分类、博文的阅读量、博文喜欢量、博文作者 等
针对博文的分类,我们可以参考csdn博客系统,一篇博文只能有一个分类,但是可以有多个标签,比如我现在写的这篇博文,可以分类到 django 下,但是它可以有多个标签:django、博客、数据库、开发……
考虑到每一篇博文都只能有一个分类,而一个分类下是可以包含很多博文的,因此分类与博文是一对多的关系,此时应当使用外键来进行关联。而一篇博文可以有多个标签, 每个标签也可以包含多个博文,因此,标签与博文是多对多的关系。关于一对多与多对多的知识话题,这里就不再展开了,不了解的查看 Django文档 与相关资料。
推荐阅读:Django官方文档 Django中文文档
针对网站优化,那么一个网站最基本的SEO就是设置TDK
T: 网站页面 title
D: 网站页面描述
K: 网站页面Keywords,也即网站涵盖的主题
则需要一个页面关键字表 Keyword,一个页面可能包含多个主题,一个主题可能在多个页面出现,所以应该是多对多的关系 暂且称作 Keyword
崔庆才博客导航栏菜单存在下拉菜单,下拉菜单即是博文分类,这里的导航栏菜单也需要一个表,因为这个表就是为了给博文分类归类的 暂且称作 Bigcategory
观察崔庆才博客导航栏下边还一个公告,公告也需要一个表,它和任何表都没关系 暂且称作 Activate
公告下边是幻灯片,思考了一下,这个幻灯片应该和别的表也没啥关系,暂且称作 Carousel
再看看,右侧还有一个友情链接功能,需要一个表,友链和其它表也没啥关系 暂且称作 FriendLink
因此,通过上述分析,我们可以确定出这些数据表,博客(Article)、分类(Category)与标签(Tag)、导航(Bigcategory)、文章关键词 (Keyword)、公告(Activate)、幻灯片(Carousel)、友链(FriendLink)
2、编写 storm 应用模型
blog -> storm -> models.py
头文件
from django.db import models
from django.conf import settings
from django.shortcuts import reverse
import markdown
import re
由于 Article 表包含外键与多对多关系,因此首先应当建立另外两个表:
分类(Category)表的创建:
由于 Category 分类表包含外键,因此首先需要创建导航菜单表 Bigcategory
# 网站导航菜单栏分类表
class BigCategory(models.Model):
# 导航名称
name = models.CharField('文章大分类', max_length=20)
# 用作文章的访问路径,每篇文章有独一无二的标识,下同
slug = models.SlugField(unique=True)
# 分类页描述
description = models.TextField('描述', max_length=240, default=settings.SITE_DESCRIPTION,
help_text='用来作为SEO中description,长度参考SEO标准')
# 分类页Keywords
keywords = models.TextField('关键字', max_length=240, default=settings.SITE_KEYWORDS,
help_text='用来作为SEO中keywords,长度参考SEO标准')
class Meta:
verbose_name = '大分类'
verbose_name_plural = verbose_name
def __str__(self):
return self.name
# 导航栏,分类下的下拉擦菜单分类
class Category(models.Model):
# 分类名字
name = models.CharField('文章分类', max_length=20)
# slug 用作分类路径,对一无二
slug = models.SlugField(unique=True)
# 分类栏目页描述
description = models.TextField('描述', max_length=240, default=settings.SITE_DESCRIPTION,
help_text='用来作为SEO中description,长度参考SEO标准')
# 对应导航菜单外键
bigcategory = models.ForeignKey(BigCategory, verbose_name='大分类')
class Meta:
verbose_name = '分类'
verbose_name_plural = verbose_name
ordering = ['name']
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('blog:category', kwargs={'slug': self.slug, 'bigslug': self.bigcategory.slug})
def get_article_list(self):
return Article.objects.filter(category=self)
标签(Tag)表的创建:
# 文章标签
class Tag(models.Model):
name = models.CharField('文章标签', max_length=20)
slug = models.SlugField(unique=True)
description = models.TextField('描述', max_length=240, default=settings.SITE_DESCRIPTION,
help_text='用来作为SEO中description,长度参考SEO标准')
class Meta:
verbose_name = '标签'
verbose_name_plural = verbose_name
ordering = ['id']
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('blog:tag', kwargs={'tag': self.name})
def get_article_list(self):
"""返回当前标签下所有发表的文章列表"""
return Article.objects.filter(tags=self)
标签(Keyword)表的创建:
# 文章关键词,用来作为 SEO 中 keywords
class Keyword(models.Model):
name = models.CharField('文章关键词', max_length=20)
class Meta:
verbose_name = '关键词'
verbose_name_plural = verbose_name
ordering = ['name']
def __str__(self):
return self.name
博客(Article)表的创建:
# 文章
class Article(models.Model):
# 文章默认缩略图
IMG_LINK = '/static/images/summary.jpg'
# 文章作者
author = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name='作者')
title = models.CharField(max_length=150, verbose_name='文章标题')
summary = models.TextField('文章摘要', max_length=230, default='文章摘要等同于网页description内容,请务必填写...')
# 文章内容
body = models.TextField(verbose_name='文章内容')
img_link = models.CharField('图片地址', default=IMG_LINK, max_length=255)
create_date = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)
update_date = models.DateTimeField(verbose_name='修改时间', auto_now=True)
views = models.IntegerField('阅览量', default=0)
loves = models.IntegerField('喜爱量', default=0)
# 文章唯一标识符
slug = models.SlugField(unique=True)
category = models.ForeignKey(Category, verbose_name='文章分类')
tags = models.ManyToManyField(Tag, verbose_name='标签')
keywords = models.ManyToManyField(Keyword, verbose_name='文章关键词',
help_text='文章关键词,用来作为SEO中keywords,最好使用长尾词,3-4个足够')
class Meta:
verbose_name = '文章'
verbose_name_plural = verbose_name
ordering = ['-create_date']
def __str__(self):
return self.title[:20]
def get_absolute_url(self):
return reverse('blog:article', kwargs={'slug': self.slug})
def body_to_markdown(self):
return markdown.markdown(self.body, extensions=[
'markdown.extensions.extra',
'markdown.extensions.codehilite',
])
def update_views(self):
self.views += 1
self.save(update_fields=['views'])
def get_pre(self):
return Article.objects.filter(id__lt=self.id).order_by('-id').first()
def get_next(self):
return Article.objects.filter(id__gt=self.id).order_by('id').first()
为什么要用slug给文章起别名呢?这个可能暂且就认为只是为了提升逼格吧
公告(Activate)表的创建:
# 公告
class Activate(models.Model):
text = models.TextField('公告', null=True)
is_active = models.BooleanField('是否开启', default=False)
add_date = models.DateTimeField('提交日期', auto_now_add=True)
class Meta:
verbose_name = '公告'
verbose_name_plural = verbose_name
def __str__(self):
return self.id
幻灯片(Carousel)表的创建:
# 幻灯片
class Carousel(models.Model):
number = models.IntegerField('编号', help_text='编号决定图片播放的顺序,图片不要多于5张')
title = models.CharField('标题', max_length=20, blank=True, null=True, help_text='标题可以为空')
content = models.CharField('描述', max_length=80)
img_url = models.CharField('图片地址', max_length=200)
url = models.CharField('跳转链接', max_length=200, default='#', help_text='图片跳转的超链接,默认#表示不跳转')
class Meta:
verbose_name = '图片轮播'
verbose_name_plural = verbose_name
# 编号越小越靠前,添加的时间约晚约靠前
ordering = ['number', '-id']
def __str__(self):
return self.content[:25]
友链(FriendLink)表的创建:
# 友情链接表
class FriendLink(models.Model):
name = models.CharField('网站名称', max_length=50)
description = models.CharField('网站描述', max_length=100, blank=True)
link = models.URLField('友链地址', help_text='请填写http或https开头的完整形式地址')
logo = models.URLField('网站LOGO', help_text='请填写http或https开头的完整形式地址', blank=True)
create_date = models.DateTimeField('创建时间', auto_now_add=True)
is_active = models.BooleanField('是否有效', default=True)
is_show = models.BooleanField('是否首页展示', default=False)
class Meta:
verbose_name = '友情链接'
verbose_name_plural = verbose_name
ordering = ['create_date']
def __str__(self):
return self.name
def get_home_url(self):
"""提取友链的主页"""
u = re.findall(r'(http|https://.*?)/.*?', self.link)
home_url = u[0] if u else self.link
return home_url
def active_to_false(self):
self.is_active=False
self.save(update_fields=['is_active'])
def show_to_false(self):
self.is_show = True
self.save(update_fields=['is_show'])
【提示】—— storm -> models.py 中出现的 AUTH_USER_MODEL、SITE_DESCRIPTION、AUTH_USER_MODEL、SITE_KEYWORDS,把它们当作默认字段放在 setting.py 中,便于管理
blog -> blog -> settings.py
# 网站描述,用于SEO
SITE_DESCRIPTION = "StormSha的个人网站,记录生活的瞬间,分享学习的心得,感悟生活,留住感动,静静寻觅生活的美好"
# 网站关键词,用于SEO
SITE_KEYWORDS = "StormSha,静觅,网络,IT,技术,博客,Python"
在文件首部 # 引入 setings.py 文件,即可使用这些字段
from django.conf import settings
以上的类名代表了数据库表名,且继承了models.Model,类里面的字段代表数据表中的字段(name),数据类型则由CharField(相当于varchar)、DateField(相当于datetime),max_length 参数限定长度。
3、几点注意
关于博客表有以下几点需要注意的:
标题应当限定长度,我们设定最大值为100
内容不用限定长度,因此用的是TextField字段
修改时间直接设定成,auto_now=True,在你修改时,会自动变成当前时间。
关于ForeignKey与ManyToManyField,请自行查看相关文档资料
4、编写 user 用户应用模型
另外 文章有一个作者外键
author = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name='作者')
这个外键是网站注册用户,这样用户也可以有发文权限,考虑到以后会扩展用户功能,所以这里还是创建一个用户app比较好
创建app可以参考:Django个人博客开发五 | 创建第一个APP 不要忘了创建app后去配置文件里注册用户app,这里不再赘述,创建好 user 应用后,编写用户模型
blog -> user -> models.py
from django.db import models
from django.contrib.auth.models import AbstractUser
from imagekit.models import ProcessedImageField
from imagekit.processors import ResizeToFill
# 继承 AbstractUser ,django 自带用户类,扩展用户个人网站字段,用户头像字段
class Ouser(AbstractUser):
# 扩展用户个人网站字段
link = models.URLField('个人网址', blank=True, help_text='提示:网址必须填写以http开头的完整形式')
# 扩展用户头像字段
avatar = ProcessedImageField(upload_to='avatar/%Y/%m/%d',
default='avatar/default.png',
verbose_name='头像',
processors=[ResizeToFill(80, 80)]
)
class Meta:
verbose_name = '用户' # 定义网站管理后台表名
verbose_name_plural = verbose_name
ordering = ['-id']
def __str__(self):
return self.username
5、编写 user 用户应用模型
Tools -> run manage.py task 下依次执行命令:
& makemigrations
& migrate
即可将新建的这些表添加到我们的数据库 blog 中:
auth_group,
auth_group_permissions,
auth_permission,
auth_user_groups,
auth_user_user_permissions,
django_admin_log,
django_content_type,
django_migrations,
django_session,
storm_activate, # 公告表
storm_article, # 新增的博文表
storm_article_keywords, # 这个是博文与关键词的多对多关系表
storm_article_tags, # 这个是博文与标签的多对多关系表
storm_bigcategory, # 导航菜单大分类表
storm_carousel, # 幻灯片
storm_category, # 新增的分类表
storm_friendlink, # 友情链接
storm_keyword, # 关键词表
storm_tag, # 新增的标签表
user_ouser, # 新增扩展用户表
user_ouser_groups, # 自动产生
user_ouser_user_permissions # 自动产生
最后两个表示用户表继承了,Django自带的用户models产生的用户关系表
需要说明的是,这里我们只给出了最开始设计时考虑到的情况,在后续开发过程中,可以随时对其进行变更。当数据表信息变动时
Tools -> run manage.py task 下依次执行命令:
& makemigrations
& migrate
————————————————————————————————————————————————————————————————————————————————————
转载请注明: StormSha » Django个人博客开发六 | 数据库结构设计