python 之 Django框架(orm單表查詢、orm多表查詢、聚合查詢、分組查詢、F查詢、 Q查詢、事務、Django ORM執行原生SQL)

12.329 orm單表查詢
import os if __name__ == '__main__': # 指定當前py腳本須要加載的Django項目配置信息
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "orm_demo.settings") import django django.setup() # 啓動Django項目
    from app01 import models #返回QuerySet對象的方法:
    ret = models.Book.objects.all() print(ret)                      # QuerySet類型:書籍對象的列表
​ ret = models.Book.objects.filter(title="圍城")  # QuerySet類型 --> 書籍對象的列表
    # id值大於1
    ret = models.Book.objects.filter(id__gt=1) # id值小於3
    ret = models.Book.objects.filter(id__lt=3) # 出版日期是2017年的書
    ret = models.Book.objects.filter(publisher_date__year=2017) # 出版日期大於2017年
    ret = models.Book.objects.filter(publisher_date__year__gt=2017) # 書名中包含'曌'的書
    ret = models.Book.objects.filter(title__contains="") # 書名中包含'曌'的書而且出版年份是2018年
    ret = models.Book.objects.filter(title__contains="", publisher_date__year=2018) ​ # get方法若是符合篩選條件的對象超過一個或者沒有都會拋出錯誤。
    #符合篩選條件的對象只有一個,則返回具體的類對象實例:書籍對象,而不是列表
    ret = models.Book.objects.get(id=10) print(ret)                          #報錯
    # 使用filter檢索的時候沒有知足條件的數據就返回一個空 QuerySet
    ret = models.Book.objects.filter(id=10) print(ret)                          #[]
# 將知足條件的去掉,留下不知足條件的
    ret = models.Book.objects.exclude(id__in=[1,3,4]) print(ret) # 按字段排序
    ret = models.Book.objects.all().order_by("price")  # QuerySet類型:根據price字段對全部數據排序
    ret = models.Book.objects.all().order_by("-price") #反轉
    ret = models.Book.objects.all().order_by("price").reverse() # 按照出版時間排序後反轉再去字段值 # QuerySet類型:字段及字段值的字典的列表
    ret = models.Book.objects.all().order_by("publisher_date").reverse().values("title") #特殊的QuerySet:
    #values() 取字段的值,以字典返回
    ret = models.Book.objects.filter(publisher_date__year=2018).values("title", "publisher_date") print(ret)          # QuerySet類型:字段及字段值的字典的列表
    #values_list() 取字段的值,以元組返回
    ret = models.Book.objects.filter(publisher_date__year=2018).values_list("title", "publisher_date")        # QuerySet類型:字段值的元祖的列表
    # 連表查詢
    ret = models.Book.objects.all().values("publisher__name").distinct() print(ret)           # QuerySet類型:字段及字段值的字典的列表,並去重
#返回數字的方法
    # count 計數
    ret = models.Book.objects.all().count()  # 數字:結果集中數據的個數  #返回具體對象
    #first()和last()
    ret = models.Book.objects.all().first()  #結果集中的第一個對象
    #get()
    ret = models.Book.objects.get(id=1)      #返回匹配到的對象,有且僅有一個 #返回布爾值的方法
    # 判斷結果集中是否有數據
    ret = models.Book.objects.all().exists()  # 布爾值:結果集中是否有數據
12.3210 orm多表查詢(方式二)

ForeignKey操做:書籍表(Book表)外鍵關聯出版社表(Publisher表)mysql

正向查找:git

1.基於對象(子查詢) book_obj = models.Book.objects.first()    # 第一本書對象
print(book_obj.publisher)                # 獲得這本書關聯的出版社對象
print(book_obj.publisher.name)            # 獲得出版社對象的名稱
2.基於雙下劃線字段方法(聯表查詢) print(models.Book.objects.values_list("publisher__name"))

反向查找:sql

1.基於對象(子查詢) publisher_obj = models.Publisher.objects.first()   # 找到第一個出版社對象
books = publisher_obj.book_set.all()              # 找到第一個出版社出版的全部書籍對象
titles = books.values_list("title")               # 找到第一個出版社出版的全部書籍的書名 #若是設置了 related_name="books" #publisher= models.ForeignKey(to="Publisher", related_name="books")
publisher_obj = models.Publisher.objects.first() ret = publisher_obj.books.all() print(ret)#<QuerySet [<Book: 西瓜物語>, <Book: 香蕉物語>]>
2.基於雙下劃線的字段方法(聯表查詢) ret = models.Publisher.objects.filter(id=1).values_list("book__title") print(ret)#<QuerySet [('西瓜物語',), ('香蕉物語',)]>
titles = models.Publisher.objects.values_list("book__title") print(titles)#<QuerySet [('西瓜物語',), ('香蕉物語',), ('番茄物語',), (None,)]>
#若是related_query_name="books"或者 related_name="books"(若是兩個同時出現,則以related_query_name爲準)
titles = models.Publisher.objects.filter(id=1).values_list("books__title") #<QuerySet [('西瓜物語',), ('香蕉物語',)]>
titles = models.Publisher.objects.filter(id=1).values("books__title") #<QuerySet [{'books__title': '西瓜物語'}, {'books__title': '香蕉物語'}]>

ManyToManyField:(使用方式二:經過ManyToManyField自動建立第三張表)數據庫

models:django

class Book(models.Model): title = models.CharField(max_length=32) publish_date = models.DateField(auto_now_add=True) price = models.DecimalField(max_digits=5, decimal_places=2) memo = models.TextField(null=True) # 建立外鍵,關聯publish
    publisher = models.ForeignKey(to="Publisher", ) # 建立多對多關聯author
    author = models.ManyToManyField(to="Author") ​ class Author(models.Model): name = models.CharField(max_length=32) age = models.IntegerField() phone = models.CharField(max_length=11) detail = models.OneToOneField(to="AuthorDetail")

class RelatedManager:"關聯管理器"是在一對多或者多對多的關聯上下文中使用的管理器。app

它存在於下面兩種狀況:外鍵關係的反向查詢多對多關聯關係,簡單來講就是當 "."後面的對象 可能存在多個的時候就能夠使用如下的方法函數

create():建立一個新的對象,保存對象,並將它添加到關聯對象集之中,返回新建立的對象。fetch

#models.Book.objects.first().author獲得是一個class RelatedManager對象,使用.create操做author表和第三張表
1.正向建立author表數據 ret = models.Book.objects.first().author.create(name="張三",age=16,phone="18012xxxx",detail_id=4) #作了兩件事情:1. 建立了一個新的做者,2. 將新建立的做者和第一本書作關聯
ret = models.Book.objects.first().author.all().values("id") print(ret)#<QuerySet [{'id': 1}, {'id': 3}, {'id': 15}]>
2.反向建立book表數據 import datetime models.Author.objects.first().book_set.create(title="番茄物語", publish_date=datetime.date.today())

add():把指定的model對象或對象id添加到關聯對象集中atom

#添加對象
author_objs = models.Author.objects.filter(id__lt=3) models.Book.objects.first().author.add(*author_objs) #添加id
models.Book.objects.first().author.add(*[1, 2]) models.Book.objects.first().author.add(1) #第一本書關聯的做者id
ret = models.Book.objects.first().author.all().values("id") print(ret)#<QuerySet [{'id': 1}, {'id': 3}, {'id': 15}]>

set():更新model對象的關聯對象。spa

ret=models.Book.objects.first().author.set([2, 3])#設置第三張表的關聯關係,給第一個book對象加上id=2和3
ret = models.Book.objects.first().author.all() print(ret)#<QuerySet [<Author: 小仙女>, <Author: 大烏龜>, <Author: 張曌>]>
ret = models.Book.objects.first().author.all().values("id") print(ret)#<QuerySet [{'id': 1}, {'id': 3}, {'id': 15}]>

remove():從關聯對象集中移除執行的model對象

models.Book.objects.first().author.remove(3)#找到第一個圖書對象所對應的全部做者,到第三張表中刪除它與id=3的做者的關聯關係#<QuerySet [{'id': 1}, {'id': 15},{'id'=3}]>
ret = models.Book.objects.first().author.all().values("id") print(ret)        #<QuerySet [{'id': 1}, {'id': 15}]>

clear():從關聯對象集中移除一切對象。

#<QuerySet [{'id': 1}, {'id': 15}]>
models.Book.objects.first().author.clear() ret = models.Book.objects.first().author.all().values("id") print(ret)#<QuerySet []>

注意:對於ForeignKey對象,clear()和remove()方法僅在null=True時存在

all():

ret = models.Book.objects.first().author.all()#獲得第一本書對象對應的做者對象集
print(ret)                                #<QuerySet [Author object,Author object,Author object]>
12.3211 聚合查詢

aggregate()是QuerySet 的一個終止子句,它返回一個包含一些鍵值對的字典。

鍵的名稱是聚合值的標識符,值是計算出來的聚合值。鍵的名稱是按照字段和聚合函數的名稱自動生成出來的。

from django.db.models import Avg, Sum, Max, Min, Count models.Book.objects.all().aggregate(Avg("price")) #{'price__avg': 13.233333}
ret = models.Book.objects.aggregate(Sum("price")) #{'price__sum': Decimal('13.10')
ret = models.Book.objects.aggregate(total_price=Sum("price")) #{'total_price': Decimal('13.10')}
ret = models.Book.objects.aggregate(avg_price=Avg("price"), max_price=Max("price"), min_price=Min("price")) #{'avg_price': 4.366667, 'max_price': Decimal('12.00'), 'min_price': Decimal('0.10')}
12.3212 分組查詢

單表查詢分組:按照部門分組求平均工資

select dept,AVG(salary) from employee group by dept;

orm查詢:

from django.db.models import Avg models.Employee.objects.values("dept").annotate(avg=Avg("salary") #<QuerySet [{'dept': '教學部', 'avg': 221.0}, {'dept': '銷售部', 'avg': 21.0}, {'dept': '人事部', 'avg': 999.0}]> 
models.Employee.objects.values("dept").annotate(avg=Avg("salary").values('dept', "avg") #<QuerySet [{'dept': '教學部', 'avg': 221.0}, {'dept': '銷售部', 'avg': 21.0}, {'dept': '人事部', 'avg': 999.0}]> 

連表查詢的分組:按照部門分組求平均工資

select dept.name,AVG(salary) from employee inner join dept on (employee.dept_id=dept.id) group by dept_id;

ORM查詢:

from django.db.models import Avg models.Dept.objects.annotate(avg=Avg("employee__salary")).values("name", "avg") ​ models.Employee.objects.values("dept__name").annotate(avg=Avg("salary")) #<QuerySet [{'dept__name': '垃圾部', 'avg': 221.0}, {'dept__name': '保安部', 'avg': 21.0}, {'dept__name': '教學部', 'avg': 999.0}]> 
​ models.Employee.objects.values("dept__name").annotate(avg=Avg("salary")).values('dept', "avg") #<QuerySet [{'dept__name': '垃圾部', 'avg': 221.0}, {'dept__name': '保安部', 'avg': 21.0}, {'dept__name': '教學部', 'avg': 999.0}]> 
​ models.Employee.objects.values("dept__name") #<QuerySet [{'dept__name': '垃圾部'}, {'dept__name': '保安部'}, {'dept__name': '教學部'}]> 

做者、圖書、出版社表關係:

from django.db import models # 出版社
class Publisher(models.Model): name = models.CharField(max_length=32) city = models.CharField(max_length=32) #
class Book(models.Model): title = models.CharField(max_length=32) publish_date = models.DateField(auto_now_add=True) price = models.DecimalField(max_digits=5, decimal_places=2) # 建立外鍵,關聯publish
    publisher = models.ForeignKey(to="Publisher") # 建立多對多關聯author
    author = models.ManyToManyField(to="Author") # 做者
class Author(models.Model): name = models.CharField(max_length=32)

示例:

1.統計每一本書的做者個數 (1):ret = models.Book.objects.annotate(autor_num=Count("author")).values("title", "autor_num") #<QuerySet [{'title': '西瓜物語', 'autor_num': 0}, {'title': '香蕉物語', 'autor_num': 1}, {'title': '番茄物語', 'autor_num': 1}]>
​ (2):book_list = models.Book.objects.all().annotate(author_num=Count("author")) print(book_list)        #<QuerySet [<Book: 西瓜物語>, <Book: 香蕉物語>, <Book: 番茄物語>]>
for obj in book_list: print(obj.author_num)#0 1 1
2.統計出每一個出版社出版的最便宜的書的價格 (1):ret = models.Publisher.objects.annotate(min_price=Min("book__price")).values("name", "min_price") #<QuerySet [{'name': '清華出版社', 'min_price': Decimal('0.10')}, {'name': '香江出版社', 'min_price': Decimal('12.00')}, 
{'name': '北大青鳥出版社', 'min_price': None}]> (2):ret=models.Book.objects.values("publisher__name").annotate(min_price=Min("price")) #<QuerySet [{'publisher__name': '清華出版社', 'min_price': Decimal('0.10')}, #{'publisher__name': '香江出版社', 'min_price': Decimal('12.00')}]>
​ (3):publisher_list = models.Publisher.objects.annotate(min_price=Min("book__price")) print(publisher_list) #<QuerySet [<Publisher: 清華出版社>, <Publisher: 香江出版社>, <Publisher: 北大青鳥出版社>]>
for obj in publisher_list: print(obj.min_price)#0.10 12.00 None
3.統計不止一個做者的圖書 models.Book.objects.annotate(author_num=Count("author")).filter(author_num__gt=1)#<QuerySet []>
4.根據一本圖書做者數量的多少對查詢集 QuerySet進行排序 models.Book.objects.annotate(author_num=Count("author")).order_by("author_num") #<QuerySet [<Book: 西瓜物語>, <Book: 香蕉物語>, <Book: 番茄物語>]>
5.查詢各個做者出的書的總價格 models.Author.objects.annotate(sum_price=Sum("book__price")).values("name", "sum_price") #<QuerySet [{'name': '小仙女', 'sum_price': Decimal('1.00')}, {'name': '小魔女', 'sum_price': Decimal('12.00')},  #{'name': '大烏龜', 'sum_price': None}, {'name': '張san', 'sum_price': None}]>
12.3213 F查詢

F() 的實例能夠在查詢中引用字段,來比較同一個 model 實例中兩個不一樣字段的值。

商品表結構:

from django.db import models ​ class Product(models.Model): name = models.CharField(max_length=32) price = models.DecimalField(max_digits=6, decimal_places=2) # 庫存數
    keep = models.IntegerField() # 賣出數
    sale = models.IntegerField() ​ def __str__(self): return  "{}:{}:{}:{}".format(self.name, self.price, self.keep, self.sale)

示例:

from django.db.models import F 1.查詢出賣出數大於庫存數的商品 models.Product.objects.filter(sale__gt=F("keep")) #<QuerySet [<Product: 跟哪吒學詩歌:59.00:50:10000>, <Product: 跟苑局學三不:55.00:100:200>]>
2.Django支持F()對象之間以及F()對象和常數之間的加減乘除和取模的操做 models.Product.objects.filter(sale__gt=F('keep')*2) #<QuerySet [<Product: 跟哪吒學詩歌:59.00:50:10000>]>
3.修改操做也能夠使用F函數:好比將每一個產品的價格提升50元 models.Product.objects.all().update(price=F("price")+50) 4.把全部商品名後面加上"新款"
from django.db.models.functions import Concat from django.db.models import Value models.Product.objects.all().update(name=Concat(F("name"),  Value("新款")))
12.3214 Q查詢

filter() 等方法中的關鍵字參數查詢都是一塊兒進行「AND」 的。 若是須要執行更復雜的查詢(例如OR語句),能夠使用Q對象

#賣出數大於100 而且 價格大於100塊的
models.Product.objects.filter(sale__gt=100, price__gt=100) #<QuerySet [<Product: 跟哪吒學詩歌新款:259.00:50:10000>, <Product: 跟苑局學三不新款:255.00:100:200>]>

示例:

from django.db.models import Q 1.查詢賣出數大於100或者價格小於100的 models.Product.objects.filter(Q(sale__gt=100)|Q(price__lt=100))  #|:或 #<QuerySet [<Product: 跟哪吒學詩歌新款:259.00:50:10000>, <Product: 跟苑局學三不新款:255.00:100:200>]>
2.查詢庫存數是100而且賣出數不是0的產品 models.Product.objects.filter(Q(keep=100)&~Q(sale=0))           #&:與,~:非
models.Product.objects.filter(Q(kucun=100),~Q(maichu=0)) #<QuerySet [<Product: 跟苑局學三不新款:255.00:100:200>]>
models.Product.objects.filter(Q(kucun=100)&~Q(maichu=0)).values('name') #<QuerySet [{'name': '跟苑局學三不新款'}]>
models.Product.objects.filter(Q(kucun=100)&~Q(maichu=0)).values_list('name') #<QuerySet [('跟苑局學三不新款',)]>

查詢函數能夠混合使用Q 對象和關鍵字參數。全部提供給查詢函數的參數(關鍵字參數或Q 對象)都將"AND」在一塊兒。可是,若是出現Q 對象,它必須位於全部關鍵字參數的前面

#查詢產品名包含新款, 而且庫存數大於60或者價格小於100的產品
models.Product.objects.filter(Q(keep__gt=60)|Q(price__lt=100), name__contains="新款") #<QuerySet [<Product: 跟苑局學三不新款:255.00:100:200>]>
12.3215 事務

開啓一個事務能夠包含一些sql語句,這些sql語句要麼同時成功,要麼都不成功,稱之爲事務的原子性 做用:事務用於將某些操做的多個SQL做爲原子性操做,一旦有某一個出現錯誤,便可回滾到原來的狀態,從而保證數據庫數據完整性。

import os if __name__ == '__main__': os.environ.setdefault("DJANGO_SETTINGS_MODULE", "BMS.settings") import django django.setup() import datetime from app01 import models try: from django.db import transaction with transaction.atomic(): #開啓事務
            new_publisher = models.Publisher.objects.create(name="火星出版社") models.Book.objects.create(title="橘子物語", publish_date=datetime.date.today(), publisher_id=10) # 指定一個不存在的出版社id,上一行建立一條出版社數據被回滾,數據庫並未建立新數據
    except Exception as e: print(str(e))
12.3216 Django ORM執行原生SQL

不少狀況下咱們不須要將查詢結果映射成模型,或者咱們須要執行DELETE、 INSERT以及UPDATE操做,在這些狀況下,咱們能夠直接訪問數據庫,徹底避開模型層。咱們能夠直接從django提供的接口中獲取數據庫鏈接,而後像使用pymysql模塊同樣操做數據庫

from django.db import connection, connections cursor = connection.cursor()  # cursor = connections['default'].cursor()
cursor.execute("""SELECT * from auth_user where id = %s""", [1]) ret = cursor.fetchone()
相關文章
相關標籤/搜索