Django3.0+Python3.8+MySQL8.0 个人博客搭建六|数据库结构设计

一、功能分析

今天主要做数据库的设计与实现,这一块需要数据库的基础知识了,如果要讲解篇幅就大了,有兴趣的朋友看一下推荐阅读,有基础的朋友可以看下面的思维导图来分析。

推荐阅读:Mysql数据库基础知识 数据库表设计

我们直接从想学习的目标博客网站的功能上分析,看看这个博客网站需要建立哪些表,每个表中都需要什么字段。

First:博文

最主要的是我们的博文表,名字可以直接叫做 article,这个表中,肯定要包括以下几点:

  • 博文的标题
  • 博文的内容
  • 博文的发表时间
  • 博文的修改时间
  • 博文的分类
  • 博文的阅读量
  • 博文喜欢量
  • 博文作者等

Second:分类

针对博文的分类,我们可以参考csdn博客系统。

一篇博文只能有一个分类,但是可以有多个标签。

比如我现在写的这篇博文,可以分类到 django 下,但是它可以有多个标签:django、博客、数据库、开发……

考虑到每一篇博文都只能有一个分类,而一个分类下是可以包含很多博文的,因此分类与博文是一对多的关系,此时应当使用外键来进行关联。

而一篇博文可以有多个标签, 每个标签也可以包含多个博文,因此,标签与博文是多对多的关系。

关于一对多与多对多的知识话题,这里就不再展开了,不了解的查看 Django文档 与相关资料。

推荐阅读:Django官方文档 Django中文文档

Third:SEO

针对网站优化,那么一个网站最基本的SEO就是设置TDK

T: 网站页面 title

D: 网站页面描述

K: 网站页面Keywords,也即网站涵盖的主题

要实现SEO,则需要一个页面关键字表 Keyword,一个页面可能包含多个主题,一个主题可能在多个页面出现,所以应该是多对多的关系,称作 Keyword表。

目标博客网站导航栏菜单存在下拉菜单,下拉菜单即是博文分类,这里的导航栏菜单也需要一个表,因为这个表就是为了给博文分类归类的,称作 Bigcategory表。

观察目标博客导航栏下边还有一个公告栏,公告也需要一个表,它和任何表都没关系,称作 Activate表。

公告下边是幻灯片,思考了一下,这个幻灯片应该和别的表也没啥关系,称作 Carousel表。

右侧还有一个友情链接功能,需要一个表,友链和其它表也无关系,称作 FriendLink表。

因此,通过上述分析,我们可以确定出这些数据表,

  • 博客(Article)
  • 分类(Category)
  • 标签(Tag)
  • 导航(Bigcategory)
  • 文章关键词 (Keyword)
  • 公告(Activate)
  • 幻灯片(Carousel)
  • 友链(FriendLink)

二、数据库设计的思维导图

数据库思维导图

三、编写 fswy 应用模型

blog -> fswy -> models.py

头文件引入模块:

from django.db import models
from django.conf import settings
from django.shortcuts import reverse

import markdown
import re

由于 Article 表包含外键与多对多关系,因此首先应当建立另外两个表:Category表和Bigcategory表。

由于 Category 分类表包含外键,因此首先需要创建导航菜单表 Bigcategory

导航(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

分类(Category)表的创建:

# 导航栏,分类下的下拉菜单分类
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='大分类', on_delete=models.CASCADE)

    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="作者", on_delete=models.CASCADE)
    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='文章分类',on_delete=models.CASCADE)
    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={'sulg': self.slug})

    def body_to_markdown(self):
        return markdown.markdown(self.body, extension=[
            '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'])

提示:

fswy -> models.py 中出现的 SITE_DESCRIPTIONSITE_KEYWORDSAUTH_USER_MODEL,把它们当作默认字段放在 setting.py 中,便于管理

blog -> blog -> settings.py

# 网站描述,用于SEO
SITE_DESCRIPTION = "Fswy的个人网站,记录生活的瞬间,分享学习的心得"

# 网站关键词,用于SEO
SITE_KEYWORDS = "Fswy,网络,IT,技术,博客,Python,iOS"

# 作者(网站注册用户)
AUTH_USER_MODEL = 'user.Ouser'

在文件首部 # 引入 setings.py 文件,即可使用这些字段

from django.conf import settings

以上的类名代表了数据库表名,且继承了models.Model,类里面的字段代表数据表中的字段(name),数据类型则由CharField(相当于varchar)、DateField(相当于datetime),max_length 参数限定长度。

四、注意事项

关于博客表有以下几点需要注意的:

  1. 标题应当限定长度,我们设定最大值为100
  2. 内容不用限定长度,因此用的是TextField字段
  3. 修改时间直接设定成,auto_now=True,在你修改时,会自动变成当前时间。
  4. 关于ForeignKey与ManyToManyField,请自行查看相关文档资料

Django官方文档 Django中文文档

五、编写 user 用户应用模型

另外,文章有一个作者外键:

author = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name='作者')

这个外键是网站注册用户,这样用户也可以有发文权限。

这里创建一个用户app比较好。

创建app可以参考:Django3.0+Python3.8+MySQL8.0 个人博客搭建四|创建第一个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

# Create your models here.
# 继承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
注意:

这里导入imagekit时,发现报错。

需要先安装pillow

(fswy) blog xiatian$ pip3 install pillow
Collecting pillow
......
Successfully installed pillow-7.1.1

然后安装django-imagekit

(fswy) blog xiatian$ pip3 install django-imagekit
Collecting django-appconf>=0.5 (from django-imagekit)
......
Successfully installed django-appconf-1.0.4 django-imagekit-4.0.2 pilkit-2.0 six-1.14.0

这时发现,PyCharm中imagekit还是在报错

解决方案:

PyCharm->Perferences ->项目:blog ->点击下方的 "+"号 ->搜索pillowdjango-imagekit,分别Install Package
在这里插入图片描述
最后注意:

settings.py中的INSTRALLED_APPS添加上:'imagekit'.

在这里插入图片描述

六、Django建立数据库

Tools -> run manage.py task 下依次执行命令:

& makemigrations
& migrate

或者在终端执行:

(fswy) blog xiatian$ python3 manage.py makemigrations
(fswy) blog xiatian$ python3 manage.py migrate

注意,一定要先进入虚拟环境哈!!!

当然,由于版本和一些细节原因,在执行makemigrations时,依旧有不少的坑等着我们去填,我将其汇总到:Django3.0+Python3.8+MySQL8.0 个人博客搭建七|makemigrations创建数据库的坑(第二弹)
中,报错的同学可以去参考一下,希望对你们的开发有所帮助。

(fswy) blog xiatian$ python3 manage.py makemigrations
Migrations for 'fswy':
  fswy/migrations/0002_activate_article_bigcategory_carousel_category_friendlink_keyword_tag.py
    - Create model Activate
    - Create model Article
    - Create model BigCategory
    - Create model Carousel
    - Create model FriendLink
    - Create model Keyword
    - Create model Tag
    - Create model Category
  fswy/migrations/0003_auto_20200424_1819.py
    - Add field author to article
    - Add field category to article
    - Add field keywords to article
    - Add field tags to article
Migrations for 'user':
  user/migrations/0001_initial.py
    - Create model Ouser
(fswy) blog xiatian$ python3 manage.py migrate
Operations to perform:
  Apply all migrations: auth, contenttypes, fswy, sessions, user
Running migrations:
  Applying user.0001_initial... OK
  Applying fswy.0002_activate_article_bigcategory_carousel_category_friendlink_keyword_tag... OK
  Applying fswy.0003_auto_20200424_1819... OK

在PyCharm中打开Database,刷新,可以看到如图所示:
在这里插入图片描述

即已经将新建的这些表添加到我们的数据库 blog 中了。

fswy_activate,         # 公告表 
fswy_article,          # 新增的博文表
fswy_article_keywords, # 这个是博文与关键词的多对多关系表
fswy_article_tags,     # 这个是博文与标签的多对多关系表
fswy_bigcategory,      # 导航菜单大分类表
fswy_carousel,         # 幻灯片
fswy_category,         # 新增的分类表
fswy_friendlink,       # 友情链接
fswy_keyword,          # 关键词表
fswy_tag,              # 新增的标签表
user_ouser,             # 新增扩展用户表
user_ouser_groups,      # 自动产生
user_ouser_user_permissions # 自动产生

最后两个表示用户表继承了,Django自带的用户models产生的用户关系表

需要说明的是,这里我们只给出了最开始设计时考虑到的情况,在后续开发过程中,可以随时对其进行变更。当数据表信息变动时
在终端执行:

(fswy) blog xiatian$ python3 manage.py makemigrations
(fswy) blog xiatian$ python3 manage.py migrate

即可。

原创文章 214 获赞 359 访问量 89万+

猜你喜欢

转载自blog.csdn.net/yxys01/article/details/105737645