天天看點

Django(17)orm查詢操作[通俗易懂]前言查詢條件

大家好,又見面了,我是你們的朋友全棧君。

前言

查找是資料庫操作中一個非常重要的技術。查詢一般就是使用

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

    先将

    datetime.datetime

    從navie時間轉換為aware時間。

    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