Django ORM 和 QuerySets(查询集)

在这一章中,你将学习 Django 如何连接到数据库,并将数据存储在里面。一探究竟吧!

QuerySet 是什么呢?

从本质上说,QuerySet 是给定模型的对象列表(list)。QuerySet 允许您从数据库中读取数据,对其进行筛选以及排序。

用例子来学习最容易的了。让我们试试这个,好吗?

Django shell

打开你本地的终端(不是在Python解析器里面) 然后输入这个命令:

(myvenv) ~/djangogirls$ python manage.py shell

效果应该像这样:

(InteractiveConsole)
>>>

你现在在 Django 的交互式控制台中。它是就像 Python 提示符,但有一些额外神奇的 Django 特性:)。你当然也可以在这里使用所有的 Python 命令。

所有对象

首先让我们尝试显示所有我们的文章。你可以用下面的命令:

>>> Post.objects.all()
Traceback (most recent call last):
      File "<console>", line 1, in <module>
NameError: name 'Post' is not defined

哎呀 !出现了一个错误。它告诉我们没有文章。这是正确的 — — 我们忘了首先导入它 !

>>> from blog.models import Post

这很简单: 我们从 blog.models 导入 Post 的模型。让我们试着再一次显示所有的帖子:

>>> Post.objects.all()
<QuerySet [<Post: my post title>, <Post: another post title>]>

这是我们之前创建的文章的 list 列表!我们通过使用Django admin界面创建了这些文章。但是我们现在想通过Python来创建新的文章,那么我们应该如何做呢?

创建对象

这就是你如何在数据库创建一个新的Post对象的方法:

>>> Post.objects.create(author=me, title='Sample title', text='Test')

但是我们这里有一个遗漏的要素: me。我们需要传递 User 模型的实例作为作者。如何做到这一点?

让我们首先导入用户模型:

>>> from django.contrib.auth.models import User

我们在数据库中有哪些用户?试试这个:

>>> User.objects.all()
<QuerySet [<User: ola>]>

这是一个我们之前创建的超级用户!让我们现在获取一个用户实例:

me = User.objects.get(username='ola')

正如你所看到的,我们现在 get 一个 username 等于 'ola' 的User 。简单吧!当然,你必须将其改为你所使用的用户名。

现在我们终于可以创建我们的文章了:

>>> Post.objects.create(author=me, title='Sample title', text='Test')

哈哈!要检查是否有效吗?

>>> Post.objects.all()
<QuerySet [<Post: my post title>, <Post: another post title>, <Post: Sample title>]>

就是这样,又一个文章在列表里面!

添加更多文章

你现在可以找点乐子,并添加更多的帖子,看它是如何工作。添加 2-3 个并前进到下一个部分。

筛选对象

QuerySets的很大一部分功能是对它们进行筛选。 譬如,我们想要发现所有都由用户ola编写的文章。 我们将使用 filter,而不是 allPost.objects.all()。 我们需要在括号中申明哪些条件,以在我们的 queryset 结果集中包含一篇博客文章。 在我们的情况是 author,它等于 me。 把它写在 Django 的方式是: author = me。 现在我们的代码段如下所示:

>>> Post.objects.filter(author=me)
<QuerySet [<Post: Sample title>, <Post: Post number 2>, <Post: My 3rd post!>, <Post: 4th title of post>]>

或者,也许我们想看到包含在 title 字段标题的所有帖子吗?

>>> Post.objects.filter(title__contains='title')
<QuerySet [<Post: Sample title>, <Post: 4th title of post>]>

titlecontains 之间有两个下划线字符 (_)。 Django 的 ORM 使用此语法来分隔字段名称 ("title") 和操作或筛选器 ("contains")。 如果您只使用一个下划线,您将收到类似"FieldError: 无法解析关键字 title_contains"的错误。

你也可以获取一个所有已发布文章的列表。我们通过筛选所有含published_date为过去时间的文章来实现这个目的:

from django.utils import timezone Post.objects.filter(published_date__lte=timezone.now())[]

不幸的是,通过Python终端添加的文章还没发布。我们可以改变它!首先获取一个我们想要发布的文章实例:

>>> post = Post.objects.get(title="Sample title")

然后将它与我们 publish 的方法一起发布 !

>>> post.publish()

现在再一次尝试获取已发布的文章(按向上箭头按钮三次,然后按回车):

>>> Post.objects.filter(published_date__lte=timezone.now())
<QuerySet [<Post: Sample title>]>

对象排序

Queryset 还允许您排序结果集对象的列表。让我们试着让它们按 created_date 字段排序:

>>> Post.objects.order_by('created_date')
<QuerySet [<Post: Sample title>, <Post: Post number 2>, <Post: My 3rd post!>, <Post: 4th title of post>]>

我们也可以在开头添加 - 来反向排序:

>>> Post.objects.order_by('-created_date')
<QuerySet [<Post: 4th title of post>,  <Post: My 3rd post!>, <Post: Post number 2>, <Post: Sample title>]>

链式 QuerySets

你可以通过链式调用连续组合QuerySets

>>> Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')

这真是强而有力,而且可以让你写较复杂的的查询

酷 !现在,你准备下一个部分 !若要关闭shell程序,请键入这:

>>> exit()
$