1. 程式人生 > >Django2.0-db(6)-查詢操作-查詢條件

Django2.0-db(6)-查詢操作-查詢條件

查詢操作

查詢是資料庫操作中一個非常重要的技術。查詢一般就是使用filterexclude以及get三個方法來實現。我們可以在呼叫這些方法的時候傳遞不同的引數來實現查詢需求。在ORM層面,這些查詢條件都是使用field+__+condition的方式來使用的。

  • get返回一個模型物件
  • filter返回一個QuerySet
  • QuerySet.query: query()可以用來檢視查詢語句最終被翻譯成的SQL語句。但是query()只能被用在QuerySet物件上,不能用在普通的ORM模型

查詢條件

exact

使用精確的=進行查詢。如果提供的是一個None,那麼在SQL層面就是被解釋為NULL

。示例程式碼如下:

article = Article.objects.get(id__exact=14) # == (id = 14)
article = Article.objects.get(id__exact=None) # == (id = None)

以上的兩個查詢在翻譯為SQL語句為如下:

select ... from article where id=14;
select ... from article where id IS NULL;

collation排序規則

  • 在windows上,mysql的collation無論選擇什麼都是大小寫不敏感
  • 在linux上,mysql的collation如果是utf_bin,則大小寫敏感

iexact

使用like進行查詢。示例程式碼如下:

article = Article.objects.filter(title__iexact='hello world')

那麼以上的查詢就等價於以下的SQL語句:

select ... from article where title like 'hello world';

注意上面這個sql語句,因為在MySQL中,沒有一個叫做ilike的。所以exactiexact的區別實際上就是LIKE=的區別,在大部分collation=utf8_general_ci情況下都是一樣的(collation是用來對字串比較的)。

contains

大小寫敏感,判斷某個欄位是否包含了某個資料。示例程式碼如下:

articles = Article.objects.filter(title__contains='hello')

在翻譯成SQL語句為如下:

select ... where title like binary '%hello%';

binary: 大小寫敏感

要注意的是,在使用contains的時候,翻譯成的sql語句左右兩邊是有百分號的,意味著使用的是模糊查詢。而exact翻譯成sql語句左右兩邊是沒有百分號的,意味著使用的是精確的查詢。

icontains

大小寫不敏感的匹配查詢。示例程式碼如下:

articles = Article.objects.filter(title__icontains='hello')

在翻譯成SQL語句為如下:

select ... where title like '%hello%';

in

提取那些給定的field的值是否在給定的容器中。容器可以為listtuple或者任何一個可以迭代的物件,包括QuerySet物件。示例程式碼如下:

articles = Article.objects.filter(id__in=[1,2,3])

以上程式碼在翻譯成SQL語句為如下:

select ... where id in (1,3,4)

當然也可以傳遞一個QuerySet物件進去。示例程式碼如下:

inner_qs = Article.objects.filter(title__contains='hello') # QuerySet
categories = Category.objects.filter(article__in=inner_qs)

以上程式碼的意思是獲取那些文章標題包含hello的所有分類。 將翻譯成以下SQL語句,示例程式碼如下:

select ...from category where article.id in (select id from article where title like '%hello%');

如果要判斷相關聯的表的欄位,也是通過__來連線。

  • 在做關聯引用的時候,不需要寫models_set,直接使用模型的名字的小寫化就可以了。比如通過分類去查詢相應的文章,那麼通過article__id__in iterator而不是article_set__id__in的形式。如果使用related__query_name = "xxx"執指定了外來鍵名,則就直接使用該外來鍵名
    • 如果查詢的欄位就是模型的主鍵,那麼可以省略掉該欄位,直接寫成article__in就而無需article__id__in

gt

gt: greater than

某個field的值要大於給定的值。示例程式碼如下:

articles = Article.objects.filter(id__gt=4)

以上程式碼的意思是將所有id大於4的文章全部都找出來。 將翻譯成以下SQL語句:

select ... where id > 4;

gte

gte: greater than equal

類似於gt,是大於等於。

lt

lt: lower than

類似於gt是小於。

lte

lte: lower than equal

類似於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
"""
make_aware(value, timezone=None, is_sdt=None)
#如果timezone未指定,則使用setting.py中TIME_ZONE設定的時區
	return value.replace(tzinfo=timezone)
"""
start_date = make_aware(datetime(year=2018,month=1,day=1))
end_date = make_aware(datetime(year=2018,month=3,day=29,hour=16))
articles = Article.objects.filter(pub_date__range=(start_date,end_date))

以上程式碼的意思是提取所有釋出時間在2018/1/12018/12/12之間的文章。 將翻譯成以下的SQL語句:

select ... from article where pub_time between '2018-01-01' and '2018-12-12'

需要注意的是,以上提取資料,不會包含最後一個值。range右閉合 而且另外一個重點,因為我們在settings.py中指定了USE_TZ=True,並且設定了TIME_ZONE='Asia/Shanghai',因此我們在提取資料的時候要使用django.utils.timezone.make_aware先將datetime.datetimenavie時間轉換為aware時間。make_aware會將指定的時間轉換為TIME_ZONE中指定的時區的時間。

date

針對某些date或者datetime型別的欄位。可以指定date的範圍。並且這個時間過濾,還可以使用鏈式呼叫。示例程式碼如下:

articles = Article.objects.filter(pub_date__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(pub_date__year=2018)
articles = Article.objects.filter(pub_date__year__gte=2017)

以上的程式碼在翻譯成SQL語句為如下:

select ... where pub_date between '2018-01-01' and '2018-12-31';
select ... where pub_date >= '2017-01-01';

month

year,根據月份進行查詢。

day

year,根據日期進行查詢。

week_day

Django 1.11新增的查詢方式。同year,根據星期幾進行查詢。1表示星期天,7表示星期六,2-6代表的是星期一到星期五。

time

根據時間進行查詢。示例程式碼如下:

articles = Article.objects.filter(pub_date__time=datetime.time(12,12,12));

以上的程式碼是獲取每一天中12點12分12秒發表的所有文章。 更多的關於時間的過濾,請參考Django官方文件:https://docs.djangoproject.com/en/2.0/ref/models/querysets/#range

isnull

根據值是否為空進行查詢。示例程式碼如下:

articles = Article.objects.filter(pub_date__isnull=False)

以上的程式碼的意思是獲取所有釋出日期不為空的文章。 將來翻譯成SQL語句如下:

select ... where pub_date is not null;
  • 如果要具體到秒,比較難以匹配。可以使用區間的方式range來查詢。

    • 比如想要獲取17時10分27秒-28秒的文章,可以通過以下程式碼

      start_time = date(hour=17, minute=10, second=27)
      end_time = date(hour=17, minute=10, second=28)
      articles = Article.object.filter(create_time__time__range(start_time, end_time))
      

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