美文网首页
数据库API

数据库API

作者: 蝉时雨丶 | 来源:发表于2020-06-09 07:54 被阅读0次

Django官方文档

执行查询

一旦创建 数据模型 后,Django 自动给予你一套数据库抽象 API,允许你创建,检索,更新和删除对象。本页介绍如何使用这些 API。参考 数据模型参考 获取所有查询选项的完整细节。

在本指南中(以及相关参考资料中),我们将引用以下模型,这些模型包含了一个 Webblog 应用:

from django.db import models

class Blog(models.Model):
    name = models.CharField(max_length=100)
    tagline = models.TextField()

    def __str__(self):
        return self.name

class Author(models.Model):
    name = models.CharField(max_length=200)
    email = models.EmailField()

    def __str__(self):
        return self.name

class Entry(models.Model):
    blog = models.ForeignKey(Blog, on_delete=models.CASCADE)
    headline = models.CharField(max_length=255)
    body_text = models.TextField()
    pub_date = models.DateField()
    mod_date = models.DateField()
    authors = models.ManyToManyField(Author)
    number_of_comments = models.IntegerField()
    number_of_pingbacks = models.IntegerField()
    rating = models.IntegerField()

    def __str__(self):
        return self.headline

创建对象

方法一:

为了用 Python 对象展示数据表对象,Django 使用了一套直观的系统:一个模型类代表一张数据表,一个模型类的实例代表数据库表中的一行记录。

要创建一个对象,用关键字参数初始化它,然后调用 save() 将其存入数据库。

假设模型都位于文件 mysite/blog/models.py 中,这是一个例子:

>>> from blog.models import Blog
>>> b = Blog(name='Beatles Blog', tagline='All the latest Beatles news.')
>>> b.save()

这在幕后执行了 INSERT SQL 语句。Django 在你显式调用 save() 才操作数据库。

方法二:
b=Blog.objects.create(name='Beatles Blog', tagline='All the latest Beatles news.')

一步到位,不用调用save()

将修改保存至对象

要将修改保存至数据库中已有的某个对象,使用 save()

有一个已被存入数据库中的 Blog 实例 b5,本例将其改名,并在数据库中更新其记录:

>>> b5.name = 'New name'
>>> b5.save()

这在幕后执行了 UPDATE SQL 语句。Django 在你显示调用 save() 后才操作数据库。

保存 ForeignKey 和 ManyToManyField 字段

更新 ForeignKey 字段的方式与保存普通字段的方式相同——只需将正确类型的实例分配给相关字段。本例为 Entry 类的实例 entry 更新了 blog 属性,假设 EntryBlog 的实例均已保存在数据库中(因此能在下面检索它们):

>>> from blog.models import Blog, Entry
>>> entry = Entry.objects.get(pk=1)
>>> cheese_blog = Blog.objects.get(name="Cheddar Talk")
>>> entry.blog = cheese_blog
>>> entry.save()

更新 ManyToManyField 字段有点不同——在字段上使用 add() 方法为关联关系添加一条记录。本例将 Author 实例 joe 添加至 entry 对象:

>>> from blog.models import Author
>>> joe = Author.objects.create(name="Joe")
>>> entry.authors.add(joe)

要一次添加多行记录至 ManyToManyField 字段,在一次调用 add() 时传入多个参数,像这样:

>>> john = Author.objects.create(name="John")
>>> paul = Author.objects.create(name="Paul")
>>> george = Author.objects.create(name="George")
>>> ringo = Author.objects.create(name="Ringo")
>>> entry.authors.add(john, paul, george, ringo)

Django 会在添加或指定错误类型的对象时报错。\

BlackLivesMatter

执行查询

一旦创建 数据模型 后,Django 自动给予你一套数据库抽象 API,允许你创建,检索,更新和删除对象。本页介绍如何使用这些 API。参考 数据模型参考 获取所有查询选项的完整细节。

在本指南中(以及相关参考资料中),我们将引用以下模型,这些模型包含了一个 Webblog 应用:

<pre>from django.db import models

class Blog(models.Model):
name = models.CharField(max_length=100)
tagline = models.TextField()

def __str__(self):
    return self.name

class Author(models.Model):
name = models.CharField(max_length=200)
email = models.EmailField()

def __str__(self):
    return self.name

class Entry(models.Model):
blog = models.ForeignKey(Blog, on_delete=models.CASCADE)
headline = models.CharField(max_length=255)
body_text = models.TextField()
pub_date = models.DateField()
mod_date = models.DateField()
authors = models.ManyToManyField(Author)
number_of_comments = models.IntegerField()
number_of_pingbacks = models.IntegerField()
rating = models.IntegerField()

def __str__(self):
    return self.headline

</pre>

创建对象

为了用 Python 对象展示数据表对象,Django 使用了一套直观的系统:一个模型类代表一张数据表,一个模型类的实例代表数据库表中的一行记录。

要创建一个对象,用关键字参数初始化它,然后调用 save() 将其存入数据库。

假设模型都位于文件 mysite/blog/models.py 中,这是一个例子:

<pre>>>> from blog.models import Blog

b = Blog(name='Beatles Blog', tagline='All the latest Beatles news.')
b.save()
</pre>

这在幕后执行了 INSERT SQL 语句。Django 在你显式调用 save() 才操作数据库。

save() 方法没有返回值。

参见

save() 接受很多此处未介绍的高级选项。参考文档 save() 获取完整细节。

要一步创建并保存一个对象,使用 create() 方法。

将修改保存至对象

要将修改保存至数据库中已有的某个对象,使用 save()

有一个已被存入数据库中的 Blog 实例 b5,本例将其改名,并在数据库中更新其记录:

<pre>>>> b5.name = 'New name'

b5.save()
</pre>

这在幕后执行了 UPDATE SQL 语句。Django 在你显示调用 save() 后才操作数据库。

保存 ForeignKeyManyToManyField 字段

更新 ForeignKey 字段的方式与保存普通字段的方式相同——只需将正确类型的实例分配给相关字段。本例为 Entry 类的实例 entry 更新了 blog 属性,假设 EntryBlog 的实例均已保存在数据库中(因此能在下面检索它们):

<pre>>>> from blog.models import Blog, Entry

entry = Entry.objects.get(pk=1)
cheese_blog = Blog.objects.get(name="Cheddar Talk")
entry.blog = cheese_blog
entry.save()
</pre>

更新 ManyToManyField 字段有点不同——在字段上使用 add() 方法为关联关系添加一条记录。本例将 Author 实例 joe 添加至 entry 对象:

<pre>>>> from blog.models import Author

joe = Author.objects.create(name="Joe")
entry.authors.add(joe)
</pre>

要一次添加多行记录至 ManyToManyField 字段,在一次调用 add() 时传入多个参数,像这样:

>>> john = Author.objects.create(name="John")
>>> paul = Author.objects.create(name="Paul")
>>> george = Author.objects.create(name="George")
>>> ringo = Author.objects.create(name="Ringo")
>>> entry.authors.add(john, paul, george, ringo)

Django 会在添加或指定错误类型的对象时报错。

检索对象

要从数据库检索对象,要通过模型类的 Manager 构建一个 QuerySet

一个 QuerySet 代表来自数据库中对象的一个集合。它可以有 0 个,1 个或者多个 filters. Filters,可以根据给定参数缩小查询结果量。在 SQL 的层面上, QuerySet 对应 SELECT 语句,而filters对应类似 WHERELIMIT 的限制子句。

你能通过模型的 Manager 获取 QuerySet。每个模型至少有一个 Manager,默认名称是 objects。像这样直接通过模型类使用它:

>>> Blog.objects
<django.db.models.manager.Manager object at ...>
>>> b = Blog(name='Foo', tagline='Bar')
>>> b.objects
Traceback:
    ...
AttributeError: "Manager isn't accessible via Blog instances."

注解:
Managers 只能通过模型类访问,而不是通过模型实例,目的是强制分离 “表级” 操作和 “行级” 操作。

Manager 是模型的 QuerySets 主要来源。例如 Blog.objects.all() 返回了一个 QuerySet,后者包含了数据库中所有的 Blog 对象。

检索全部对象

从数据库中检索对象最简单的方式就是检索全部。为此,在 Manager 上调用 all() 方法:

>>> all_entries = Entry.objects.all()

方法 all() 返回了一个包含数据库中所有对象的 QuerySet 对象。

通过过滤器检索指定对象

all() 返回的 QuerySet 包含了数据表中所有的对象。虽然,大多数情况下,你只需要完整对象集合的一个子集。

要创建一个这样的子集,你需要通过添加过滤条件精炼原始 QuerySet。两种最常见的精炼 QuerySet 的方式是:

<dl class="docutils">

<dt>filter(**kwargs)</dt>

<dd>返回一个新的 QuerySet,包含的对象满足给定查询参数。</dd>

<dt>exclude(**kwargs)</dt>

<dd>返回一个新的 QuerySet,包含的对象 满足给定查询参数。</dd>

</dl>

查询参数(**kwargs)应该符合下面的 Field lookups 的要求。

例如,要包含获取 2006 年的博客条目(entries blog)的 QuerySet,像这样使用 filter():

Entry.objects.filter(pub_date__year=2006)

通过默认管理器类也一样:

Entry.objects.all().filter(pub_date__year=2006)

链式过滤器

精炼 QuerySet 的结果本身还是一个 QuerySet,所以能串联精炼过程。例子:

>>> Entry.objects.filter(
...     headline__startswith='What'
... ).exclude(
...     pub_date__gte=datetime.date.today()
... ).filter(
...     pub_date__gte=datetime.date(2005, 1, 30)
... )

这个先获取包含数据库所有条目(entry)的 QuerySet,然后排除一些,再进入另一个过滤器。最终的 QuerySet 包含标题以 "What" 开头的,发布日期介于 2005 年 1 月 30 日与今天之间的所有条目

每个 QuerySet 都是唯一的

每次精炼一个 QuerySet,你就会获得一个全新的 QuerySet,后者与前者毫无关联。每次精炼都会创建一个单独的、不同的 QuerySet,能被存储,使用和复用。

举例:

>>> q1 = Entry.objects.filter(headline__startswith="What")
>>> q2 = q1.exclude(pub_date__gte=datetime.date.today())
>>> q3 = q1.filter(pub_date__gte=datetime.date.today())

这三个 QuerySets 是独立的。第一个是基础 QuerySet,包含了所有标题以 "What" 开头的条目。第二个是第一个的子集,带有额外条件,排除了 pub_date 是今天和今天之后的所有记录。第三个是第一个的子集,带有额外条件,只筛选 pub_date 是今天或未来的所有记录。最初的 QuerySet (q1) 不受筛选操作影响。

用 get() 检索单个对象

filter() 总是返回一个 QuerySet,即便只有一个对象满足查询条件 —— 这种情况下, QuerySet 只包含了一个元素。

若你知道只会有一个对象满足查询条件,你可以在 Manager 上使用 get() 方法,它会直接返回这个对象:

>>> one_entry = Entry.objects.get(pk=1)

你可以对 get() 使用与 filter() 类似的所有查询表达式 —— 同样的,参考下面的 Field lookups

注意, 使用切片 [0] 时的 get()filter() 有点不同。如果没有满足查询条件的结果, get() 会抛出一个 DoesNotExist 异常。该异常是执行查询的模型类的一个属性 —— 所有,上述代码中,若没有哪个 Entry 对象的主键是 1,Django 会抛出 Entry.DoesNotExist

类似了,Django 会在有不止一个记录满足 get() 查询条件时发出警告。这时,Django 会抛出 MultipleObjectsReturned,这同样也是模型类的一个属性。

其它 QuerySet 方法

大多数情况下,你会在需要从数据库中检索对象时使用 all()get()filter()exclude()。然而,这样远远不够;完整的各种 QuerySet 方法请参阅 QuerySet API 参考

限制 QuerySet 条目数

利用 Python 的数组切片语法将 QuerySet 切成指定长度。这等价于 SQL 的 LIMITOFFSET 子句。

例如,这将返回前 5 个对象 (LIMIT 5):

>>> Entry.objects.all()[:5]

这会返回第 6 至第 10 个对象 (OFFSET 5 LIMIT 5):

>>> Entry.objects.all()[5:10]

不支持负索引 (例如 Entry.objects.all()[-1])

一般情况下, QuerySet 的切片返回一个新的 QuerySet —— 其并未执行查询。一个特殊情况是使用了的 Python 切片语法的 “步长”。例如,这将会实际的执行查询命令,为了获取从前 10 个对象中,每隔一个抽取的对象组成的列表:

>>> Entry.objects.all()[:10:2]

由于对 queryset 切片工作方式的模糊性,禁止对其进行进一步的排序或过滤。

要检索 单个 对象而不是一个列表时(例如 SELECT foo FROM bar LIMIT 1),请使用索引,而不是切片。例如,这会返回按标题字母排序后的第一个 Entry:

>>> Entry.objects.order_by('headline')[0]

这大致等价于:

>>> Entry.objects.order_by('headline')[0:1].get()

然而,注意一下,若没有对象满足给定条件,前者会抛出 IndexError,而后者会抛出 DoesNotExist。参考 get() 获取更多细节。

字段查询

字段查询即你如何制定 SQL WHERE 子句。它们以关键字参数的形式传递给 QuerySet 方法 filter()exclude()get()

基本的查询关键字参数遵照 field__lookuptype=value。(有个双下划线)。例如:

>>> Entry.objects.filter(pub_date__lte='2006-01-01')

转换为 SQL 语句大致如下:

SELECT * FROM blog_entry WHERE pub_date <= '2006-01-01';

查询子句中指定的字段必须是模型的一个字段名。不过也有个例外,在 ForeignKey 中,你可以指定以 _id 为后缀的字段名。这种情况下,value 参数需要包含 foreign 模型的主键的原始值。例子:

>>> Entry.objects.filter(blog_id=4)

若你传入了无效的关键字参数,查询函数会抛出 TypeError

数据库 API 支持两套查询类型;完整参考文档位于 字段查询参考。为了让你了解能干啥,以下是一些常见的查询:

exact

一个 "exact" 匹配的例子:

>>> Entry.objects.get(headline__exact="Cat bites dog")

会生成这些 SQL:

SELECT ... WHERE headline = 'Cat bites dog';

若你为提供查询类型 —— 也就说,若关键字参数未包含双下划线 —— 查询类型会被指定为 exact。

例如,以下两条语句是等价的:

>>> Blog.objects.get(id__exact=14)  # Explicit form
>>> Blog.objects.get(id=14)         # __exact is implied

这是为了方便,因为 exact 查询是最常见的。

iexact

不分大小写的匹配,查询语句:

>>> Blog.objects.get(name__iexact="beatles blog")

会匹配标题为 "Beatles Blog", "beatles blog", 甚至 "BeAtlES blOG" 的 Blog。

contains

大小写敏感的包含测试。例子:

Entry.objects.get(headline__contains='Lennon')

粗略地转为 SQL:

SELECT ... WHERE headline LIKE '%Lennon%';

注意这将匹配标题 'Today Lennon honored',而不是 'today lennon honored'

这也有个大小写不敏感的版本, icontains

<dt>startswith, endswith</dt>

<dl class="docutils">

<dd>以……开头和以……结尾的查找。当然也有大小写不敏感的版本,名为 istartswithiendswith。</dd>

</dl>

同样,这只介绍了皮毛。完整的参考能在 field 查询参考 找到。

相关文章

网友评论

      本文标题:数据库API

      本文链接:https://www.haomeiwen.com/subject/kkiazhtx.html