Django ORM 简介 ============================================================ ### 学习怎么去使用 Python 的 web 框架中的对象关系映射与你的数据库交互,就像你使用 SQL 一样。 ![Getting to know the Django ORM](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/web-spider-frame-framework.png?itok=Rl2AG2Dc "Getting to know the Django ORM") Image by : [Christian Holmér][10]. Modified by Opensource.com. [CC BY-SA 4.0][11] 你可能听说过 [Django][12],它是一个被称为“完美主义者的最后期限” 的 Python web 框架。它是一匹 [可爱的小矮马][13]。 Django 的其中一个强大的功能是它的对象关系映射(ORM),它允许你去和你的数据库交互,就像你使用 SQL 一样。事实上,Django 的 ORM 就是创建 SQL 去查询和维护数据库的一个 Python 的方法,并且在一个 Python 方法中获取结果。 我说 _就是_ 一种方法,但实际上,它是一项非常聪明的工程,它利用了 Python 中比较复杂的部分,使得开发过程更容易。 在我们开始去了解 ORM 是怎么工作的之前,我们需要一个去操作的数据库。和任何一个关系型数据库一样,我们需要去定义一堆表和它们的关系(即,它们相互之间联系起来的方式)。让我们使用我们熟悉的东西。比如说,我们需要去建立一个有博客文章和作者的博客。每个作者有一个名字。一位作者可以有很多的博客文章。一篇博客文章可以有很多的作者、标题、内容和发布日期。 在 Django-ville 中,这个文章和作者的概念可以被称为博客应用。在这个语境中,一个应用是一个自包含一系列描述我们的博客行为和功能的模型和视图。用正确的方式打包,以便于其它的 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 ``` 更多的 Python 资源 * [Python 是什么?][1] * [最好的 Python IDEs][2] * [最好的 Python GUI 框架][3] * [最新的 Python 内容][4] * [更多的开发者资源][5] 现在,看上去似乎有点令人恐惧,因此,我们把它分解来看。我们有两个模型:作者和文章。它们都有名字或者标题。文章为内容设置一个大文本框,以及为发布的时间和日期设置一个 `DateTimeField`。文章也有一个 `ManyToManyField`,它同时链接到文章和作者。 大多数的教程都是从 scratch—but 开始的,但是,在实践中并不会发生这种情况。实际上,它会提供给你一堆已存在的代码,就像上面的 `model.py` 一样,而你必须去搞清楚它们是做什么的。 因此,现在你的任务是去进入到应用程序中去了解它。做到这一点有几种方法,你可以登入到 [Django admin][14],一个 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` 命令][15] 为我们做了很多设置,包括导入我们的设置和配置 Django 环境。虽然我们启动了 shell,但是,在我们导入它之前,我们并不能访问我们的博客模型。 ``` >>> from blog.models import * ``` 它导入了全部的博客模型,因此,我们可以玩我们的博客了。 首先,我们列出所有的作者。 ``` >>> Author.objects.all() ``` 我们将从这个命令取得结果,它是一个 `QuerySet`,它列出了所有我们的作者对象。它不会充满我们的整个控制台,因为,如果有很多查询结果,Django 将自动截断输出结果。 ``` >>> Author.objects.all() ,  , '...(remaining elements truncated)...'] ``` 我们可以使用 `get` 代替 `all` 去检索单个作者。但是,我们需要一些更多的信息去 `get` 一个单个记录。在关系型数据库中,表有一个主键,它唯一标识了表中的每个记录,但是,作者名并不唯一。许多人都 [重名][16],因此,它不是唯一约束的一个好的选择。解决这个问题的一个方法是使用一个序列(1、2、3...)或者一个通用唯一标识符(UUID)作为主键。但是,因为它对人类并不可用,我们可以通过使用 `name` 来操作我们的作者对象。 ``` >>> 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)...'] ``` We can manipulate `QuerySets` using normal pythonic list manipulations. ``` >>> 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[] ``` 现在,关于双下划线(`__`)我有一个小小的提示。这些是 Python _特有的_。在 Python 的世界里,你可以看到如 `__main__` 或者 `__repr__`。这些有时被称为 `dunder methods`,是 “双下划线” 的缩写。这里仅有几个非字母数字字符可以被用于 Python 中的对象名字;下划线是其中的一个。这些在 ORM 中被用于不同的过滤关键字的显式分隔。在底层,字符串被这些下划线分割。并且这个标记是分开处理的。`name__contains` 被替换成 `attribute: name, filter: contains`。在其它编程语言中,你可以使用箭头代替,比如,在 PHP 中是 `name->contains`。不要被双下划线吓着你,正好相反,它们是 Python 的好帮手(并且如果你斜着看,你就会发现它看起来像一条小蛇,想去帮你写代码的小蟒蛇)。 ORM 是非常强大并且是 Python 特有的。不过,在 Django 的管理网站上我提到过上面的内容。 ### [django-admin.png][6] ![Django Admin](https://opensource.com/sites/default/files/u128651/django-admin.png "Django Admin") Django 的其中一个非常精彩的用户可访问特性是它的管理界面,如果你定义你的模型,你将看到一个非常好用的基于 web 的编辑门户,而且它是免费的。 ORM,有多强大? ### [django-admin-author.png][7] ![Authors list in Django Admin](https://opensource.com/sites/default/files/u128651/django-admin-author.png "Authors list in Django Admin") 好吧!给你一些代码去创建最初的模型,Django 转到基于 web 的门户,它是非常强大的,它可以使用我们前面用过的同样的原生函数。默认情况下,这个管理门户只有基本的东西,但这只是在你的模型中添加一些定义去改变外观的问题。例如,在早期的这些 `__str__` 方法中,我们使用这些去定义作者对象应该有什么?(在这种情况中,比如,作者的名字),做了一些工作后,你可以创建一个界面,让它看起来像一个内容管理系统,以允许你的用户去编辑他们的内容。(例如,为一个标记为 “已发布” 的文章,增加一些输入框和过滤)。 如果你想去了解更多内容,[Django 美女的教程][17] 中关于 [the ORM][18] 的节有详细的介绍。在 [Django project website][19] 上也有丰富的文档。 -------------------------------------------------------------------------------- 作者简介: Katie McLaughlin - Katie 在过去的这几年有许多不同的头衔,她以前是使用多种语言的一位软件开发人员,多种操作系统的系统管理员,和多个不同话题的演讲者。当她不改变 “世界” 的时候,她也去享受烹饪、挂毯艺术,和去研究各种应用程序栈怎么去处理 emoji。 ------------------------ via: https://opensource.com/article/17/11/django-orm 作者:[Katie McLaughlin Feed ][a] 译者:[qhwdw](https://github.com/qhwdw) 校对:[校对者ID](https://github.com/校对者ID) 本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出 [a]:https://opensource.com/users/glasnt [1]:https://opensource.com/resources/python?intcmp=7016000000127cYAAQ [2]:https://opensource.com/resources/python/ides?intcmp=7016000000127cYAAQ [3]:https://opensource.com/resources/python/gui-frameworks?intcmp=7016000000127cYAAQ [4]:https://opensource.com/tags/python?intcmp=7016000000127cYAAQ [5]:https://developers.redhat.com/?intcmp=7016000000127cYAAQ [6]:https://opensource.com/file/377811 [7]:https://opensource.com/file/377816 [8]:https://opensource.com/article/17/11/django-orm?rate=iwO0q67yiUUPweMIMoyLbbYyhK5RTOOzEtyiNkJ0eBE [9]:https://opensource.com/user/41661/feed [10]:https://www.flickr.com/people/crsan/ [11]:https://creativecommons.org/licenses/by-sa/4.0/ [12]:https://www.djangoproject.com/ [13]:http://www.djangopony.com/ [14]:https://docs.djangoproject.com/en/1.11/ref/contrib/admin/ [15]:https://docs.djangoproject.com/en/1.11/ref/django-admin/#shell [16]:https://2016.katieconf.xyz/ [17]:https://djangogirls.org/ [18]:https://tutorial.djangogirls.org/en/django_orm/ [19]:https://docs.djangoproject.com/en/1.11/topics/db/ [20]:https://opensource.com/users/glasnt [21]:https://opensource.com/users/glasnt [22]:https://opensource.com/article/17/11/django-orm#comments