学习怎么去使用 Python 的 web 框架中的对象关系映射与你的数据库交互,就像你使用 SQL 一样。
你可能听说过 Django,它是一个被称为“完美主义者的最后期限” 的 Python web 框架。它是一匹 可爱的小矮马。
Django 的一个强大的功能是它的 对象关系映射 Object-Relational Mapper (ORM),它允许你就像使用 SQL 一样去和你的数据库交互。事实上,Django 的 ORM 就是创建 SQL 去查询和操作数据库的一个 Python 式方式,并且获得 Python 风格的结果。 我说的是一种方式,但实际上,它是一种非常聪明的工程方法,它利用了 Python 中一些很复杂的部分,而使得开发者更加轻松。
在我们开始去了解 ORM 是怎么工作之前,我们需要一个可以操作的数据库。和任何一个关系型数据库一样,我们需要去定义一堆表和它们的关系(即,它们相互之间联系起来的方式)。让我们使用我们熟悉的东西。比如说,我们需要去建模一个有博客文章和作者的博客。每个作者有一个名字。一位作者可以有很多的博客文章。一篇博客文章可以有很多的作者、标题、内容和发布日期。
在 Django 村里,这个文章和作者的概念可以被称为博客应用。在这个语境中,一个应用是一个自包含一系列描述我们的博客行为和功能的模型和视图的集合。用正确的方式打包,以便于其它的 Django 项目可以使用我们的博客应用。在我们的项目中,博客正是其中的一个应用。比如,我们也可以有一个论坛应用。但是,我们仍然坚持我们的博客应用的原有范围。
这是为这个教程事先准备的 models.py
:
from django.db import models
class Author(models.Model):
name = models.CharField(max_length=100)
def __str__(self):
return self.name
class Post(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
published_date = models.DateTimeField(blank=True, null=True)
author = models.ManyToManyField(Author, related_name="posts")
def __str__(self):
return self.title
现在,看上去似乎有点令人恐惧,因此,我们把它分解来看。我们有两个模型:作者(Author
)和文章(Post
)。它们都有名字(name
)或者标题(title
)。文章有个放内容的大的文本字段,以及用于发布时间和日期的 DateTimeField
。文章也有一个 ManyToManyField
,它同时链接到文章和作者。
大多数的教程都是从头开始的,但是,在实践中并不会发生这种情况。实际上,你会得到一堆已存在的代码,就像上面的 model.py
一样,而你必须去搞清楚它们是做什么的。
因此,现在你的任务是去进入到应用程序中去了解它。做到这一点有几种方法,你可以登入到 Django admin,这是一个 Web 后端,它会列出全部的应用和操作它们的方法。我们先退出它,现在我们感兴趣的东西是 ORM。
我们可以在 Django 项目的主目录中运行 python manage.py shell
去访问 ORM。
/srv/web/django/ $ python manage.py shell
Python 3.6.3 (default, Nov 9 2017, 15:58:30)
[GCC 4.2.1 Compatible Apple LLVM 9.0.0 (clang-900.0.38)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>>
这将带我们进入到交互式控制台。shell
命令 为我们做了很多设置,包括导入我们的设置和配置 Django 环境。虽然我们启动了 shell,但是,在我们导入它之前,我们并不能访问我们的博客模型。
>>> from blog.models import *
它导入了全部的博客模型,因此,我们可以玩我们的博客了。
首先,我们列出所有的作者:
>>> Author.objects.all()
我们将从这个命令取得结果,它是一个 QuerySet
,它列出了我们所有的作者对象。它不会充满我们的整个控制台,因为,如果有很多查询结果,Django 将自动截断输出结果。
>>> Author.objects.all()
>> Author.objects.get(name="VM (Vicky) Brasseur")
到现在为止,我们已经有了一个我们可以交互的对象,而不是一个 QuerySet
列表。我们现在可以与这个 Python 对象进行交互了,使用任意一个表列做为属性去查看对象。
>>> vmb = Author.objects.get(name="VM (Vicky) Brasseur")
>>> vmb.name
u'VM (Vicky) Brasseur'
然后,很酷的事件发生了。通常在关系型数据库中,如果我们希望去展示其它表的信息,我们需要去写一个 LEFT JOIN
,或者其它的表耦合函数,并确保它们之间有匹配的外键。而 Django 可以为我们做到这些。
在我们的模型中,由于作者写了很多的文章,因此,我们的作者对象可以检索他自己的文章。
>>> vmb.posts.all()
QuerySet[,
,
,
'...(remaining elements truncated)...']
我们可以使用正常的 Python 式的列表操作方式来操作 QuerySets
。
>>> for post in vmb.posts.all():
... print(post.title)
...
7 tips for nailing your job interview
5 tips for getting the biggest bang for your cover letter buck
Quit making these 10 common resume mistakes
要实现更复杂的查询,我们可以使用过滤得到我们想要的内容。这有点复杂。在 SQL 中,你可以有一些选项,比如,like
、contains
和其它的过滤对象。在 ORM 中这些事情也可以做到。但是,是通过 特别的 方式实现的:是通过使用一个隐式(而不是显式)定义的函数实现的。
如果在我的 Python 脚本中调用了一个函数 do_thing()
,我会期望在某个地方有一个匹配的 def do_thing
。这是一个显式的函数定义。然而,在 ORM 中,你可以调用一个 不显式定义的 函数。之前,我们使用 name
去匹配一个名字。但是,如果我们想做一个子串搜索,我们可以使用 name__contains
。
>>> Author.objects.filter(name__contains="Vic")
QuerySet[,