一、功能分析
今天主要做数据库的设计与实现,这一块需要数据库的基础知识了,如果要讲解篇幅就大了,有兴趣的朋友看一下推荐阅读,有基础的朋友可以看下面的思维导图来分析。
推荐阅读: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_DESCRIPTION
、SITE_KEYWORDS
、AUTH_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
参数限定长度。
四、注意事项
关于博客表有以下几点需要注意的:
- 标题应当限定长度,我们设定最大值为100
- 内容不用限定长度,因此用的是TextField字段
- 修改时间直接设定成,auto_now=True,在你修改时,会自动变成当前时间。
- 关于ForeignKey与ManyToManyField,请自行查看相关文档资料
五、编写 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 ->点击下方的 "+"号 ->搜索pillow
和django-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
即可。
转载:https://blog.csdn.net/yxys01/article/details/105737645