Django--ORM 多表查詢


一 . 建立外鍵 

  一對一建立外鍵

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

  一對多建立外鍵

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

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

  多對多建立外鍵

外鍵名稱 = 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(第三張表的操作)

# 給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]

 

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

# 蕭峰的住址
    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就是外鍵名

 

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

# 地址是大理的英雄名字
    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)

  一對多反向查詢

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

  多對多正向查詢

# 天龍八部的作者都有誰
    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)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM