Django ORM 简介

了解如何使用 Python Web 框架的对象关系映射器与数据库交互,就像使用 SQL 一样。
342 位读者喜欢这篇文章。
Getting to know the Django ORM

Christian Holmér。由 Opensource.com 修改。CC BY-SA 4.0

您可能听说过 Django,这个 Python Web 框架是为“追求完美但有截止日期的人”而设计的。它就是那个带有可爱小马的框架。

Django 最强大的功能之一是其对象关系映射器 (ORM),它使您能够像使用 SQL 一样与数据库进行交互。实际上,Django 的 ORM 只是创建 SQL 以查询和操作数据库并以 Pythonic 方式获取结果的一种 Python 式方法。好吧,我说只是一种方法,但它实际上是非常聪明的工程设计,它利用 Python 中一些更复杂的部分来让开发人员的生活更轻松。

在我们开始研究 ORM 的工作原理之前,我们需要一个数据库来操作。与任何关系数据库一样,我们需要定义一堆表及其关系(即,它们彼此关联的方式)。让我们使用一些熟悉的东西。例如,假设我们要建模一个博客,该博客具有博客文章和作者。作者有名字。一位作者可以有多篇博客文章。一篇博客文章可以有多位作者,并且具有标题、内容和发布日期。

在 Django 的世界中,帖子和作者的概念可以称为我们的 Blog 应用程序。在这种情况下,应用程序是一组独立的模型和视图,它们描述了我们博客的行为和功能。以正确的方式打包,许多 Django 项目都可以使用我们的 Blog 应用程序。在我们的项目中,Blog 可能只是一个应用程序。例如,我们可能还有一个 Forum 应用程序。但是我们将坚持 Blog 应用程序的原始范围。

这是一个为此教程准备的 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。每个模型都有一个名称或标题。Post 有一个用于内容的大文本字段和一个用于发布日期和时间的 DateTimeField。Post 还有一个 ManyToManyField,它将帖子和作者链接在一起。

大多数教程都从头开始——但这在实践中不会发生。实际上,您将获得一堆像上面的 model.py 这样的现有代码,并且您必须弄清楚所有这些代码的含义。

因此,您现在的任务是进入应用程序并四处看看。有几种方法可以做到这一点。您可以登录 Django 管理后台,这是一个基于 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,但在导入 Blog 模型之前,我们无法访问它。

>>> from blog.models import *

这将导入所有博客模型,以便我们可以使用我们的博客文章和作者。

首先,让我们获取所有作者的列表。

>>> Author.objects.all()

我们从这个命令得到的是结果的 QuerySet,其中列出了我们所有的 Author 对象。我们也不会填满整个控制台,因为如果有大量结果,Django 会自动截断打印的结果。

>>> Author.objects.all()
<QuerySet [<Author: VM (Vicky) Brasseur>, <Author: Rikki Endsley>,
 <Author: Jen Wike Huger>, '...(remaining elements truncated)...']

我们可以使用 get 而不是 all 来选择单个作者。但是我们需要更多信息才能 get 单个记录。在关系数据库中,表有一个主键字段,该字段为表中的每个记录都有一个唯一标识符;但是,作者姓名不是唯一的。很多人 同名同姓,所以这不是一个好的唯一约束。解决此问题的一种方法是将序列 (1, 2, 3...) 或通用唯一标识符 (UUID) 作为主键。但是由于这些对于人类来说不太好用,我们可以通过使用 name 来操作我们的 Author 对象。

>>> Author.objects.get(name="VM (Vicky) Brasseur")
<Author: VM (Vicky) Brasseur>

这一次,我们有一个可以与之交互的单个对象,而不是 QuerySet 列表。我们可以以 Pythonic 方式与此对象交互,使用任何表列作为属性来查看对象。

>>> vmb = Author.objects.get(name="VM (Vicky) Brasseur")
>>> vmb.name
u'VM (Vicky) Brasseur'

这就是很酷的事情发生的地方。通常在关系数据库中,如果我们想显示其他表的信息,我们需要编写 LEFT JOIN 或其他表耦合函数,以确保我们的外键在表之间匹配。Django 为我们处理了这一点。

在我们的模型中,作者撰写了许多帖子,因此我们的 Author 对象可以检查作者撰写了哪些帖子。

>>> vmb.posts.all()
QuerySet[<Post: "7 tips for nailing your job interview">,
 <Post: "5 tips for getting the biggest bang for your cover letter buck">,
 <Post: "Quit making these 10 common resume mistakes">,
 '...(remaining elements truncated)...']

我们可以使用普通的 Pythonic 列表操作来操作 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 中,您有诸如 likecontains 和其他过滤对象之类的选项。您也可以在 ORM 中执行所有这些操作,但它有一种特殊的方式来执行它们:通过使用隐式(而不是显式)定义的函数。

如果我在我的 Python 脚本中调用一个函数 do_thing(),我希望在某处会有一个匹配的 def do_thing。这是一个显式的函数定义。但是,在 ORM 中,您可以调用一个未显式定义的函数。之前,我们使用 name 来匹配名称。但是,如果我们想进行子字符串搜索,我们可以使用 name__contains

>>> Author.objects.filter(name__contains="Vic")
QuerySet[<Author: VM (Vicky) Brasseur>, <Author: Victor Hugo">]

现在,关于双下划线 (__) 的一个小提示。这些非常 Pythonic。您可能在 Python 世界的旅程中见过 __main____repr__。这些有时被称为 dunder methods,是“double underscore”的缩写。在 Python 中,只有少数非字母数字字符可以用于对象名称;下划线就是其中之一。这些在 ORM 中用作过滤器键名称的不同部分的显式分隔符。在底层,字符串被这些下划线分割,并且令牌被单独处理。name__contains 变为 attribute: name, filter: contains。在其他编程语言中,您可以使用箭头代替,例如 PHP 中的 name->contains。不要让双下划线吓到你,它们只是 Pythonic 助手!(如果您眯起眼睛,您可能会说它们看起来像小蛇,想要帮助您编写代码的小蟒蛇。)

ORM 非常强大且非常 Pythonic。但是我上面提到的 Django 管理后台 呢?

Django Admin

opensource.com

Django 最出色的用户可访问性功能之一是其管理界面。如果您定义了模型,您将免费获得一个漂亮的基于 Web 的编辑门户。

是什么驱动了这个功能?ORM。

Authors list in Django Admin

opensource.com

没错!给定用于创建原始模型的代码,Django 将其变成了一个基于 Web 的门户,该门户使用我们之前使用的相同原始函数提供支持。默认情况下,管理后台是基本的,但这只是在您的模型中添加更多定义来更改管理后台外观的问题。例如,早期的那些 __str__ 方法?我们使用它们来定义 Author 对象的外观(在本例中,仅是作者姓名)。通过一些工作,您可以创建一个感觉像完整内容管理系统的界面,该界面允许您的用户轻松编辑自己的内容(例如,添加用于标记帖子“已发布”的字段和过滤器)。

如果您想了解更多信息,关于 ORMDjango Girls 教程 部分有详细的演练。Django 项目网站上也有大量文档。

User profile image.
多年来,Katie 担任过许多不同的角色。她以前曾担任多种语言的软件开发人员、多个操作系统的系统管理员,以及许多不同主题的演讲者。当她没有改变世界时,她喜欢烹饪、编织挂毯,并观察各种应用程序堆栈处理表情符号的效果如何。

3 条评论

我通常会使用老式的 SQL 方法与数据库交互,但不知道如何使用 Python 做同样的事情。现在学会了,它非常有用。非常感谢您的文章,Katie。

Jamesh
https://dltutuapp.com/

谢谢。我正在学习 Python,您的教程真的帮助了我。

Ankit。
http://tutuapp.tech/

谢谢

© . All rights reserved.