1. 程式人生 > 實用技巧 >Django ORM 常見查詢條件

Django ORM 常見查詢條件

常見查詢條件:

  • exact:在底層會被翻譯成=

  • iexact:在底層會被翻譯成LIKE

    • LIKE和=:大部分情況下都是等價的,只有少數情況下是不等價的。
    • exict和iexact:他們的區別其實就是LIKE和=的區別,因為exact會被翻譯成=,而iexact會被翻譯成LIKE。
    • 因為field__exact=xxx其實等價於filed=xxx,因此我們直接使用filed=xxx就可以了,並且因為大部分情況exactiexact又是等價的,因此我們以後直接使用field=xxx就可以了。
  • QuerySet.query:query

    可以用來檢視這個ORM查詢語句最終被翻譯成的SQL語句。但是query只能被用在QuerySet物件上,不能用在普通的ORM模型上。因此如果你的查詢語句是通過get來獲取資料的,那麼就不能使用query,因為get返回的是滿足條件的ORM模型,而不是QuerySet。如果你是通過filter等其他返回QuerySet的方法查詢的,那麼就可以使用query

  • contains:使用大小寫敏感的判斷,某個字串是否在指定的欄位中。這個判斷條件會使用大小敏感,因此在被翻譯成SQL語句的時候,會使用like binary,而like binary就是使用大小寫敏感的。

  • icontains:使用大小寫不敏感的判斷,某個字串是否被包含在指定的欄位中。這個查詢語句在被翻譯成SQL

    的時候,使用的是like,而likeMySQL層面就是不區分大小寫的。

  • contains和icontains:在被翻譯成SQL的時候使用的是%hello%,就是隻要整個字串中出現了hello都能過夠被找到,而iexact沒有百分號,那麼意味著只有完全相等的時候才會被匹配到。

  • in:可以直接指定某個欄位的是否在某個集合中。例:

    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'
    

    因為在cateogryForeignKey中指定了related_query_namearticles,因此你不能再使用article來進行反向查詢了。這時候就需要通過articles__id__in來進行反向查詢。

    反向查詢是將模型名字小寫化。比如article__in。可以通過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、gte、lt、lte:代表的是大於、大於等於、小於、小於等於的條件。例:

    articles = Article.objects.filter(id__lte=3)
    
  • startswith、istartswith、endswith、iendswith:表示以某個值開始,不區分大小寫的以某個值開始、以某個值結束、不區分大小寫的以某個值結束。例:

    articles = Article.objects.filter(title__endswith="hello")
    
  • isnull:根據值是否為空進行查詢

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

    以上的程式碼的意思是獲取所有釋出日期不為空的文章。

  • regex和iregex:大小寫敏感和大小寫不敏感的正則表示式

    articles = Article.objects.filter(title__regex=r'^hello')
    

    以上程式碼的意思是提取所有標題以hello字串開頭的文章。

    iregex是大小寫不敏感的。

關於時間的查詢條件:

  • range:可以指定一個時間段。並且時間應該標記為aware時間,不然django會報警告。例:

    start_time = make_aware(datetime(year=2018,month=4,day=4,hour=17,minute=0,second=0))
    end_time = make_aware(datetime(year=2018,month=4,day=4,hour=18,minute=0,second=0))
    articles = Article.objects.filter(create_time__range=(start_time,end_time))
    print(articles.query)
    print(articles)
    
  • date:用年月日來進行過濾。如果想要使用這個過濾條件,那麼前提必須要在MySQL中新增好那些時區檔案。

    • 因為預設情況下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中。

        例:

        articles = Article.objects.filter(create_time__date=datetime(year=2018,month=4,day=4))
        
  • year/month/day:表示根據年/月/日進行查詢。例:

    articles = Article.objects.filter(create_time__year__gte=2018)
    
  • week_day:根據星期來進行查詢。1表示星期天,7表示星期六,2-6代表的是星期一到星期五。比如要查詢星期三的所有文章,那麼可以通過以下程式碼來實現:

    articles = Article.objects.filter(create_time__week_day=4)
    
  • time:根據分時秒來進行查詢。如果要具體到秒,一般比較難匹配到,可以使用區間的方式來進行查詢。區間使用range條件。比如想要獲取17時/10分/27-28秒之間的文章,那麼可以通過以下程式碼來實現:

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

根據關聯的表進行查詢:

假如現在有兩個ORM模型,一個是Article,一個是Category。程式碼如下:
python 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"))