咱们已经编写了博客数据库模型的代码,但那还只是 Python 代码而已,Django 尚未把它翻译成数据库语言,所以实际上这些数据库表尚未真正的在数据库中建立。javascript
为了让 Django 完成翻译,建立好这些数据库表,咱们再一次请出个人工程管理助手 manage.py。激活虚拟环境,切换到 manage.py 文件所在的目录下,分别运行 python manage.py makemigrations
和 python manage.py migrate
命令:java
C:\WINDOWS\system32>C:\Users\yangxg\Envs\blogproject_env\Scripts\activate
(blogproject_env) C:\WINDOWS\system32>cd C:\Users\yangxg\Workspace\blogproject
(blogproject_env) C:\Users\yangxg\Workspace\blogproject>python manage.py makemigrations
Migrations for 'blog':
blog\migrations\0001_initial.py:
- Create model Category
- Create model Post
- Create model Tag
- Add field tags to post
(blogproject_env) C:\Users\yangxg\Workspace\blogproject>python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, blog, contenttypes, sessions
Running migrations:
Applying contenttypes.0001_initial... OK
Applying auth.0001_initial... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying auth.0007_alter_validators_add_error_messages... OK
Applying auth.0008_alter_user_username_max_length... OK
Applying blog.0001_initial... OK
Applying sessions.0001_initial... OK复制代码
注意:若是代码中含有中文注释,且你使用的是 Python 2 开发环境的话,会获得一个编码错误。所以请在含有中文注释的文件最开始处加入编码声明:# coding: utf-8。python
当咱们执行了 python manage.py makemigrations
后,Django 在 blog 应用的 migrations\ 目录下生成了一个 0001_initial.py 文件,这个文件是 Django 用来记录咱们对模型作了哪些修改的文件。目前来讲,咱们在 models.py 文件里建立了 3 个模型类,Django 把这些变化记录在了 0001_initial.py 里。git
不过此时还只是告诉了 Django 咱们作了哪些改变,为了让 Django 真正地为咱们建立数据库表,接下来又执行了 python manage.py migrate
命令。Django 经过检测应用中 migrations\ 目录下的文件,得知咱们对数据库作了哪些操做,而后它把这些操做翻译成数据库操做语言,从而把这些操做做用于真正的数据库。github
你能够看到命令的输出除了 Applying blog.0001_initial... OK 外,Django 还对其它文件作了操做。这是由于除了咱们本身创建的 blog 应用外,Django 自身还内置了不少应用,这些应用自己也是须要存储数据的。能够在 settings.py 的 INSTALLED_APP
设置里看到这些应用,固然咱们目前没必要关心这些。sql
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 究竟为咱们作了什么:shell
python manage.py sqlmigrate blog 0001复制代码
你将看到输出了经 Django 翻译后的数据库表建立语句,这有助于你理解 Django ORM 的工做机制。数据库
咱们没有安装任何的数据库软件,Django 就帮咱们迁移了数据库。这是由于咱们使用了 Python 内置的 SQLite3 数据库。django
SQLite3 是一个十分轻巧的数据库,它仅有一个文件。你能够看一到项目根目录下多出了一个 db.sqlite3 的文件,这就是 SQLite3 数据库文件,Django 博客的数据都会保存在这个数据库文件里。session
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 为这些操做提供了一整套方法,从而把咱们从数据库语言中解放出来。咱们不用学习如何利用数据库语言去完成这些操做,只要简单地调用几个 Python 函数就能够知足咱们的需求。
先在命令行中来探索一下这些函数,感觉一下如何用 Django 的方式来操做数据库。在 manage.py 所在目录下运行 python manage.py shell
命令:
(blogproject_env) C:\Users\yangxg\Workspace\blogproject>python manage.py shell
Python 3.5.2 (v3.5.2:4def2a2901a5, Jun 25 2016, 22:18:55) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>>复制代码
这打开了一个交互式命令行。
首先咱们来建立一个分类和一个标签:
>>> from blog.models import Category, Tag, Post
>>> c = Category(name='category test')
>>> c.save()
>>> t = Tag(name='tag test')
>>> t.save()复制代码
咱们首先导入 3 个以前写好的模型类,而后实例化了一个 Category
类和一个 Tag
类,为他们的属性 name
赋了值。为了让 Django 把这些数据保存进数据库,调用实例的 save
方法便可。
再建立一篇文章试试,但建立文章以前,咱们须要先建立一个 User,用于指定文章的做者。建立 User 的命令 Django 已经帮咱们写好了,依然是经过 manage.py 来运行。首先按住 Ctrl + c 退出命令交互栏(一次退不出就连续多按几回),运行 python manage.py createsuperuser
命令并根据提示建立用户:
(blogproject_env) C:\Users\yangxg\Workspace\blogproject>python manage.py createsuperuser
Username (leave blank to use 'zmrenwu@163.com'): myuser
Email address: a@aa.com
Password:
Password (again):
Superuser created successfully.复制代码
运行 python manage.py createsuperuser
开始建立用户,以后会提示你输入用户名、邮箱、密码和确认密码,按照提示输入便可。注意一点的是密码输入过程当中不会有任何字符显示,不要误觉得你的键盘出问题了,正常输入便可。最后出现 Superuser created successfully. 说明用户建立成功了。
再次运行 python manage.py shell
进入 Python 命令交互栏,开始建立文章:
>>> from blog.models import Category, Tag, Post
>>> from django.utils import timezone
>>> from django.contrib.auth.models import User
>>> user = User.objects.get(username='myuser')
>>> c = Category.objects.get(name='category test')
>>> p = Post(title='title test', body='body test', created_time=timezone.now(), modified_time=timezone.now(), category=c, author=user)
>>> p.save()复制代码
因为咱们重启了 shell,所以须要从新导入了 Category
、Tag
、Post
以及 User
。咱们还导入了一个 Django 提供的辅助模块 timezone,这是由于咱们须要调用它的 now()
方法为 created_time
和 modified_time
指定时间,容易理解 now
方法返回当前时间。而后咱们根据用户名和分类名,经过 get
方法取出了存在数据库中的 User
和 Category
(取数据的方法将在下面介绍)。接着咱们为文章指定了 title
、body
、created_time
、modified_time
值,并把它和前面建立的 Category 以及 User 关联了起来。容许为空 excerpt
、tags
咱们就没有为它们指定值了。
注意:咱们这里使用 get
方法根据 Category
的 name
属性的值获取分类的一条记录。Category.objects.get(name='category test')
的含义是从数据库中取出 name
的值为 category test 的分类记录。确保数据库中只有一条值为 category test 的记录,不然 get
方法将返回一个 MultipleObjectsReturned
异常。若是你不当心已经存了多条记录,请删掉多余的记录。如何删除数据请看下文。
数据已经存入数据库了,如今要把它们取出来看看:
>>> Category.objects.all()
<QuerySet [<Category: Category object>]>
>>> Tag.objects.all()
<QuerySet [<Tag: Tag object>]>
>>> Post.objects.all()
<QuerySet [<Post: Post object>]>
>>>复制代码
objects
是咱们的模型管理器,它为咱们提供一系列从数据库中取数据方法,这里咱们使用了 all
方法,表示咱们要把对应的数据所有取出来。能够看到 all
方法都返回了数据,这些数据应该是咱们以前存进去的,可是显示的字符串有点奇怪,没法看出到底是不是咱们以前存入的数据。为了让显示出来的数据更加人性化一点,咱们为 3 个模型分别增长一个 __str__
方法:
blog/models.py
from django.utils.six import python_2_unicode_compatible
# python_2_unicode_compatible 装饰器用于兼容 Python2
@python_2_unicode_compatible
class Category(models.Model):
...
def __str__(self):
return self.name
@python_2_unicode_compatible
class Tag(models.Model):
...
def __str__(self):
return self.name
@python_2_unicode_compatible
class Post(models.Model):
...
def __str__(self):
return self.title复制代码
定义好 __str__
方法后,解释器显示的内容将会是 __str__
方法返回的内容。这里 Category
返回分类名 name
,Tag
返回标签名,而 Post
返回它的 title
。
python_2_unicode_compatible
装饰器用于兼容 Python2。若是你使用的 Python3 开发环境,去掉这个装饰器不会有任何影响。若是你使用的 Python2 开发环境,而又不想使用这个装饰器,则将 __str__
方法改成 __unicode__
方法便可。
先按 Ctrl + c 退出 Shell,再从新运行 python manage.py shell
进入 Shell。
>>> from blog.models import Category, Tag, Post
>>> Category.objects.all()
<QuerySet [<Category: category test>]>
>>> Tag.objects.all()
<QuerySet [<Tag: tag test>]>
>>> Post.objects.all()
<QuerySet [<Post: title test>]>
>>> Post.objects.get(title='title test')
<Post: title test>复制代码
能够看到返回的是咱们以前存入的数据。
此外咱们在建立文章时提到了经过 get
方法来获取数据,这里 all
方法和 get
方法的区别是:all
方法返回所有数据,是一个相似于列表的数据结构(QuerySet);而 get
返回一条记录数据,若有多条记录或者没有记录,get
方法均会抛出相应异常。
尝试修改数据:
>>> c = Category.objects.get(name='category test')
>>> c.name = 'category test new'
>>> c.save()
>>> Category.objects.all()
<QuerySet [<Category: test category new>]>复制代码
首先经过 get
方法根据分类名 name
获取值为 category test 到分类,修改它的 name
属性为新的值 category test new,而后调用 save
方法把修改保存到数据库,以后能够看到数据库返回的数据已是修改后的值了。Tag
、Post
的修改也同样。
删除掉数据:
>>> p = Post.objects.get(title='title test')
>>> p
<Post: title test>
>>> p.delete()
(1, {'blog.Post_tags': 0, 'blog.Post': 1})
>>> Post.objects.all()
<QuerySet []>复制代码
先根据标题 title
的值从数据库中取出 Post
,保存在变量 p
中,而后调用它的delete
方法,最后看到 Post.objects.all()
返回了一个空的 QuerySet(相似于一个列表),代表数据库中已经没有 Post,Post 已经被删除了。
这就是 Django 对数据库增、删、改、查的操做。除了上述演示的方法外,Django 还为咱们提供了大量其它的方法,这些方法有一部分会在教程中使用,用到时我会讲解它们的用法。但之后你开发本身的项目时,你就须要经过阅读 Django 的官方文档 来了解有哪些方法可用以及如何使用它们。
本章节的代码位于:Step4: make migrations and migrate。
若是遇到问题,请经过下面的方式寻求帮助。