Django--ORM 多表查詢

一 . 創建外鍵 

  一對一創建外鍵python

外鍵名稱 = models.OneToOneField(to='要鏈接的類名', to_field='字段')

  一對多創建外鍵mysql

外鍵名稱 = models.ForeignKey(to='要鏈接的類名',to_field='字段')

# 外鍵要寫在一對多的 那個多的類 下面,好比一個老師對應不少學生,外鍵就要寫在學生的下面

  多對多創建外鍵git

外鍵名稱 = models.ManyToManyField(to='另外一個類名')

# 這個外鍵名稱(屬性)要寫在其中一個類的下面,而後to=另外一個類名, 這個外鍵就至關於第三張表(多對多創建外鍵必須經過第三張表)

 二 . 多表查詢(基於子查詢)

複製代碼
# models.py建立表
class Author(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=16)
    age = models.IntegerField()
    # to後面加類名 to_field後面寫類名中的字段名   這是一對一的外鍵寫法
    author_detail = models.OneToOneField(to='AuthorDetail', to_field='id')
    def __str__(self):
        return self.name

class AuthorDetail(models.Model):
    id = models.AutoField(primary_key=True)
    addr = models.CharField(max_length=16)
    tel = models.IntegerField()

class Publish(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=16)
    addr = models.CharField(max_length=16)

class Book(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=16)
    price = models.DecimalField(max_digits=6,decimal_places=2)
    # 在Book上publish變成了publish_id   這是一對多的外鍵寫法
    publish = models.ForeignKey(to='Publish',to_field='id')
    #  這個authors不是字段,他只是Book類裏面的一個屬性  這是多對多的創建第三張表的寫法
    authors = models.ManyToManyField(to='Author')
複製代碼

 

   

  對authors(第三張表的操做)sql

複製代碼
# 給id=1的書籍添加id=5和id=6這兩個做者
book_obj = models.Book.objects.filter(id=1)[0]
book_obj.authors.add(*[5, 6])   #  數字的類型是int或者str都行

# 把id=1的書籍的做者所有刪掉
book_obj = models.Book.objects.filter(id=1)[0]
book_obj.authors.clear()

# 把id=1的書籍中的id=5和id=6的這兩個做者刪掉 
book_obj = models.Book.objects.filter(id=1)[0]
book_obj.authors.remove(*[5, 6])

# 把id=1的書籍中的做者名更新成id=7和id=8這兩個做者
book_obj = models.Book.objects.filter(id=1)[0]
book_obj.authors.set([7, 8])
# set 不能用*[7, 8]      set的執行流程是先把做者所有刪除,而後添加[7, 8]
複製代碼

 

  一對一正向查詢(外鍵在哪一個表,他找別人就是正向)django

複製代碼
# 蕭峯的住址
    author_obj = models.Author.objects.get(name='蕭峯')
    # author_obj.外鍵名.要查字段  
    print(author_obj.author_detail.addr)

   # author_detail = models.OneToOneField(to='AuthorDetail', to_field='id')
    # 這個author_detail就是外鍵名
複製代碼

 

  一對一反向查詢(沒有外鍵的表查詢有外鍵的表就是反向查詢)app

# 地址是大理的英雄名字
    author_detail_obj = models.AuthorDetail.objects.get(addr='大理')
    # author_detail_obj.要查詢的表名(要小寫).要查字段
    print(author_detail_obj.author.name)

  一對多正向查詢函數

# 出版天龍八部的出版社名字
    book_obj = models.Book.objects.get(name='天龍八部')
    # book_obj.外鍵名.要查字段    
    print(book_obj.publish.name)

  一對多反向查詢spa

# 查詢城市是西夏的出版社 出版的圖書
    pub_obj = models.Publish.objects.get(city='西夏')
    # pub_obj.表名_set.all().values('name')   由於不止一個因此須要  表名_set
    print(pub_obj.book_set.all().values('name'))

  多對多正向查詢code

# 天龍八部的做者都有誰
    book_obj = models.Book.objects.get(name='天龍八部')
    # book_obj.第三張表的屬性.all().values(字段)
    print(book_obj.authors.all().values('name'))  # 這個authors雖然在Book類下面,可是它不是字段,只是屬性.

  多對多反向查詢對象

# 令狐沖寫了哪些書
    author_obj = models.Author.objects.get(name='令狐沖')
    # author_obj.表名_all().values(字段)
    print(author_obj.book_set.all().values('name'))

 三 .基於雙下劃線跨表查詢(基於join)

  正向查詢按照外鍵名,反向查詢按照表名(小寫), 和上面的同樣,外鍵字段在哪一個表中, 他找別人就是正向,相反就是反向查詢

複製代碼
# 一對一查詢
    # 查詢蕭峯做者的電話號
# 正向查詢     按照外鍵    "__" 這個是雙下劃線
# models.類名(表名).objects.filter(條件).values(外鍵名__字段)
ret = models.Author.objects.filter(name='蕭峯').values('author_detail__tel')

# 反向查詢   按照類名(小寫)
# models.類名.objects.filter(另外一個類名(小寫)__條件).values(字段)
ret = models.AuthorDetail.objects.filter(book__name='蕭峯').values('tel')
複製代碼

 

複製代碼
# 一對多查詢
    # 金庸出版社出版過的全部書籍的名字
# 正向查詢  按照外鍵
# models.類名.objects.filter(外鍵名__條件).values(字段)
ret = models.Book.objects.filter(publish__name='金庸出版社').values('name')

# 反向查詢 按照類名(小寫)
# models.類名.objects.filter(條件).values(另外一個類名(小寫)__字段)
ret = models.Publish.objects.filter(name='金庸出版社').values('book__name')
複製代碼

 

複製代碼
# 多對多查詢
    # 蕭峯這個做者寫了哪幾本書
# 正向查詢  按照外鍵
# models.類名.objects.filter(外鍵__條件).values(字段)
ret = models.Book.objects.filter(authors__name='蕭峯').values('name')

# 反向查詢  按照類名
# models.類名.objects.filter(條件).values(另外一個類名__字段)
ret = models.Author.objects.filter(name='蕭峯').values('book__name')
複製代碼

 

複製代碼
# 連續跨表查詢
# 查詢金庸出版社出版的全部的書名及做者名 # 正向查詢 ret = models.Book.objects.filter(publish__name='金庸出版社').values('name','authors__name') # 反向查詢 ret = models.Publish.objects.filter(name='金庸出版社').values('book__name','book__authors__name') # 因爲Author和Publish兩個表沒有外鍵關係因此須要經過Book表找到做者名 # 電話以6開頭的做者出版過的書名及出版社名 # 正向查詢 ret = models.Book.objects.filter(authors__author_detail__tel__startswith='6').values('name','publish__name') # 反向查詢 # 方法一 ret = models.Publish.objects.filter(book__authors__author_detail__tel__startswith='6').values('name','book__name') # 方法二 ret = models.AuthorDetail.objects.filter(tel__startswith='6').values('author__book__name','author__book__publish__name') # 因爲Author與Book是多對多的關係,而且authors寫在Book下面,因此經過author往回找的時候直接author__book.
複製代碼

 四 . 聚合查詢, 分組查詢, F查詢, Q查詢

  聚合查詢

複製代碼
# aggregate(*args, **kwargs)    是queryset的終結,queryset對象後面.aggregate  獲得一個字典再也不是queryset對象
# 計算全部書的平均價格
    from django.db.models import Avg
    models.Book.objects.all().aggregate(Avg('price'))   # 也能夠給它起名字 aggregate(a = Avg('price'))  
     # 這個objects後面的 all()寫不寫都行  能夠直接在控制器(models.Book.objects)後面寫
    
# 還能夠不止生成一個聚合函數
    from django.db.models import Avg,Max,Min
    models.Book.objects.aggregate(Avg('price'),Max('price'),Min('price'))
複製代碼

 

  分組查詢

複製代碼
------------------單表查詢(用上邊的Book表)----------------------
# 查詢每一個出版社出版了多少本書      annotate裏面寫聚合函數(Max,Min,Avg,Count)  獲得一個queryset對象

models.Book.objects.values('publish').annotate(c=Count('id'))  
# values裏面寫的是要分組的字段,每一個出版社意思就是以出版社爲分組, annotate裏面寫你要統計的, 並且必須是 別名=聚合函數這個格式

------------------多表查詢(用以前那些表) ---------------------

查詢每一個出版社出版了多少本書
models.Publish.objects.values('name').annotate(c=Count('book__id'))
# 下面這個方法比較經常使用
models.Publish.objects.annotate(c=Count('book__id')).values('name','c')
# 若是用上邊的那個方法出現關於group by的錯誤的話,須要進行一下操做:
    進入mysql裏執行SELECT @@GLOBAL.sql_mode;  看看裏面是否有    
    ONLY_FULL_GROUP_BY參數,若是有的話須要到配置文件中(my.ini或者是mysql.cnf)修改
 sql_mode ='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION'
 而後重啓mysql.
複製代碼

 

  F查詢(能夠進行兩個字段的比較)

複製代碼
# 好比說在Book表裏面加上評論數comment_num 和點贊數support_num
    # 查詢評論數大於點贊數的書
    from django.db.models import F
    models.Book.objects.filter(comment_num__gt=F('support_num'))
 
    # django 還支持F()對象之間以及F()對象與常數之間的加減乘除
    models.Book.objects.filter(comment_num__gt=F('support_num')*2)

    # 也能夠用F()來進行修改
    # 把每本書的價格添加1000
    models.Book.objects.update(price=F('price')+1000)
複製代碼

  Q查詢

    像filter()中的條件一塊兒查詢的時候都是and, 若是想要有or的關係就須要用到Q查詢

複製代碼
Q對象可使用$(and)   |(or)   ~(not) 操做組合起來. 當一個操做符用在兩個Q對象上面時,這兩個Q對象因爲操做符的做用就變成了一個新的對象.
# 查詢做者名字爲蕭峯或者段譽出版的書
models.Book.objects.filter(Q(authors__name='蕭峯')|Q(authors__name='段譽'))

# 能夠組合其餘的操做符進行操做
# 查詢做者是蕭峯或者是段譽價格不高於100的書
models.Book.objects.filter(Q(author__name='蕭峯')|Q(author__name='段譽')& ~Q(price__gt=100))

# 若是有關鍵字參數和Q查詢同時在篩選條件裏面,Q查詢必需要寫到關鍵字參數前面
# 查詢做者名字是蕭峯或者是段譽的價格爲100 的書
models.Book.objects.filter(Q(author__name='蕭峯')|Q(author__name='段譽'),price=100)
# 這個關鍵字參數要寫到Q查詢的後面,中間用逗號隔開,表示and的意思
複製代碼

五 . python腳本中調用Django環境(django外部腳本使用models)

複製代碼
import os

if __name__ == '__main__':
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "BMS.settings")
    import django
    django.setup()

    from app01 import models  #引入也要寫在上面三句以後

    books = models.Book.objects.all()
    print(books)
複製代碼
相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息