大家好,又見面了,我是你們的朋友全棧君。
前言
查找是資料庫操作中一個非常重要的技術。查詢一般就是使用
filter
、
exclude
以及
get
三個方法來實作。我們可以在調用這些方法的時候傳遞不同的參數來實作查詢需求。在ORM層面,這些查詢條件都是使用
field+__+condition
的方式來使用的。以下将那些常用的查詢條件來一一解釋。
查詢條件
exact
使用精确的=進行查找。如果提供的是一個None,那麼在SQL層面就是被解釋為NULL。示例代碼如下:
article = Article.objects.get(id__exact=14)
article = Article.objects.get(id__exact=None)
複制
以上的兩個查找在翻譯為SQL語句為如下:
select ... from article where id=14;
select ... from article where id IS NULL;
複制
iexact
在底層會被翻譯成
LIKE
。示例代碼如下:
article = Article.objects.filter(title__iexact='hello world')
複制
那麼以上的查詢就等價于以下的SQL語句:
select ... from article where title like 'hello world';
複制
- LIKE和=:大部分情況下都是等價的,隻有少數情況下是不等價的。
- exict和iexact:他們的差別其實就是LIKE和=的差別,因為exact會被翻譯成=,而iexact會被翻譯成LIKE。
- 因為
其實等價于field__exact=xxx
,是以我們直接使用filed=xxx
就可以了,并且因為大部分情況filed=xxx
和exact
又是等價的,是以我們以後直接使用iexact
就可以了。field=xxx
QuerySet.query
QuerySet.query:
query
可以用來檢視這個
ORM
查詢語句最終被翻譯成的
SQL
語句。但是
query
隻能被用在
QuerySet
對象上,不能用在普通的
ORM模型
上。是以如果你的查詢語句是通過
get
來擷取資料的,那麼就不能使用
query
,因為
get
傳回的是滿足條件的
ORM
模型,而不是
QuerySet
。如果你是通過
filter
等其他傳回
QuerySet
的方法查詢的,那麼就可以使用
query
。
article = Article.objects.filter(title__iexact='hello world') # article是QuerySet對象,是以可以被翻譯成sql語句
print(article.query) # 列印sql語句
複制
列印結果
SELECT `article`.`id`, `article`.`title`, `article`.`content`, `article`.`category_id` FROM `article` WHERE `article`.`content` LIKE hello world
複制
contains
大小寫敏感,判斷某個字段是否包含了某個資料。示例代碼如下:
articles = Article.objects.filter(title__contains='hello')
複制
在翻譯成SQL語句為如下:
select ... where title like binary '%hello%';
複制
要注意的是,在使用
contains
的時候,翻譯成的sql語句左右兩邊是有百分号的,意味着使用的是模糊查詢。而exact翻譯成sql語句左右兩邊是沒有百分号的,意味着使用的是精确的查詢。
icontains
大小寫不敏感的比對查詢。示例代碼如下:
articles = Article.objects.filter(title__icontains='hello')
複制
翻譯成SQL語句為如下:
select ... where title like '%hello%';
複制
in
提取那些給定的field的值是否在給定的容器中。容器可以為list、tuple或者任何一個可以疊代的對象,包括
QuerySet
對象。示例代碼如下:
articles = Article.objects.filter(id__in=[1,2,3])
複制
也可以通過其他的表的字段來判斷是否在某個集合中。示例代碼如下:
categories = Category.objects.filter(article__id__in=[1,2,3])
複制
如果要判斷相關聯的表的字段,那麼也是通過
__
來連接配接。并且在做關聯查詢的時候,不需要寫
models_set
,直接使用
模型的名字的小寫化
就可以了。比如通過分類去查找相應的文章,那麼通過
article__id__in
就可以了,而不是寫成
article_set__id__in
的形式。當然如果你不想使用預設的形式,可以在外鍵定義的時候傳遞
related_query_name
來指定反向查詢的名字。示例代碼如下:
class Category(models.Model):
name = models.CharField(max_length=100)
class Meta:
db_table = 'category'
class Article(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
cateogry = models.ForeignKey("Category",on_delete=models.CASCADE,null=True,related_query_name='articles')
class Meta:
db_table = 'article'
複制
因為在
cateogry
的
ForeignKey
中指定了
related_query_name
為
articles
,是以你不能再使用
article
來進行反向查詢了。這時候就需要通過
articles__id__in
來進行反向查詢。
反向查詢和反向引用的差別
- 反向查詢:将模型名字小寫化。比如
,就是将article__in
模型小寫了。當然我們也可以通過Article
來指定自己的方式,而不使用預設的方式。related_query_name
- 反向引用:将模型名字小寫化,然後再加上
,比如_set
,可以通過article_set
來指定自己的方式,而不是用預設的方式。related_name
并且,如果在做反向查詢的時候,如果查詢的字段就是模型的主鍵,那麼可以省略掉這個字段,直接寫成
article__in
就可以了,不需要這個
id
了。
in
不僅僅可以指定清單/元組,還可以為
QuerySet
。比如要查詢“文章标題中包含有hello的所有分類”,那麼可以通過以下代碼來實作:
articles = Article.objects.filter(title__icontains='hello')
categories = Category.objects.filter(articles__in=articles)
for cateogry in categories:
print(cateogry)
複制
gt
某個field的值要大于給定的值。示例代碼如下:
articles = Article.objects.filter(id__gt=3)
複制
以上代碼的意思是将所有id大于3的文章全部都找出來。将翻譯成以下SQL語句:
select ... where id > 4;
複制
gte
類似于gt,是大于等于。
lt
類似于gt是小于。
lte
類似于lt,是小于等于。
startswith
判斷某個字段的值是否是以某個值開始的。大小寫敏感。示例代碼如下:
articles = Article.objects.filter(title__startswith='hello')
複制
以上代碼的意思是提取所有标題以hello字元串開頭的文章。将翻譯成以下SQL語句:
select ... where title like 'hello%'
複制
istartswith
類似于startswith,但是大小寫是不敏感的。
endswith
判斷某個字段的值是否以某個值結束。大小寫敏感。示例代碼如下:
articles = Article.objects.filter(title__endswith='world')
複制
以上代碼的意思是提取所有标題以world結尾的文章。将翻譯成以下SQL語句:
select ... where title like '%world';
複制
iendswith
類似于endswith,隻不過大小寫不敏感。
range
判斷某個field的值是否在給定的區間中。示例代碼如下:
from django.utils.timezone import make_aware
from datetime import datetime
start_time = make_aware(datetime(year=2018, month=1, day=1))
end_time = make_aware(datetime(year=2018, month=12, day=12))
article = Article.objects.filter(create_time__range=(start_time, end_time))
複制
以上代碼的意思是提取所有釋出時間在2018/1/1到2018/12/12之間的文章。将翻譯成以下的SQL語句
select ... from article where pub_time between '2018-01-01' and '2018-12-12'。
複制
注意點
- 以上提取資料,不會包含最後一個值。也就是不會包含2018/12/12的文章。
- 因為我們在
中指定了settings.py
,并且設定了USE_TZ=True
,是以我們在提取資料的時候要使用TIME_ZONE='Asia/Shanghai'
先将django.utils.timezone.make_aware
從navie時間轉換為aware時間。datetime.datetime
會将指定的時間轉換為make_aware
中指定的時區的時間。TIME_ZONE
date
針對某些
date
或者
datetime
類型的字段。可以指定date的範圍。并且這個時間過濾,還可以使用鍊式調用。示例代碼如下:
articles = Article.objects.filter(create_time__date=date(2018,3,29))
複制
以上代碼的意思是查找時間為2018/3/29這一天發表的所有文章。将翻譯成以下的sql語句:
select ... WHERE DATE(CONVERT_TZ(`front_article`.`pub_date`, 'UTC', 'Asia/Shanghai')) = 2018-03-29
複制
注意,因為預設情況下MySQL的表中是沒有存儲時區相關的資訊的。是以我們需要下載下傳一些時區表的檔案,然後添加到Mysql的配置路徑中。如果你用的是
windows
作業系統。那麼在
http://dev.mysql.com/downloads/timezones.html
下載下傳
timezone_2018d_posix.zip - POSIX standard
。然後将下載下傳下來的所有檔案拷貝到
C:\ProgramData\MySQL\MySQL Server 5.7\Data\mysql
中,如果提示檔案名重複,那麼選擇覆寫即可。
如果用的是
linux
或者
mac
系統,那麼在指令行中執行以下指令:
mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -D mysql -u root -p
,然後輸入密碼,從系統中加載時區檔案更新到mysql中。
year
根據年份進行查找。示例代碼如下:
articles = Article.objects.filter(create_time__year=2021)
articles = Article.objects.filter(create_time__year__gte=2021)
複制
以上的代碼在翻譯成SQL語句為如下:
select ... where pub_date between '2021-01-01' and '2021-12-31';
select ... where pub_date >= '2021-01-01';
複制
month
同year,根據月份進行查找。
day
同year,根據日期進行查找。
week_day
同year,根據星期幾進行查找。1表示星期天,7表示星期六,2-6代表的是星期一到星期五。示例代碼如下:
article = Article.objects.filter(create_time__week_day=3) # 尋找星期三建立的文章
複制
time
根據時間進行查找。示例代碼如下:
articles = Article.objects.filter(create_time__time=datetime.time(12,12,12));
複制
以上的代碼是擷取每一天中12點12分12秒發表的所有文章。
isnull
根據值是否為空進行查找。示例代碼如下:
articles = Article.objects.filter(create_time__isnull=False)
複制
以上的代碼的意思是擷取所有釋出日期不為空的文章。将來翻譯成SQL語句如下:
select ... where pub_date is not null;
複制
regex和iregex
大小寫敏感和大小寫不敏感的正規表達式。示例代碼如下:
articles = Article.objects.filter(title__regex=r'^hello')
複制
以上代碼的意思是提取所有标題以hello字元串開頭的文章。将翻譯成以下的SQL語句:
select ... where title regexp binary '^hello';
複制
iregex
是大小寫不敏感的。
根據關聯的表進行查詢
假如現在有兩個ORM模型,一個是
Article
,一個是
Category
。代碼如下:
class Category(models.Model):
"""文章分類表"""
name = models.CharField(max_length=100)
class Article(models.Model):
"""文章表"""
title = models.CharField(max_length=100,null=True)
category = models.ForeignKey("Category",on_delete=models.CASCADE)
複制
比如想要擷取文章标題中包含”hello”的所有的分類。那麼可以通過以下代碼來實作:
categories = Category.object.filter(article__title__contains("hello"))
複制
釋出者:全棧程式員棧長,轉載請注明出處:https://javaforall.cn/164924.html原文連結:https://javaforall.cn