1. 程式人生 > >Django之表高階操作

Django之表高階操作

目錄

  • 一、如何開啟自己的測試指令碼?
  • 二、對錶資料的新增、更新、刪除
    • 1.create()
    • 2.update()
    • 3.delete()
    • 4.檢視執行的sql語句
  • 三、 單表查詢13個操作
    • 返回QuerySet物件的方法有:
      • 1.all() 查詢所有結果
      • 2.filter() 條件匹配
      • 3.exclude() 取反
      • 4.order_by() 排序
      • 5.reverse() 反轉
      • 6.distinct() 去重
    • 特殊的QuerySet:
      • 7.values() 獲取指定欄位對 列表套字典
      • 8.values_list() 獲取指定欄位對** 列表套字典 列表套元組
    • 返回具體物件的:
      • 9.get 直接獲取物件,不存在就報錯
      • 10.first() 取第一個元素物件
      • 11.last() 取最後一個元素物件
    • 返回布林值的方法有:
      • 12.exists()
    • 返回數字的方法有:
      • 13.count() 統計資料條數
  • 四、雙下線查詢
  • 五、外來鍵欄位的增刪改查
    • 1.一對多
    • 2.多對多
      • 1.繫結關係 add
      • 2.移除繫結關係 remove
      • 3.修改繫結關係 set
      • 4.清空關係
  • 六、跨表查詢
    • 1.基於物件的跨表查詢(子查詢):
    • 2.基於雙下劃線跨表查詢(連結串列查詢)
    • 3.聚合查詢
    • 4.分組查詢
    • 5.F查詢
    • 6.Q查詢
    • 7.Q的高階用法

一、如何開啟自己的測試指令碼?

如何只單獨測試django中的某一個py檔案
    如何書寫測試指令碼
    
    在任意一個py檔案中書寫以下程式碼 
        應用下的tests
        或者自己新建一個
        
        
    import os
    if __name__ == "__main__":
        os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day53.settings")
        import django
        django.setup()

這樣就可以直接執行你的test.py檔案來執行測試

二、對錶資料的新增、更新、刪除

1.create()      # 新增
2.update()      # 更新
3.delete()      # 刪除

1.create()

# 對電影表新增一條資料
# create()  返回值就是當前被建立資料的物件本身
models.Movie.objects.create(title='西遊記',price=999.23,publish_time='2016-1-1')


 # 還可以直接傳日期物件
    from datetime import date
    ctime = date.today()
    models.Movie.objects.create(title='西遊記', price=666.23, publish_time=ctime)

2.update()

# update()  更新資料      返回值是受影響的行數
res = models.Movie.objects.filter(pk=1).update(title='玉女心經')
print(res)  # 1   受影響的條數

3.delete()

# delete()  刪除資料    返回值(1, {'app01.Movie': 1})  受影響的表及行數
res = models.Movie.objects.filter(pk=3).delete()
print(res)  # (1, {'app01.Movie': 1})

4.檢視執行的sql語句

res = models.Movie.objects.filter(pk=3).delete()
print(res.query)  # 獲取res的sql執行語句

三、 單表查詢13個操作

返回QuerySet物件的方法有:
            all()
            filter()
            exclude()
            order_by()
            reverse()
            distinct()
特殊的QuerySet:
            values()       返回一個可迭代的字典序列
            values_list()  返回一個可迭代的元組序列
返回具體物件的:
            get()
            first()
            last()  
返回布林值的方法有:
            exists()
返回數字的方法有:
            count()

返回QuerySet物件的方法有:

1.all() 查詢所有結果

res = models.Movie.objects.all()
print(res)

2.filter() 條件匹配

# 獲取電影表中id為1的資料
# 不存在就返回空,而不是報錯。get(id=1)不存在就直接報錯
res = models.Movie.objects.filter(id=1)
print(res)

3.exclude() 取反

# 獲取id為1之外的資料
res = models.Movie.objects.exclude(pk=1)
print(res)

4.order_by() 排序

res = models.Movie.objects.order_by('price')  # 預設是升序
res = models.Movie.objects.order_by('-price')  # 減號就是降序

5.reverse() 反轉

res = models.Movie.objects.order_by('price').reverse()  # 將次序反轉

6.distinct() 去重

# 去重:去重的前提 必須是由完全一樣的資料的才可以
res = models.Movie.objects.values('title','price').distinct()

特殊的QuerySet:

7.values() 獲取指定欄位對 列表套字典

返回一個可迭代的字典序列

values(*field): 返回一個ValueQuerySet——一個特殊的QuerySet,執行後得到的並不是一系列model的例項化物件,而是一個可迭代的字典序列

# values()   QuerySet物件  [{},{},{}]     獲取指定欄位對的資料
# 返回一個可迭代的字典序列
res = models.Movie.objects.values('title','publish_time')

8.values_list() 獲取指定欄位對** 列表套字典 列表套元組

返回一個可迭代的元組序列

values_list(*field): 它與values()非常相似,它返回的是一個元組序列,values返回的是一個字典序列

res = models.Movie.objects.values_list('title','price')
print(res)

返回具體物件的:

9.get 直接獲取物件,不存在就報錯

# get()      直接獲取物件本身  不推薦使用  當查詢條件不存在的時候直接報錯
res = models.Movie.objects.get(pk=1)
print(res)

10.first() 取第一個元素物件

# first()    資料物件        取第一個元素物件
res = models.Movie.objects.filter().first()
print(res)

11.last() 取最後一個元素物件

# last()    資料物件          取最後一個元素物件
res = models.Movie.objects.last()
print(res)

返回布林值的方法有:

12.exists()

# exists()   返回的是布林值  判斷前面的物件是否有資料
res = models.Movie.objects.filter(pk=1000).exists()  # 不存在,Fslse
print(res)

res = models.Movie.objects.filter(pk=1).exists()   # 存在,True

返回數字的方法有:

13.count() 統計資料條數

# 統計篩選之後資料的條數
res = models.Movie.objects.count()
print(res)

四、雙下線查詢

在python中我們進行邏輯判斷會用到>、<、=、or之類的符號,那麼在Django進行models資料操作的時候,我們表示:雙下劃線

__gt        : 大於
__lt        : 小於
__gte       : 大於等於
__lte       : 小於等於
__in        : 或
__rang      : 在...之間,顧頭也顧尾
__contains   :模糊查詢,區分大小寫
__icontains  :模糊查詢,不區分大小寫
__year      : 查詢年份
__month     : 查詢月份

案例:

 # 神奇的雙下劃線查詢
    # 1.查詢價格大於200的電影
    res = models.Movie.objects.filter(price__gt=200)
    print(res)
    # 2.查詢價格小於500的電影
    res = models.Movie.objects.filter(price__lt=500)
    print(res)
    # 3.查詢價格大於等於876.23的電影
    res = models.Movie.objects.filter(price__gte=876.23)
    print(res.query)
    # 4.查詢價格小於等於876.23的電影
    res = models.Movie.objects.filter(price__lte=500)
    print(res)
    # 5.查詢價格是123 或666 或876
    res = models.Movie.objects.filter(price__in=[123,666,876])
    print(res)
    # 6.查詢價格在200到900之間的電影  顧頭也顧尾
    res = models.Movie.objects.filter(price__range=(200,900))
    print(res)
    # 7.查詢電影名中包含字母p的電影
    res = models.Movie.objects.filter(title__contains='p')  # 預設是區分大小寫
    res = models.Movie.objects.filter(title__icontains='p')  # i忽略大小寫
   
    # 8.查詢2014年出版的電影
    res = models.Movie.objects.filter(publish_time__year=2014)
    # print(res)
    # 9.查詢是1月份出版的電影
    res = models.Movie.objects.filter(publish_time__month=1)
    print(res)

五、外來鍵欄位的增刪改查

在1.X版本中預設就是級聯更新、級聯刪除

在2.X版本中需要自己手動設定

1.一對多

1.增 直接寫真實的表字段

# publish_id是外來鍵欄位
models.Book.objects.create(title='三國演義',price=123.23,publish_id=2)

2.增 通過物件

# Publish 是modles中有關聯的表
publish_obj = models.Publish.objects.get(pk=1)
models.Book.objects.create(title='大話西遊',price=66.66,publish=publish_obj)

1.改 直接篩選出來,直接改

models.Book.objects.filter(pk=1).update(publish_id=3)

2.改 通過物件

# 先獲取出版社表id為4的物件
publish_obj = models.Publish.objects.get(pk=4)
models.Book.objects.filter(pk=1).update(publish=publish_obj)

2.多對多

1.繫結關係 add

add專門給第三張關係表新增資料
    括號內即可以傳數字也可以傳物件  並且都支援傳多個
# 1.獲取書籍物件
book_obj = models.Book.objects.filter(pk=1).first()
# 2.書籍物件點‘.’外來鍵欄位就已經跨入第三張表中了。再用add新增繫結關係
book_obj.authors.add(1,2,3)  # 給書籍繫結一個主鍵為1,2,3的作者
    # 獲取物件
    author_obj = models.Author.objects.get(pk=1)
    author_obj1 = models.Author.objects.get(pk=3)
    # 新增繫結關係
    book_obj.authors.add(author_obj)
    book_obj.authors.add(author_obj,author_obj1)

2.移除繫結關係 remove

remove專門給第三張關係表移除資料
        括號內即可以傳數字也可以傳物件  並且都支援傳多個
    # 按照具體外來鍵的值進行刪除
    book_obj = models.Book.objects.filter(pk=1).first()
    book_obj.authors.remove(2)
    book_obj.authors.remove(1,3)
    
    # 獲取相關物件刪除
    author_obj = models.Author.objects.get(pk=2)
    author_obj1 = models.Author.objects.get(pk=3)
    book_obj.authors.remove(author_obj)
    book_obj.authors.remove(author_obj,author_obj1)

3.修改繫結關係 set

 set 修改書籍與作者的關係 
        括號內支援傳數字和物件 但是需要是可迭代物件
# authors外來鍵欄位,Author類名
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.authors.set((3,))
book_obj.authors.set((2,3))


author_obj = models.Author.objects.get(pk=2)
author_obj1 = models.Author.objects.get(pk=3)
book_obj.authors.set([author_obj,author_obj1])   # 可迭代物件

4.清空關係

clear()  清空關係
    不需要任何的引數
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.authors.clear()  # 去第三張表中清空書籍為1的所有資料

六、跨表查詢

mysql中跨表查詢的方式
        1.子查詢  將一張表的查詢結果當做另外一張表的查詢條件
            正常解決問題的思路 分步操作
        2.連結串列查詢
            inner join
            left join
            right join
            union
正反向的概念
        正向
            跨表查詢的時候 外來鍵欄位是否在當前資料物件中 如果在
            查詢另外一張關係表  叫正向
            
        反向
            如果不在叫反向
        
        口訣
            正向查詢按外來鍵欄位
            反向查詢按表名小寫

案例:

正向查詢的時候 當外來鍵欄位對應的資料可以有多個的時候需要加.all()
    否則點外來鍵字典即可獲取到對應的資料物件
基於物件的反向查詢 表名小寫是否需要加_set.all()
        一對多和多對多的時候需要加
        一對一不需要

1.基於物件的跨表查詢(子查詢):

# 1.查詢書籍pk為1的出版社名稱
    book_obj = models.Book.objects.filter(pk=1).first()
    print(book_obj.publish.name)
# 2.查詢書籍pk為2的所有作者的姓名
    book_obj = models.Book.objects.filter(pk=2).first()
    author_list = book_obj.authors.all()
        for author_obj in author_list:
        print(author_obj.name)
       
# 3.查詢作者pk為1的電話號碼
    author_obj = models.Author.objects.filter(pk=1).first()
    print(author_obj.author_detail.phone)
 
# 4.查詢出版社名稱為東方出版社出版過的書籍
    publish_obj = models.Publish.objects.filter(name='東方出版社').first()
    print(publish_obj.book_set.all())
    
# 5.查詢作者為jason寫過的書
    author_obj = models.Author.objects.filter(name='jason').first()
    print(author_obj.book_set.all())
    
# 6.查詢手機號為120的作者姓名
    author_detail_obj = models.AuthorDetail.objects.filter(phone=120).first()
    print(author_detail_obj.author.name)

2.基於雙下劃線跨表查詢(連結串列查詢)

只要表之間有關係  你就可以通過正向的外來鍵欄位或者反向的表名小寫 連續跨表操作
# 1.查詢書籍pk為1的出版社名稱
    # 正向
    res = models.Book.objects.filter(pk=1).values('publish__name')  # 寫外來鍵欄位 就意味著你已經在外來鍵欄位管理的那張表中
    print(res)
    # 反向
    res = models.Publish.objects.filter(book__pk=1)  # 拿出版過pk為1的書籍對應的出版社
    res = models.Publish.objects.filter(book__pk=1).values('name')
    print(res)

# 2.查詢書籍pk為1的作者姓名和年齡
    # 正向
    res = models.Book.objects.filter(pk=1).values('title','authors__name','authors__age')
    print(res)
    # 反向
    res = models.Author.objects.filter(book__pk=1)  # 拿出出版過書籍pk為1的作者
    res = models.Author.objects.filter(book__pk=1).values('name','age','book__title')
    print(res)
    
# 3.查詢作者是jason的年齡和手機號
    # 正向
    res = models.Author.objects.filter(name='jason').values('age','author_detail__phone')
    print(res)
    # 反向
res = models.AuthorDetail.objects.filter(author__name='jason')  # 拿到jason的個人詳情
res = models.AuthorDetail.objects.filter(author__name='jason').values('phone','author__age')
print(res)

# 4.查詢書籍pk為的1的作者的手機號
    # 正向
    # 只要表之間有關係  你就可以通過正向的外來鍵欄位或者反向的表名小寫 連續跨表操作
    res = models.Book.objects.filter(pk=1).values('authors__author_detail__phone')
    print(res)
    # 反向
    res = models.AuthorDetail.objects.filter(author__book__pk=1).values('phone')
    print(res)

3.聚合查詢

需要使用到:aggregate關鍵字
from django.db.models import Max,Min,Avg,Count,Sum   # 匯入模組

res = models.Book.objects.aggregate(avg_num=Avg('price'))
print(res)
# 查詢價格最貴的書
res = models.Book.objects.aggregate(max_num=Max('price'))
print(res)
# 全部使用一遍
res = models.Book.objects.aggregate(Avg("price"), Max("price"), Min("price"),Count("pk"),Sum('price'))
print(res)

4.分組查詢

需要使用到:annotate關鍵字
    # 1.統計每一本書的作者個數
    res = models.Book.objects.annotate(author_num=Count('authors')).values('title','author_num')
    print(res)

    # 2.統計出每個出版社賣的最便宜的書的價格
    res = models.Publish.objects.annotate(min_price=Min('book__price')).values('name','min_price','book__title')
    print(res)

    # 3.統計不止一個作者的圖書
    res = models.Book.objects.annotate(author_num=Count('authors')).filter(author_num__gt=1).values('title')
    print(res)

    # 4.查詢各個作者出的書的總價格
    res = models.Author.objects.annotate(price_sum=Sum('book__price')).values('name','price_sum')
    print(res)

如何按照表中的某一個指定欄位分組?

res = models.Book.objects.values('price').annotate()  就是以價格分組

5.F查詢

在上面所有的例子中,我們構造的過濾器都只是將欄位值與某個我們自己設定的常量做比較。如果我們要對兩個欄位的值做比較,那該怎麼做呢?

Django 提供 F() 來做這樣的比較。F() 的例項可以在查詢中引用欄位,來比較同一個 model 例項中兩個不同欄位的值。

簡而言之:F()查詢可以動態獲取表字段對應的值

需要匯入模組:from django.db.models import F,Q

案例:

# 1.查詢庫存數大於賣出數的書籍
    res = models.Book.objects.filter(kucun__gt=F('maichu'))
    print(res)

# 2.將所有書的價格提高100
    res = models.Book.objects.update(price=F('price') + 100)

6.Q查詢

','逗號隔開是and關係
'|'管道符是or的關係
'~'是not關係

filter() 等方法中逗號隔開的條件是與的關係。 如果你需要執行更復雜的查詢(例如OR語句),你可以使用Q物件

示例1:

查詢 賣出數大於100 或者 價格小於100塊的

from django.db.models import Q
models.Product.objects.filter(Q(maichu__gt=100)|Q(price__lt=100))
# 1.查詢書的名字是python入門或者價格是1000的書籍
    res = models.Book.objects.filter(title='python入門',price=1000)  # and關係
    res = models.Book.objects.filter(Q(title='python入門'),Q(price=1000))  # 逗號是and關係
    res = models.Book.objects.filter(Q(title='python入門')|Q(price=1000))  # |是or關係
    res = models.Book.objects.filter(~Q(title='python入門')|Q(price=1000))  # ~是not關係

7.Q的高階用法

res = models.Book.objects.filter('title'='python入門')

    q = Q()
    q.connector = 'or'  # q物件預設也是and關係  可以通過connector改變or
    q.children.append(('title','python入門'))
    q.children.append(('price',1000))

    res = models.Book.objects.filter(q)
    print(res)