1. 程式人生 > >Django-官網查詢部分翻譯(1.11版本文件)-QuerySet-欄位查詢-06

Django-官網查詢部分翻譯(1.11版本文件)-QuerySet-欄位查詢-06

目錄

  • 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(以一個網頁應用為例展開)

首先是建立表模型類

先分析一下他們的表關係,會有助於理解下面的內容

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() 方法把這個物件儲存到資料庫中即可

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 屬性值,然後更新它到資料庫中去

b5.name = 'New name'
b5.save()  # 程式碼執行到這裡才會進行資料庫操作,真正地更新到資料庫!

儲存外來鍵欄位或多對多欄位(ForeignKey or ManyToManyField fields)

外來鍵欄位 ForeignKey

更新一個外來鍵欄位的寫法和普通欄位的完全一致,只需要將正確型別的物件分配給相關欄位即可,下面的語句是更新一個 Entry 模型類例項化出來的 entry 物件的 blog 屬性(請確保下面用到的 Entry 和 Blog 的例項化物件已經存在在資料庫中,這樣我們的語句才能將它們查出來)

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 物件中(加了一個對應關係)

from blog.models import Author

joe = Author.objects.create(name="joe")  # 建立了一個 Author類的物件 joe, 它的 name 屬性是 joe
entry.authors.add(joe)  # 給已經查出來了的 entry 物件增加...(建立關聯關係)

插入多個多對多欄位

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 ,他可以直接被物件呼叫(封裝好了的),我們可以通過表模型類直接訪問它,就像下面這樣:

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() 方法

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 這麼實現:

Entry.objects.filter(pub_date__year=2006)
# 也可以這麼寫(使用 表模型類的 Manager 來呼叫 filter)
Entry.objects.all().filter(pub_date__year=2006)

鏈式 filter

細化 QuerySet 後的結果自身還是一個 QuerySet ,所以我們可以鏈式地細分(再次篩選)它,比如:

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 物件,它可以被用來儲存、使用、重用。

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 (檢查,評估?--> 推測是 遍歷、取值,翻譯成取值好像更合適一點),看看下面的例子:

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 的快取結果。

# 下面的這兩行程式碼會走兩次資料庫操作,很可能他們兩次得到的資料是相同的。
# 為什麼我們不避免它呢? --> 很可能兩次查詢請求之間可能有物件被刪除或者新增,會造成兩次結果不一致
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.),具體來說,這意味著使用陣列切片或者索引限制查詢結果集將不會儲存快取。

比如,每次獲取一個明確的索引值都會執行一次資料庫操作

# 下面的操作執行了兩次資料庫查詢
queryset = Entry.objects.all()
print(queryset[5]) # 查詢資料庫
print(queryset[5]) # 又一次查詢了資料庫

然而,如果整個 QuerySet 已經被取值(evaluated),那麼 cache 將會被快取

# 下面的操作只執行了一次資料庫查詢
queryset = Entry.objects.all()
entry_list = [entry for entry in queryset] # 執行了資料庫操作
print(queryset[5]) # 使用 cache
print(queryset[5]) # 使用 cache

下面是一些可以將會整個取值(evaluated)的一些案例,可以將資料存到 cache 中(讓後續使用 cache,減少資料庫操作次數)

[entry for entry in queryset]
bool(queryset)
entry in queryset
list(queryset)

小心這個特性,你可以用它來提升程式碼的效能(減少查詢次數,降低資料庫壓力),但也可能因為用了 cache 造成資料紊亂(使用的資料不是最新的,讀取到修改之間發生了另一次修改,這次使用的資料在資料庫裡已經更新過了(高併發很可能發生),)!

Retrieving a single object with get() 使用 get() 只取一個數據物件

. filter() 方法返回的是一個 QuerySet ,即使他裡面只有一個數據物件,如果你確定查詢結果只有一個物件,你可以用 表模型類的 Manager 物件來呼叫 .get() 方法,往裡面傳入查詢條件來直接獲取到資料物件。

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 的方法

# 常見的幾個
.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物件 的使用

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 物件

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 的例項)

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 快取,相反,每次呼叫他們都會執行資料庫操作

# 常見的幾個
.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 (兩個下劃線)

比如

# 省略一些要匯入的檔案
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 *

關係比較類

__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

# --------- 是否包含 --------------
__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) +';

範圍類

__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, 大於小於這樣的) 鏈式拼接

__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)

一般官方提供的這些就已經完全夠用了,真的要自定義了再去文件裡看吧

單詞

每個翻譯文件後面都寫出來,方便檢視

後續再整合到一篇部落格上,可以附上出現這個單詞的整句話,翻譯出來,這個學習英語的實際意義會更加明確且有效,積累看文件要用到的單詞

lookuptype      查詢型別
refine          細分、精細化(縮小範圍)
brand-new       嶄新的
in no way       絕對不
separate        獨立的...
stored          儲存
reuse           重用
an additional criteria      附加條件
the act of      ...的行為
involve         涉及
stack ... together      將...疊加在一起
evaluated       (檢查,評估?--> 推測是 遍歷、取值,翻譯成取值好像更合適一點)
alias           別名

特別點

儲存外來鍵欄位那裡,可以直接給外來鍵物件賦值一個物件(blog 物件 --> blog 屬性)

cache 機制