使用python和Django完成博客数据库的迁移方法


Posted in Python onJanuary 05, 2018

上一讲完成了基本博客的配置和项目工程的生成。这次开始将博客一些基本的操作主要是数据库方面学习。

1.设计博客数据库表结构

博客最主要的功能就是展示我们写的文章,它需要从某个地方获取博客文章数据才能把文章展示出来,通常来说这个地方就是数据库。我们把写好的文章永久地保存在数据库里,当用户访问我们的博客时,Django 就去数据库里把这些数据取出来展现给用户。

博客的文章应该含有标题、正文、作者、发表时间等数据。一个更加现代化的博客文章还希望它有分类、标签、评论等。为了更好地存储这些数据,我们需要合理地组织数据库的表结构。

我们的博客初级版本主要包含博客文章,文章会有分类以及标签。一篇文章只能有一个分类,但可以打上很多标签。

文章 id 标题 正文 发表时间 分类 标签
1 title 1 text 1 2016-12-23 Django Django 学习
2 title 2 text 2 2016-12-24 Django Django 学习
3 title 3 text 3 2016-12-26 Python Python 学习

其中文章 ID 是一个数字,唯一对应着一篇文章。当然还可以有更多的列以存储更多相关数据,这只是一个最基本的示例。

数据库表设计成这样其实已经可以了,但是稍微分析一下我们就会发现一个问题,这 3 篇文章的分类和标签都是相同的,这会产生很多重复数据,当数据量很大时就浪费了存储空间。

不同的文章可能它们对应的分类或者标签是相同的,所以我们把分类和标签提取出来,做成单独的数据库表,再把文章和分类、标签关联起来。下面分别是分类和标签的数据库表:

分类 id 分类名

1 Django
2 Python

标签 id 标签名

1 Django 学习
2 Python 学习

接下来就是编写我们的数据库模型:

以上是自然语言描述的表格,数据库也和编程语言一样,有它自己的一套规定的语法来生成上述的表结构,这样我们才能把数据存进去。一般来说这时候我们应该先去学习数据库创建表格的语法,再回来写我们的 Django 博客代码了。但是 Django 告诉我们不用这么麻烦,它已经帮我们做了一些事情。Django 把那一套数据库的语法转换成了 Python 的语法形式,我们只要写 Python 代码就可以了,Django 会把 Python 代码翻译成对应的数据库操作语言。用更加专业一点的说法,就是 Django 为我们提供了一套 ORM(Object Relational Mapping)系统。

例如我们的分类数据库表,Django 只要求我们这样写:

blog/models.py
from django.db import models
class Category(models.Model):
 name = models.CharField(max_length=100)

给出完整的代码:

from django.db import models
from django.contrib.auth.models import User
from django.utils.six import python_2_unicode_compatible

# python_2_unicode_compatible 装饰器用于兼容 Python2
@python_2_unicode_compatible
class Category(models.Model):
 """
 Django 要求模型必须继承 models.Model 类。
 Category 只需要一个简单的分类名 name 就可以了。
 CharField 指定了分类名 name 的数据类型,CharField 是字符型,
 CharField 的 max_length 参数指定其最大长度,超过这个长度的分类名就不能被存入数据库。
 当然 Django 还为我们提供了多种其它的数据类型,如日期时间类型 DateTimeField、整数类型 IntegerField 等等。
 Django 内置的全部类型可查看文档:
 https://docs.djangoproject.com/en/1.10/ref/models/fields/#field-types
 """
 name = models.CharField(max_length=100)
 def __str__(self):
 return self.name

@python_2_unicode_compatible
class Tag(models.Model):
 """
 标签 Tag 也比较简单,和 Category 一样。
 再次强调一定要继承 models.Model 类!
 """
 name = models.CharField(max_length=100)
 def __str__(self):
 return self.name

@python_2_unicode_compatible
class Post(models.Model):
 """
 文章的数据库表稍微复杂一点,主要是涉及的字段更多。
 """
 # 文章标题
 title = models.CharField(max_length=70)
 # 文章正文,我们使用了 TextField。
 # 存储比较短的字符串可以使用 CharField,但对于文章的正文来说可能会是一大段文本,因此使用 TextField 来存储大段文本。
 body = models.TextField()
 # 这两个列分别表示文章的创建时间和最后一次修改时间,存储时间的字段用 DateTimeField 类型。
 created_time = models.DateTimeField()
 modified_time = models.DateTimeField()
 # 文章摘要,可以没有文章摘要,但默认情况下 CharField 要求我们必须存入数据,否则就会报错。
 # 指定 CharField 的 blank=True 参数值后就可以允许空值了。
 excerpt = models.CharField(max_length=200, blank=True)
 # 这是分类与标签,分类与标签的模型我们已经定义在上面。
 # 我们在这里把文章对应的数据库表和分类、标签对应的数据库表关联了起来,但是关联形式稍微有点不同。
 # 我们规定一篇文章只能对应一个分类,但是一个分类下可以有多篇文章,所以我们使用的是 ForeignKey,即一对多的关联关系。
 # 而对于标签来说,一篇文章可以有多个标签,同一个标签下也可能有多篇文章,所以我们使用 ManyToManyField,表明这是多对多的关联关系。
 # 同时我们规定文章可以没有标签,因此为标签 tags 指定了 blank=True。
 # 如果你对 ForeignKey、ManyToManyField 不了解,请看教程中的解释,亦可参考官方文档:
 # https://docs.djangoproject.com/en/1.10/topics/db/models/#relationships
 category = models.ForeignKey(Category)
 tags = models.ManyToManyField(Tag, blank=True)
 # 文章作者,这里 User 是从 django.contrib.auth.models 导入的。
 # django.contrib.auth 是 Django 内置的应用,专门用于处理网站用户的注册、登录等流程,User 是 Django 为我们已经写好的用户模型。
 # 这里我们通过 ForeignKey 把文章和 User 关联了起来。
 # 因为我们规定一篇文章只能有一个作者,而一个作者可能会写多篇文章,因此这是一对多的关联关系,和 Category 类似。
 author = models.ForeignKey(User)
 def __str__(self):
 return self.title

Category 就是一个标准的 Python 类,它继承了 models.Model 类,类名为 Category 。Category 类有一个属性 name,它是 models.CharField 的一个实例。

这样,Django 就可以把这个类翻译成数据库的操作语言,在数据库里创建一个名为 category 的表格,这个表格的一个列名为 name。还有一个列 id,Django 则会自动创建。可以看出从 Python 代码翻译成数据库语言时其规则就是一个 Python 类对应一个数据库表格,类名即表名,类的属性对应着表格的列,属性名即列名。

我们需要 3 个表格:文章(Post)、分类(Category)以及标签(Tag),下面就来分别编写它们对应的 Python 类。模型的代码通常写在相关应用的 models.py 文件里。

二:迁移数据库

为了让 Django 完成翻译,创建好这些数据库表,我们再一次请出我的工程管理助手 manage.py。激活虚拟环境,切换到 manage.py 文件所在的目录下,分别运行 python manage.py makemigrations 和 python manage.py migrate 命令:

使用python和Django完成博客数据库的迁移方法

注意:如果代码中含有中文注释,且你使用的是 Python 2 开发环境的话,会得到一个编码错误。因此请在含有中文注释的文件最开始处加入编码声明:# coding: utf-8。

当我们执行了 python manage.py makemigrations 后,Django 在 blog 应用的 migrations\ 目录下生成了一个 0001_initial.py 文件,这个文件是 Django 用来记录我们对模型做了哪些修改的文件。目前来说,我们在 models.py 文件里创建了 3 个模型类,Django 把这些变化记录在了 0001_initial.py 里。

不过此时还只是告诉了 Django 我们做了哪些改变,为了让 Django 真正地为我们创建数据库表,接下来又执行了 python manage.py migrate 命令。Django 通过检测应用中 migrations\ 目录下的文件,得知我们对数据库做了哪些操作,然后它把这些操作翻译成数据库操作语言,从而把这些操作作用于真正的数据库。

你可以看到命令的输出除了 Applying blog.0001_initial... OK 外,Django 还对其它文件做了操作。这是因为除了我们自己建立的 blog 应用外,Django 自身还内置了很多应用,这些应用本身也是需要存储数据的。可以在 settings.py 的 INSTALLED_APP 设置里看到这些应用,当然我们目前不必关心这些。

blogproject/settings.py
INSTALLED_APPS = [
 'django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'blog',
]

对于了解数据库语言的人,你可以运行下面的命令看看 Django 究竟为我们做了什么:

python manage.py sqlmigrate blog 0001

你将看到输出了经 Django 翻译后的数据库表创建语句,这有助于你理解 Django ORM 的工作机制。

使用python和Django完成博客数据库的迁移方法

三:选择数据库版本

没有安装任何的数据库软件,Django 就帮我们迁移了数据库。这是因为我们使用了 Python 内置的 SQLite3 数据库。

SQLite3 是一个十分轻巧的数据库,它仅有一个文件。你可以看一到项目根目录下多出了一个 db.sqlite3 的文件,这就是 SQLite3 数据库文件,Django 博客的数据都会保存在这个数据库文件里。

Django 在 settings.py 里为我们做了一些默认的数据库配置:

blogproject/settings.py
## 其它配置选项...
DATABASES = {
 'default': {
 'ENGINE': 'django.db.backends.sqlite3',
 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
 }
}
## 其它配置选项...

可以看到默认的数据库引擎就是使用的 SQLite3。

当然一些人倾向于使用 MySQL 等大型数据库,至于 Django 如何配置 MySQL 这里就不赘述了,你可以自行使用搜索引擎或者查阅 Django 的官方文档解决。对于一个小型博客而言,SQLite3 数据库足以胜任。

四:用Django方式操作数据库

数据库最主要的操作就是往里面存入数据、从中取出数据、修改已保存的数据和删除不再需要的数据。和创建数据库表一样,Django 为这些操作提供了一整套方法,从而把我们从数据库语言中解放出来。我们不用学习如何利用数据库语言去完成这些操作,只要简单地调用几个 Python 函数就可以满足我们的需求。

存数据

先在命令行中来探索一下这些函数,感受一下如何用 Django 的方式来操作数据库。在 manage.py 所在目录下运行 python manage.py shell 命令:

创建一个分类和一个标签:

使用python和Django完成博客数据库的迁移方法

首先导入 3 个之前写好的模型类,然后实例化了一个 Category 类和一个 Tag 类,为他们的属性 name 赋了值。为了让 Django 把这些数据保存进数据库,调用实例的 save 方法即可。

再创建一篇文章试试,但创建文章之前,我们需要先创建一个 User,用于指定文章的作者。创建 User 的命令 Django 已经帮我们写好了,依然是通过 manage.py 来运行。首先按住 Ctrl + c 退出命令交互栏(一次退不出就连续多按几次),运行 python manage.py createsuperuser 命令并根据提示创建用户:

使用python和Django完成博客数据库的迁移方法

(密码过于简单会通不过)

再次运行 python manage.py shell 进入 Python 命令交互栏,开始创建文章:

使用python和Django完成博客数据库的迁移方法

由于我们重启了 shell,因此需要重新导入了 CategoryTagPost 以及 User。我们还导入了一个 Django 提供的辅助模块 timezone,这是因为我们需要调用它的 now() 方法为 created_timemodified_time 指定时间,容易理解 now 方法返回当前时间。然后我们根据用户名和分类名,通过 get 方法取出了存在数据库中的 UserCategory(取数据的方法将在下面介绍)。接着我们为文章指定了 titlebodycreated_timemodified_time值,并把它和前面创建的 Category 以及 User 关联了起来。允许为空 excerpttags 我们就没有为它们指定值了。

注意:我们这里使用 get 方法根据 Categoryname 属性的值获取分类的一条记录。Category.objects.get(name='category test') 的含义是从数据库中取出 name 的值为 category test 的分类记录。确保数据库中只有一条值为 category test 的记录,否则 get 方法将返回一个 MultipleObjectsReturned 异常。如果你不小心已经存了多条记录,请删掉多余的记录。如何删除数据请看下文。

取数据

数据已经存入数据库了,现在要把它们取出来看看:

使用python和Django完成博客数据库的迁移方法

objects 是我们的模型管理器,它为我们提供一系列从数据库中取数据方法,这里我们使用了 all 方法,表示我们要把对应的数据全部取出来。可以看到 all 方法都返回了数据,这些数据应该是我们之前存进去的,但是显示的字符串有点奇怪,无法看出究竟是不是我们之前存入的数据。为了让显示出来的数据更加人性化一点,我们为 3 个模型分别增加一个 __str__ 方法:

from django.db import models
from django.contrib.auth.models import User
from django.utils.six import python_2_unicode_compatible

# python_2_unicode_compatible 装饰器用于兼容 Python2
@python_2_unicode_compatible
class Category(models.Model):
 """
 Django 要求模型必须继承 models.Model 类。
 Category 只需要一个简单的分类名 name 就可以了。
 CharField 指定了分类名 name 的数据类型,CharField 是字符型,
 CharField 的 max_length 参数指定其最大长度,超过这个长度的分类名就不能被存入数据库。
 当然 Django 还为我们提供了多种其它的数据类型,如日期时间类型 DateTimeField、整数类型 IntegerField 等等。
 Django 内置的全部类型可查看文档:
 https://docs.djangoproject.com/en/1.10/ref/models/fields/#field-types
 """
 name = models.CharField(max_length=100)
 def __str__(self):
 return self.name

@python_2_unicode_compatible
class Tag(models.Model):
 """
 标签 Tag 也比较简单,和 Category 一样。
 再次强调一定要继承 models.Model 类!
 """
 name = models.CharField(max_length=100)
 def __str__(self):
 return self.name

@python_2_unicode_compatible
class Post(models.Model):
 """
 文章的数据库表稍微复杂一点,主要是涉及的字段更多。
 """
 # 文章标题
 title = models.CharField(max_length=70)
 # 文章正文,我们使用了 TextField。
 # 存储比较短的字符串可以使用 CharField,但对于文章的正文来说可能会是一大段文本,因此使用 TextField 来存储大段文本。
 body = models.TextField()
 # 这两个列分别表示文章的创建时间和最后一次修改时间,存储时间的字段用 DateTimeField 类型。
 created_time = models.DateTimeField()
 modified_time = models.DateTimeField()
 # 文章摘要,可以没有文章摘要,但默认情况下 CharField 要求我们必须存入数据,否则就会报错。
 # 指定 CharField 的 blank=True 参数值后就可以允许空值了。
 excerpt = models.CharField(max_length=200, blank=True)
 # 这是分类与标签,分类与标签的模型我们已经定义在上面。
 # 我们在这里把文章对应的数据库表和分类、标签对应的数据库表关联了起来,但是关联形式稍微有点不同。
 # 我们规定一篇文章只能对应一个分类,但是一个分类下可以有多篇文章,所以我们使用的是 ForeignKey,即一对多的关联关系。
 # 而对于标签来说,一篇文章可以有多个标签,同一个标签下也可能有多篇文章,所以我们使用 ManyToManyField,表明这是多对多的关联关系。
 # 同时我们规定文章可以没有标签,因此为标签 tags 指定了 blank=True。
 # 如果你对 ForeignKey、ManyToManyField 不了解,请看教程中的解释,亦可参考官方文档:
 # https://docs.djangoproject.com/en/1.10/topics/db/models/#relationships
 category = models.ForeignKey(Category)
 tags = models.ManyToManyField(Tag, blank=True)
 # 文章作者,这里 User 是从 django.contrib.auth.models 导入的。
 # django.contrib.auth 是 Django 内置的应用,专门用于处理网站用户的注册、登录等流程,User 是 Django 为我们已经写好的用户模型。
 # 这里我们通过 ForeignKey 把文章和 User 关联了起来。
 # 因为我们规定一篇文章只能有一个作者,而一个作者可能会写多篇文章,因此这是一对多的关联关系,和 Category 类似。
 author = models.ForeignKey(User)
 def __str__(self):
 return self.title

定义好 __str__ 方法后,解释器显示的内容将会是 __str__ 方法返回的内容。这里 Category 返回分类名 nameTag 返回标签名,而 Post 返回它的 title

python_2_unicode_compatible 装饰器用于兼容 Python2。如果你使用的 Python3 开发环境,去掉这个装饰器不会有任何影响。如果你使用的 Python2 开发环境,而又不想使用这个装饰器,则将 __str__ 方法改为 __unicode__ 方法即可。

先按 Ctrl + c 退出 Shell,再重新运行 python manage.py shell 进入 Shell。

使用python和Django完成博客数据库的迁移方法

改数据:

使用python和Django完成博客数据库的迁移方法

首先通过 get 方法根据分类名 name 获取值为 category test 到分类,修改它的 name 属性为新的值 category test new,然后调用 save 方法把修改保存到数据库,之后可以看到数据库返回的数据已经是修改后的值了。TagPost的修改也一样。

删除数据:

使用python和Django完成博客数据库的迁移方法

先根据标题 title 的值从数据库中取出 Post,保存在变量 p 中,然后调用它的delete 方法,最后看到 Post.objects.all() 返回了一个空的 QuerySet(类似于一个列表),表明数据库中已经没有 Post,Post 已经被删除了。

这就是 Django 对数据库增、删、改、查的操作。除了上述演示的方法外,Django 还为我们提供了大量其它的方法,这些方法有一部分会在教程中使用,用到时我会讲解它们的用法。但以后你开发自己的项目时,你就需要通过阅读 Django 的官方文档 来了解有哪些方法可用以及如何使用它们。

以上这篇使用python和Django完成博客数据库的迁移方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python挑选文件夹里宽大于300图片的方法
Mar 05 Python
python使用自定义user-agent抓取网页的方法
Apr 15 Python
介绍Python中的文档测试模块
Apr 28 Python
python下调用pytesseract识别某网站验证码的实现方法
Jun 06 Python
Python开发的实用计算器完整实例
May 10 Python
Python编程求质数实例代码
Jan 31 Python
深入分析python数据挖掘 Json结构分析
Apr 21 Python
python过滤中英文标点符号的实例代码
Jul 15 Python
如何在python中实现随机选择
Nov 02 Python
python中count函数简单的实例讲解
Feb 06 Python
Python3中的f-Strings增强版字符串格式化方法
Mar 04 Python
Python数据分析之pandas函数详解
Apr 21 Python
Python3多线程爬虫实例讲解代码
Jan 05 #Python
python编写微信远程控制电脑的程序
Jan 05 #Python
使用python爬虫实现网络股票信息爬取的demo
Jan 05 #Python
简单实现python收发邮件功能
Jan 05 #Python
5款非常棒的Python工具
Jan 05 #Python
Python基于列表模拟堆栈和队列功能示例
Jan 05 #Python
Django 2.0版本的新特性抢先看!
Jan 05 #Python
You might like
构建简单的Webmail系统
2006/10/09 PHP
在PHP中执行系统外部命令
2006/10/09 PHP
PHP 魔术函数使用说明
2010/05/14 PHP
使用PHPExcel操作Excel用法实例分析
2015/03/26 PHP
详解Yii2高级版引入bootstrap.js的一个办法
2017/03/21 PHP
jquery UI 1.72 之datepicker
2009/12/29 Javascript
jQuery实现页面顶部显示的进度条效果完整实例
2015/12/09 Javascript
AngularJS中的JSONP实例解析
2016/12/01 Javascript
完美解决node.js中使用https请求报CERT_UNTRUSTED的问题
2017/01/08 Javascript
Vue组件tree实现树形菜单
2017/04/13 Javascript
react-router中的属性详解
2017/06/01 Javascript
Vue.js学习记录之在元素与template中使用v-if指令实例
2017/06/27 Javascript
Laravel整合Bootstrap 4的完整方案(推荐)
2018/01/25 Javascript
微信小程序将字符串生成二维码图片的操作方法
2018/07/17 Javascript
iview tabs 顶部导航栏和模块切换栏的示例代码
2019/03/04 Javascript
Flutter 超实用简单菜单弹出框 PopupMenuButton功能
2019/08/06 Javascript
layui 动态设置checbox 选中状态的例子
2019/09/02 Javascript
[43:24]VG vs Serenity 2018国际邀请赛小组赛BO2 第二场 8.17
2018/08/20 DOTA
[05:26]TI10典藏宝瓶套装外观展示
2020/07/03 DOTA
linux系统使用python监测系统负载脚本分享
2014/01/15 Python
python的即时标记项目练习笔记
2014/09/18 Python
Using Django with GAE Python 后台抓取多个网站的页面全文
2016/02/17 Python
对Python3中bytes和HexStr之间的转换详解
2018/12/04 Python
pyqt5之将textBrowser的内容写入txt文档的方法
2019/06/21 Python
Pytorch加载部分预训练模型的参数实例
2019/08/18 Python
将keras的h5模型转换为tensorflow的pb模型操作
2020/05/25 Python
来自美国主售篮球鞋的零售商店:KICKSUSA
2017/11/28 全球购物
SQL Server里面什么样的视图才能创建索引
2015/04/17 面试题
个人简历的自荐信
2013/10/23 职场文书
大学生创业计划书的用途
2014/01/08 职场文书
个人简历中自我评价
2014/02/11 职场文书
投标人廉洁自律承诺书
2014/05/26 职场文书
乡镇综治宣传月活动总结
2014/07/02 职场文书
护士节慰问信
2015/02/15 职场文书
祝福语集锦:送给闺蜜的生日祝福语
2019/10/08 职场文书
使用RedisTemplat实现简单的分布式锁
2021/11/20 Redis