Django-官网查询部分翻译(1.11版本文档)-QuerySet-字段查找-06

2019-09-26 10:22:13 浏览数 (1)

目录

  • Making queries 进行查询
    • 创建一个对象(一条数据记录)
    • 保存修改的表对象
      • 保存外键字段或多对多字段(ForeignKey or ManyToManyField fields)
    • Retrieving objects 查出对象(QuerySet)
      • Retrieving all objects 查出所有对象
      • Retrieving specific objects with filters 通过 filter 查出指定的对象
      • Retrieving a single object with get() 使用 get() 只取一个数据对象
      • Other QuerySet methods 其他的 QuerySet 方法
      • Aggregation functions 聚合函数
    • field-lookups 字段查找(字段查询条件,双下划线查询)
      • 常见形式
      • 注意点
      • 书写格式
      • lookuptype 查找类型分类整理
  • 单词
  • 特别点

本文将翻译 django 官网的 模型层的 QuerySet 章节 文档版本:1.11

Making queries 进行查询

一旦你创建了 数据表模型类,django 会自动给你一些数据库抽象API,让你可以创建、查询、更新、删除对象,下文将介绍如何使用这些API(以一个网页应用为例展开)

首先是创建表模型类

先分析一下他们的表关系,会有助于理解下面的内容

代码语言:javascript复制
from django.db import models

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

    def __str__(self):              # __unicode__ on Python 2
        return self.name

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

    def __str__(self):              # __unicode__ on Python 2
        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)
    n_comments = models.IntegerField()
    n_pingbacks = models.IntegerField()
    rating = models.IntegerField()

    def __str__(self):              # __unicode__ on Python 2
        return self.headline

在 django(ORM)中,数据库与 python 对象的映射关系十分形象,一个表模型类(class)即代表一张表,实例化出一个对象即代表一条数据记录

创建一个对象(一条数据记录)

在 django 中要想创建一个数据对象,只需要实例化他,传入这个表模型类的关键字参数,然后调用 .save() 方法把这个对象保存到数据库中即可

代码语言:javascript复制
from blog.models import Blog

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

这段代码背后其实是一条数据库 插入语句,django 并不会直接执行这个语句,直到你调用了 .save() 方法( .save() 没有返回值)

保存修改的表对象

想要保存一个已经改动过的对象,调用 .save() 方法即可(更新一条记录)

下面是一个 Blog 表模型类的实例化对象 b5,他已经在数据库里有对应的记录了,下面的语句将修改他的 name 属性值,然后更新它到数据库中去

代码语言:javascript复制
b5.name = 'New name'
b5.save()  # 代码运行到这里才会进行数据库操作,真正地更新到数据库!

保存外键字段或多对多字段(ForeignKey or ManyToManyField fields)

外键字段 ForeignKey

更新一个外键字段的写法和普通字段的完全一致,只需要将正确类型的对象分配给相关字段即可,下面的语句是更新一个 Entry 模型类实例化出来的 entry 对象的 blog 属性(请确保下面用到的 Entry 和 Blog 的实例化对象已经存在在数据库中,这样我们的语句才能将它们查出来)

代码语言:javascript复制
from blog.models import Blog, Entry

entry = Entry.objects.get(pk=1)  # 查出主键是 1 的 entry 对象(记录)
cheese_blog = Blog.objects.get(name="Cheddar Talk")
entry.blog = cheese_blog  # 将 blog 对象直接赋值给 entry 对象的 blog 属性(对象赋值给字段)
entry.save()  # 调用 .save() 方法
ManyToManyField

想要保存多对多字段,写法和外键字段有点小区别,使用 .add() 方法来记录一个关系。

下面的案例把 Author 表模型类的实例 joe 对象增加到了 entry 对象中(加了一个对应关系)

代码语言:javascript复制
from blog.models import Author

joe = Author.objects.create(name="joe")  # 创建了一个 Author类的对象 joe, 它的 name 属性是 joe
entry.authors.add(joe)  # 给已经查出来了的 entry 对象增加...(建立关联关系)

插入多个多对多字段

代码语言:javascript复制
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 将会报错

注意!把 add 方法解释一下(对象可以直接传,如果是值,要传元组?)

...

Retrieving objects 查出对象(QuerySet)

从数据库中查询对象,通过 表模型类的 Manager 管理器 来构造一个 QuerySet 。

一个 QuerySet 代表着你数据库中的一系列对象的集合,它可以是 0 个、 1 个 或者多个 filters,filters 可以基于你给出的参数 缩小查询结果的范围,对于 SQL ,一个 QuerySet 相当于一个 SELECT 语句,一个 filter 就相当于一个限制条件,比如 WHERE 或者 LIMIT。

我们通过使用表模型类的 Manager 来构造(获得)一个 QuerySet ,每一个表模型类至少有一个 Manager ,他可以直接被对象调用(封装好了的),我们可以通过表模型类直接访问它,就像下面这样:

代码语言:javascript复制
Blog.objects
# 内部对应的是:<django.db.models.manager.Manager object at ...>
b = Blog(name='Foo', tagline='Bar')  # 表模型类实例化会返回实例化好的对象
b.objects  # 会报错 AttributeError: "Manager isn't accessible via Blog instances." --> Manager 不能通过 Blog 实例来访问

注意: Managers 只能通过表模型类来访问,而不是模型类的实例(对象) 请你一定要分清楚你当前使用的是 表层面 的操作还是 记录层面 的操作(只有表层面才有Manager)

Retrieving all objects 查出所有对象

最简单的方式从表里获取全部记录对象(QuerySet)是在 Manager 上调用 .all() 方法

代码语言:javascript复制
all_entries = Entry.objects.all()  # 查出 Entry 模型类对应表中的所有数据记录,是一个 QuerySet

Retrieving specific objects with filters 通过 filter 查出指定的对象

.all() 方法可以返回 数据库中所有记录的对象 但是通常情况下,我们只需要查询出里面的一小部分对象。

想要得到这么一小部分对象,我们需要细化(约束)最初的 QuerySet ,增加过滤条件,细化 QuerySet 最常用的两种写法如下:

filter(**kwargs)

返回一个符合你给出的查找参数(条件)的 QuerySet(满足条件的)

exclude(**kwargs)

返回一个不符合你给出的查找参数(条件)的 QuerySet(不满足条件的)

查找参数(**kwargs)应该符合 Field lookups(字段查找)格式(day 55 博客里有)

就比如,你想得到 2006年发表的 blog entries 的 QuerySet ,可以通过 filter 这么实现:

代码语言:javascript复制
Entry.objects.filter(pub_date__year=2006)
# 也可以这么写(使用 表模型类的 Manager 来调用 filter)
Entry.objects.all().filter(pub_date__year=2006)
链式 filter

细化 QuerySet 后的结果自身还是一个 QuerySet ,所以我们可以链式地细分(再次筛选)它,比如:

代码语言:javascript复制
Entry.objects.filter(
    headline__startswith='What'
).exclude(
    pub_date__gte=datetime.date.today()
).filter(
    pub_date__gte=datetime.date(2005, 1, 30)
)  # 不写成一行是这样看起来更清楚点

上面语句的最终查询条件(含义)是:查出所有 headline 以 “What” 开头,pub_date 非今天及今天以后,并且 pub_date 是在 2005-1-30 之后的 QuerySet (包含了满足条件的记录)

大白话一点就是:查出 标题以 What 开头,在2005年1月30日至今(天)的所有书籍记录(QuerySet)

QuerySet 是相互隔离的(不同的对象了)

个人理解:QuerySet 就等同于 SQL 语句,你加条件会产生一条新的语句,新的语句并不会影响 旧的语句,多次执行同一个 QuerySet 结果不同是由于数据库里符合该条件的记录少了

每一次你细化 QuerySet,你将得到一个崭新的 QuerySet,他跟细分之前的 QuerySet 没有绑定关系,互不影响。

每次细化都会创建一个单独而又独特的 QuerySet 对象,它可以被用来存储、使用、重用。

代码语言:javascript复制
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())

上面的三个 QuerySet 是相互独立的

第一个 QuerySet 包含了所有的 文章标题(headline) 以 What 开头的 QuerySet 对象(记录对象集合)

第二个 QuerySet 是第一个集合的子集合(再次筛选后的对象),附加条件:pub_date 不是(exclude)今天或者将来的 --> 今天及今天之前的

第三个 QuerySet 是第一个集合的子集合(在第一个的条件上再加条件),附加条件:pub_date 是今天或者将来的

第一个 QuerySet(q1) 不受 其他两个(q2、q3)的影响。

QuerySet 是惰性的(不会主动执行)

QuerySet 是惰性的,创建 QuerySet 的行为(语句)并不会涉及任何数据库操作。

你可以给 QuerySet 叠加许多许多过滤条件,但是 django 并不会去执行他们,直到 QuerySet 被 evaluated (检查,评估?--> 推测是 遍历、取值,翻译成取值好像更合适一点),看看下面的例子:

代码语言:javascript复制
q = Entry.objects.filter(headline__startswith="What")
q = q.filter(pub_date__lte=datetime.date.today())
q = q.exclude(body_text__icontains="food")
print(q)

这看起来像执行了几次数据库操作?三次?不!其实它只执行了一次,只在执行最后一行 print(q) 的时候执行了数据库操作。通常来说,QuerySet 的结果只会在你 “访问” 它们的时候才会从数据库获取,当你执行时,QuerySet 会通过访问数据库来取值(When you do, the QuerySet is evaluated by accessing the database,翻不出来)

触发 QuerySet 让其真正执行数据库操作的几种情况
  • 迭代(for 循环遍历)
  • 加了步长的切片操作、索引取值、get、all、first 等
  • pikle 序列化时
  • 触发了 __repr__() 或者 __str__()
  • 触发了 __len__() 或者 len()
    • 如果你想获取满足条件的数据条数而不需要其他信息,可以使用 .count() 来更高效的获取数据条数
  • list() 把 QuerySet 强制转换成 list 时
  • 强转成 bool 类型或者 作为 if 条件 时
    • 如果 QuerySet 的查询结果至少有一个(数据对象),返回 True,如果没有结果,返回 False
Caching and QuerySets 缓存 和 QuerySets

每一个 QuerySet 都包含一个缓存,来最小化数据库访问次数,知道它的工作原理可以让你写出更高效的代码。

新创建的 QuerySet 的缓存(cache)是空的,QuerySet 第一次取值执行(evaluatad)的时候进行数据库查询操作,Django 会将查询结果保存到 QuerySet 的 cache 缓存中,并返回查询出来的结果集。后续取值可以复用 QuerySet 的缓存结果。

代码语言:javascript复制
# 下面的这两行代码会走两次数据库操作,很可能他们两次得到的数据是相同的。
# 为什么我们不避免它呢? --> 很可能两次查询请求之间可能有对象被删除或者新增,会造成两次结果不一致
print([e.headline for e in Entry.objects.all()])
print([e.pub_date for e in Entry.objects.all()])


# 下面的代码只会走一次数据库操作
queryset = Entry.objects.all()
print([p.headline for p in queryset]) # 真正地执行数据库操作
print([p.pub_date for p in queryset]) # 重用上一次查询出来的结果(cache)
When QuerySets are not cached 不会保存 cache 缓存的情况

QuerySet 也不总是会缓存他的查询结果,当只需要(取值)结果集中的一部分时,cache 会被检查,但如果没有被填充,则不会缓存后续查询返回的项目(but if it is not populated then the items returned by the subsequent query are not cached.),具体来说,这意味着使用数组切片或者索引限制查询结果集将不会保存缓存。

比如,每次获取一个明确的索引值都会执行一次数据库操作

代码语言:javascript复制
# 下面的操作执行了两次数据库查询
queryset = Entry.objects.all()
print(queryset[5]) # 查询数据库
print(queryset[5]) # 又一次查询了数据库

然而,如果整个 QuerySet 已经被取值(evaluated),那么 cache 将会被缓存

代码语言:javascript复制
# 下面的操作只执行了一次数据库查询
queryset = Entry.objects.all()
entry_list = [entry for entry in queryset] # 执行了数据库操作
print(queryset[5]) # 使用 cache
print(queryset[5]) # 使用 cache

下面是一些可以将会整个取值(evaluated)的一些案例,可以将数据存到 cache 中(让后续使用 cache,减少数据库操作次数)

代码语言:javascript复制
[entry for entry in queryset]
bool(queryset)
entry in queryset
list(queryset)

小心这个特性,你可以用它来提升代码的性能(减少查询次数,降低数据库压力),但也可能因为用了 cache 造成数据紊乱(使用的数据不是最新的,读取到修改之间发生了另一次修改,这次使用的数据在数据库里已经更新过了(高并发很可能发生),)!

Retrieving a single object with get() 使用 get() 只取一个数据对象

. filter() 方法返回的是一个 QuerySet ,即使他里面只有一个数据对象,如果你确定查询结果只有一个对象,你可以用 表模型类的 Manager 对象来调用 .get() 方法,往里面传入查询条件来直接获取到数据对象。

代码语言:javascript复制
one_entry = Entry.objects.get(pk=1)

你可以在任何 查询语句 后面使用 .get() 方法,他也可以接收一些关键字参数,同样支持字段查找语法(__gt=18)。

记住这个

使用 .get().filter()[0] 有点不一样,如果没有满足条件的查询结果, .get() 会报一个 DoesNotExist 的错,这个报错是执行的表模型类的一个属性,所以,在上面的代码中,如果 Entry 对应的表中没有任何对象符合 主键 是 1,那么 django 将会报错:Entry.DoesNotExist

同样,如果有多个对象同时满足这个条件,那么 django 将会报错:MultipleObjectsReturned,这个报错也是执行的模型类的一个属性。

Other QuerySet methods 其他的 QuerySet 方法

通常情况下,你会使用 .all()、.get()、.exclude() 去查询数据库,但我们提供的远不止这些。 更多详情可以看 QuerySet API

通常情况下,当你使用 QuerySet 时会结合 filter 等链式调用,为了实现链式调用,大多数的 QuerySet 方法都会返回一个新的 QuerySet

QuerySet 类有两个公共属性你可以用于反省?(use for introspection)

ordered

如果 QuerySet 的查询结果是有序的,会返回 True,如果是无序的,会返回False

db

将会用于执行查询语句的数据库

query

可以查看当前 QuerySet 对应的 SQL 语句

Methods that return new QuerySets 返回新的 QuerySets 的方法
代码语言:javascript复制
# 常见的几个
.filter(**kwargs) 符合条件的
.exclude(**kwargs) 不符合条件的
.annnotate(*args, **kwargs)  分组
.order_by(*fields) 排序
.reverse()  反序
.distinct(*fields) 去重
.values(*fields, **expressions*) 过滤字段
.values_list(*fields, flat=False) 过滤字段
.all()
.select_related(*field) 优化,可以把对象查出来,并附带字段,后期对象 .字段 不会再触发数据库操作
.prefetch_related(*lookups) 优化相关
.defer(*fields) 优化相关
.only(*fields) 优化相关
.select_for_update(nowait=False, skip_locked=False)

# 不常见的几个
.dates(field, kind, order=‘ASC’) 
.datetimes(field_name, kind, order=‘ASC’, tzinfo=None)
.none() 创建空的 QuerySet
.union(*other_qs, all=False) 
.intersection(*other_qs)
.difference(*other_qs)
.extra(一堆参数) 自定义SQL(将被舍弃的方法)
.extra(select=None, where=None, params=None, tables=None, order_by=None, select_params=None)
.using(alias)  多个数据库时指定数据库(数据库配置可以配好几个数据库连接)
.raw(raw_query, params=None, translations=None)
.filter(**kwargs) 符合条件的

会返回一个新的 QuerySet ,里面包含的对象都是满足你给出的查询参数(条件)的,多个查询(关键字)参数以逗号间隔,对应到 SQL 语句中是 AND 连接,如果你想执行更多复杂的操作(比如 OR 或)可以使用 Q 对象

Q对象 的使用

代码语言:javascript复制
from django.db.models import *
"""
, 间隔 Q 对象,是 and 关系 ( & 也是)
| 间隔 Q 对象,是 or  关系
~ 放在 Q 对象前面,是 ! 取反关系
"""

Poll.objects.get(
    Q(question__startswith='Who'),
    Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))
)
# --> SELECT * from polls WHERE question LIKE 'Who%' AND (pub_date = '2005-05-02' OR pub_date = '2005-05-06')
.exclude(**kwargs) 不符合条件的

会返回一个新的 QuerySet ,里面包含的对象都是不满足括号内指定的查询条件的,多个查询(关键字)参数以逗号间隔,参数之间是 AND 关系,其最外层逻辑是 NOT()。如果你想执行更多复杂的操作(比如 OR 或)可以使用 Q 对象

代码语言:javascript复制
Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3), headline='Hello')
# 对应的SQL :SELECT ... WHERE NOT (pub_date > '2005-1-3' AND headline = 'Hello')

# 同样他也支持像 filter 那样链式调用
Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3)).exclude(headline='Hello')
# 对应的SQL :SELECT ... WHERE NOT pub_date > '2005-1-3' AND NOT headline = 'Hello'
.annnotate(*args, **kwargs) 分组-- 暂时看不懂
.order_by(*fields) 排序 -- 太长了,先放
.reverse() 反序

只能对排过序的 QuerySet 使用...

.distinct(*fields) 去重
.values(*fields, **expressions*) 过滤字段
.values_list(*fields, flat=False) 过滤字段
.none() 创建空的 QuerySet

调用 .none() 方法会创建一个空的 QuerySet ,里面不包含任何数据对象,并且在取值时也不会执行任何数据库操作(是 EmptyQuerySet 的实例)

代码语言:javascript复制
Entry.objects.none()
# <QuerySet []>


from django.db.models.query import EmptyQuerySet

isinstance(Entry.objects.none(), EmptyQuerySet)
# True

# 下面两句不会执行数据库操作
print(models.Book.objects.none())
# <QuerySet []>
print(models.Book.objects.none().filter(title__contains='三国'))
# <QuerySet []>
.all()
.union(*other_qs, all=False)
.intersection(*other_qs)
.difference(*other_qs)
.select_related(*field) 优化,可以把对象查出来,并附带字段,后期对象 .字段 不会再触发数据库操作
.prefetch_related(*lookups) 优化相关
.extra(一堆参数) 自定义SQL(将被舍弃的方法)

.extra(select=None, where=None, params=None, tables=None, order_by=None, select_params=None)

.defer(*fields) 优化相关
.only(*fields) 优化相关
.using(alias) 多个数据库时指定数据库(数据库配置可以配好几个数据库连接)
.select_for_update(nowait=False, skip_locked=False)
.raw(raw_query, params=None, translations=None)
Methods that do not return QuerySets 不返回QuerySet 对象的方法

下面这些 QuerySet 方法会直接触发数据库操作然后返回一些其他东西,而不是 QuerySet 这些方法不会使用 cache 缓存,相反,每次调用他们都会执行数据库操作

代码语言:javascript复制
# 常见的几个
.get(**kwargs) 返回当个对象
.create(**kwargs) 
.count()
.latest(field_name=None)
.earliest(field_name=None)
.first()
.last()
.aggregate(*args, **kwargs)
.exists()
.update(**kwargs)
.delete()

# 不常见的几个
.get_or_create(defaults=None, **kwargs)
.update_or_create(defaults=None, **kwargs)
.bulk_create(objs, batch_size=None)
.in_bulk(id_list=None)
.iterator()
.as_manager()
.get(**kwargs) 返回当个对象
.create(**kwargs)
.count()
.first()
.last()
.aggregate(*args, **kwargs)
.exists()
.update(**kwargs)
.delete()
.latest(field_name=None)
.earliest(field_name=None)

Aggregation functions 聚合函数

field-lookups 字段查找(字段查询条件,双下划线查询)

此部分参考文档: django官网 字段查找(field-lookups)

字段查找(field-lookups)对应的是 SQL 语句中的 WHERE 条件,一般放在 QuerySet 对象的 filter() 、exclude()、get() 方法中作为条件

常见形式

注意点

不同数据库对这些方法支持不同,django orm 对应不同数据库也能翻译成不同的 SQL 语句

  • sqlite 对日期类型支持不友好、数据(字符串)大小写不敏感(忽略大小写)
  • python 对浮点数精度不敏感(price=66.66 --> 可能有这么一条记录,但它却匹配不到(python(好像是 sqlite吧?) 把它变成了 66.651556464))

书写格式

field__lookuptype --> price_gt (两个下划线)

比如

代码语言:javascript复制
# 省略一些要导入的文件
Entry.objects.filter(pub_date__lte='2006-01-01')

# 翻译成对应的 SQL 语句就是:
SELECT * FROM blog_entry WHERE pub_date <= '2006-01-01';

# pub_date__lte='2006-01-01' --> pub_date <= '2006-01-01'

上面表名为什么是 blog_entry ? 用 django 表模型类创建的表会自动加上 app 的前缀(显然这里的 app 叫 blog)

lookuptype 查找类型分类整理

此部分为伪代码,仅演示这些字段查询的功能用法以及对应 SQL 语句什么样 这里都是直接以模型表类开头的(相当于 from app01.models import *

关系比较类
代码语言:javascript复制
__gt
# 字段大于...
Entry.objects.filter(id__gt=4)
# --> SELECT ... WHERE id > 4;

__gte
# 大于等于

__lt
# 小于

__lte
# 小于等于

__isnull
# 字段是否为空
Entry.objects.filter(pub_date__isnull=True)
# --> SELECT ... WHERE pub_date IS NULL;
模糊匹配类、正则

精准匹配直接就是 = / exact

代码语言:javascript复制
# --------- 是否包含 --------------
__contains
# 字段值是否包含 __ 
Entry.objects.get(headline__contains='Lennon')
# --> SELECT ... WHERE headline LIKE '%Lennon%';

__icontains
# 字段值是否包含 __ ,忽略大小写的包含
Entry.objects.get(headline__icontains='Lennon')
# --> SELECT ... WHERE headline ILIKE '%Lennon%';

# --------- 以 ... 开头 或 结尾 --------------
__startswith
# 字段以 __ 开头
Entry.objects.filter(headline__startswith='Lennon')
# --> SELECT ... WHERE headline LIKE 'Lennon%';

__istartswith
# 字段以 __ 开头,忽略大小写
Entry.objects.filter(headline__istartswith='Lennon')
# --> SELECT ... WHERE headline ILIKE 'Lennon%';

__endswith
# 字段以 __ 结尾
Entry.objects.filter(headline__endswith='Lennon')
# --> SELECT ... WHERE headline LIKE '%Lennon';

__iendswith
# 字段以 __ 结尾,忽略大小写
Entry.objects.filter(headline__iendswith='Lennon')
# --> SELECT ... WHERE headline ILIKE '%Lennon'

# --------- 全文检索 --------------
__search
# 全文检索(django 1.10 开始有改动)
Entry.objects.filter(headline__search=" Django -jazz Python")
# --> SELECT ... WHERE MATCH(tablename, headline) AGAINST ( Django -jazz Python IN BOOLEAN MODE);

# --------- 正则相关 --------------
__regex
# 正则匹配
Entry.objects.get(title__regex=r'^(An?|The)  ')
# --> SELECT ... WHERE title REGEXP BINARY '^(An?|The)  ';  # -- MySQL,对于这个字段查询,django orm 对应不同的 数据库 会解析成不同的 SQL 语句

__iregex
# 忽略大小写的正则匹配
# 案例
Entry.objects.get(title__iregex=r'^(an?|the)  ')
# -->SELECT ... WHERE title REGEXP '^(an?|the)  ';
范围类
代码语言:javascript复制
__in
# 字段的值在不在给定的列表范围内
Entry.objects.filter(id__in=[1, 3, 4])
# --> SELECT ... WHERE id IN (1, 3, 4);

# 补充:也可以使用会动态的查询 QuerySet 作为列表
inner_qs = Blog.objects.filter(name__contains='Cheddar')
entries = Entry.objects.filter(blog__in=inner_qs)
# --> SELECT ... WHERE blog.id IN (SELECT id FROM ... WHERE NAME LIKE '%Cheddar%')

__range
# 可以比较日期时间、数字范围、字符(串?没验证)范围
import datetime
start_date = datetime.date(2005, 1, 1)
end_date = datetime.date(2005, 3, 31)
Entry.objects.filter(pub_date__range=(start_date, end_date))
# --> SELECT ... WHERE pub_date BETWEEN '2005-01-01' and '2005-03-31';
日期时间类

日期时间与日期不能混用 允许其他 关系类的字段查找(field-lookups, 大于小于这样的) 链式拼接

代码语言:javascript复制
__date
# 匹配 datetime 类型字段,会将传入的值转换为日期,然后搭配 关系类的字段查找(field-lookups)进行比较
Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1))
Entry.objects.filter(pub_date__date__gt=datetime.date(2005, 1, 1))
# --> ...

__year
# 匹配 datetime、date 类型字段,直接指定精确的哪一年
Entry.objects.filter(pub_date__year=2005)
# --> SELECT ... WHERE pub_date BETWEEN '2005-01-01' AND '2005-12-31';
Entry.objects.filter(pub_date__year__gte=2005)
# --> SELECT ... WHERE pub_date >= '2005-01-01';

__month
# 匹配 datetime、date 类型字段,范围是 1 (January) --- 12 (December),语句视数据库引擎而定    
Entry.objects.filter(pub_date__month=12)
# --> SELECT ... WHERE EXTRACT('month' FROM pub_date) = '12';
Entry.objects.filter(pub_date__month__gte=6)
# --> SELECT ... WHERE EXTRACT('month' FROM pub_date) >= '6';

__day
# 匹配 datetime、date 类型字段,当月的第几天
Entry.objects.filter(pub_date__day=3)
# --> SELECT ... WHERE EXTRACT('day' FROM pub_date) = '3';
Entry.objects.filter(pub_date__day__gte=3)
# --> SELECT ... WHERE EXTRACT('day' FROM pub_date) >= '3';
# Note this will match any record with a pub_date on the third day of the month, such as January 3, July 3, etc.

__week
# 匹配 datetime、date 类型字段,当年的第几周(1-52/53,平闰年不同)
# django 1.11 中新增的
Entry.objects.filter(pub_date__week=52)
Entry.objects.filter(pub_date__week__gte=32, pub_date__week__lte=38)
# --> ...
# return the week number (1-52 or 53) according to ISO-8601, i.e., weeks start on a Monday and the first week starts on or before Thursday.

__week_day
# 匹配 datetime、date 类型字段 范围:1 (Sunday) -- 7 (Saturday)
Entry.objects.filter(pub_date__week_day=2)
Entry.objects.filter(pub_date__week_day__gte=2)
# --> ...

__time
# 匹配 datetime、time 类型字段的 minute, django 1.11 中新增的
Entry.objects.filter(pub_date__time=datetime.time(14, 30))
# 实现方式取决于数据库引擎(暂时没有例子)


__hour
# 匹配 datetime、time 类型字段的 minute,范围 0-23
Event.objects.filter(timestamp__hour=23)
# --> SELECT ... WHERE EXTRACT('hour' FROM timestamp) = '23';


__minute
# 匹配 datetime、time 类型字段的 minute,范围 0-59
Event.objects.filter(timestamp__minute=29)
# --> SELECT ... WHERE EXTRACT('minute' FROM timestamp) = '29';

__second
# datetime、time 类型字段相关的,看不太懂
Event.objects.filter(timestamp__second=31)
# --> SELECT ... WHERE EXTRACT('second' FROM timestamp) = '31';
# 文档:
# For datetime and time fields, an exact second match. Allows chaining additional field lookups. Takes an integer between 0 and 59.
# For datetime fields, when USE_TZ is True, values are converted to the current time zone before filtering.
自定义字段查找(custom field-lookups)

一般官方提供的这些就已经完全够用了,真的要自定义了再去文档里看吧

单词

每个翻译文档后面都写出来,方便查看 后续再整合到一篇博客上,可以附上出现这个单词的整句话,翻译出来,这个学习英语的实际意义会更加明确且有效,积累看文档要用到的单词

代码语言:javascript复制
lookuptype      查找类型
refine          细分、精细化(缩小范围)
brand-new       崭新的
in no way       绝对不
separate        独立的...
stored          存储
reuse           重用
an additional criteria      附加条件
the act of      ...的行为
involve         涉及
stack ... together      将...叠加在一起
evaluated       (检查,评估?--> 推测是 遍历、取值,翻译成取值好像更合适一点)
alias           别名

特别点

保存外键字段那里,可以直接给外键对象赋值一个对象(blog 对象 --> blog 属性) cache 机制

0 人点赞