本渣渣不专注技术,只专注使用技术,不是一个资深的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个人博客开发六 | 数据库结构设计