美文网首页
数据库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