Django -ORM
單表操作
添加記錄
1 方法一: 實例化Book類 進行添加記錄 2 3 book_obj = Book(id=1,title='python',price=101,pub_date='2014-02-13',publish="華夏出版社") 4 book_obj.save() # 此方法添加之后必須有 save 操作 ,否則數(shù)據(jù)不會增加 5 6 方法二: 使用Book的 object管理器的create方法添加記錄 7 obj = Book.objects.create(title='C++',price=89,pub_date='2014-12-03',publish='海浪出版社') 8 print(obj.title )
查詢表記錄API
(1). all()方法:查詢所有數(shù)據(jù) 返回一個Queryset對象
(2).first() 和 last()方法: 返回第一個和最后一個對象 返回值:models對象 調(diào)用者: Queryset
(3). filter(**kwargs):返回和篩選條件相匹配的對象 調(diào)用者:object管理器 返回值:Queryset對象
(4).get(**kwargs)方法: 返回與所給篩選條件相匹配的model對象 調(diào)用者:object管理器 返回值:model對象
(5). exclude(**kwargs)方法:排除符合條件的數(shù)據(jù) 調(diào)用者:Queryset對象 返回值:Queryset對象
(6). order_by(**kwargs)方法:根據(jù)條件進行排序 調(diào)用者:Queryset對象 返回值:Queryset對象
(7).count()方法:對數(shù)據(jù)計數(shù)(可加約束) 調(diào)用者:object管理器 返回值:int數(shù)值
(8).exist()方法:判斷數(shù)據(jù)是否為空 調(diào)用者:Queryset對象 返回值:bool類型
(9).value()方法:通過內(nèi)循環(huán)獲取對應(yīng)字段的數(shù)據(jù) 調(diào)用者:object管理器或者Queryset對象 返回值:Queryset對象(其中數(shù)據(jù)以字典的形式存儲)
(10).value_list()方法:通過內(nèi)循環(huán)獲取對應(yīng)字段的數(shù)據(jù) 調(diào)用者:object管理器或者Queryset對象 返回值:Queryset對象(其中數(shù)據(jù)以元組的形式存儲)
(11).distinct()方法:對于數(shù)據(jù)中的某一字段進行去重 調(diào)用者:Queryset對象 返回值:Queryset對象(其中數(shù)據(jù)以字典的形式存儲)
1 obj = Book.objects.all() 2 print(obj) # 返回Queryset列表對象 :[obj1,obj2,obj3,....] 3 print(type(obj)) 4 5 for i in obj: 6 print(i.title) 7 8 ''' 9 遍歷書名: 10 python 11 java 12 lua 13 lua 14 lua 15 C++ 16 ''' 17 print(obj[0].title,obj[1].title) # python java
first_obj = Book.objects.all().first() last_obj = Book.objects.all().last() print(first_obj,last_obj) # Book object (1) Book object (6) # 相當于 first_obj = Book.objects.all()[0] print(first_obj) # Book object (1)
book_list = Book.objects.filter(publish='海龜出版社') print(book_list) # <QuerySet [<Book: Book object (2)>, <Book: Book object (3)>, <Book: Book object (4)>, <Book: Book object (5)>]> fir_obj = Book.objects.filter(publish='海龜出版社').first() # Book object (2) last_obj = Book.objects.filter(publish='海龜出版社').last() # Book object (5)
# 只有結(jié)果為一時才有效 查詢結(jié)果為空或者為多者時都會報錯 obj = Book.objects.get(title='python') # model對象 :Book object (1) print(obj.title) # python # obj = Book.objects.get(title='lua') # 查詢結(jié)果為多者報錯:get() returned more than one Book -- it returned 3!
book_list = Book.objects.all().exclude(title='python') # 單條件排除 book_list=Book.objects.all().exclude(title='C++',publish="海浪出版社") # 多條件排除 # for book in book_list: # print(book.publish)
obj = Book.objects.all().order_by("title") # 單條件排序 obj2 = Book.objects.all().order_by("title","price") # 多條件排序
res = Book.objects.all().count() print(res,{"type":type(res)}) # 6 {'type': <class 'int'>}
ret = Book.objects.all().exists() print(ret,{"type":type(ret)}) # True {'type': <class 'bool'>}
ret1 = Book.objects.all().values("title") # 等于 ret1 = Book.objects.values("title") ret2 = Book.objects.all().values("title",'price') print(ret1,{"type":type(ret1)}) # # <QuerySet [{'title': 'python'}, {'title': 'java'}, {'title': 'lua'}, {'title': 'Go'}, {'title': 'C#'}, {'title': 'C++'}]> {'type': <class 'django.db.models.query.QuerySet'>} print(ret2,{"type":type(ret2)}) # <QuerySet [{'title': 'python', 'price': Decimal('101.00')}, {'title': 'java', 'price': Decimal('100.00')}, {'title': 'lua', 'price': Decimal('99.00')}, {'title': 'Go', 'price': Decimal('68.00')}, {'title': 'C#', 'price': Decimal('70.00')}, {'title': 'C++', 'price': Decimal('89.00')}]> {'type': <class 'django.db.models.query.QuerySet'>}
ret1 = Book.objects.all().values_list("title") # ret1 = Book.objects.values("title") # 同上 ret2 = Book.objects.all().values_list("title", 'price') # print(ret1, {"type": type(ret1)}) # <QuerySet [('python',), ('java',), ('lua',), ('Go',), ('C#',), ('C++',)]> {'type': <class 'django.db.models.query.QuerySet'>} print(ret2, {"type": type(ret2)}) # <QuerySet [('python', Decimal('101.00')), ('java', Decimal('100.00')), ('lua', Decimal('99.00')), ('Go', Decimal('68.00')), ('C#', Decimal('70.00')), ('C++', Decimal('89.00'))]> {'type': <class 'django.db.models.query.QuerySet'>}
ret = Book.objects.all() print(ret) ret1 = Book.objects.values('price') print(ret1) ret2 = Book.objects.values('price').distinct() print(ret2) ''' 結(jié)果: ret: <QuerySet [<Book: Book object (1)>, <Book: Book object (2)>, <Book: Book object (3)>, <Book: Book object (4)>, <Book: Book object (5)>, <Book: Book object (6)>]> ret1: <QuerySet [{'price': Decimal('100.00')}, {'price': Decimal('100.00')}, {'price': Decimal('99.00')}, {'price': Decimal('68.00')}, {'price': Decimal('70.00')}, {'price': Decimal('89.00')}]> ret2: <QuerySet [{'price': Decimal('100.00')}, {'price': Decimal('99.00')}, {'price': Decimal('68.00')}, {'price': Decimal('70.00')}, {'price': Decimal('89.00')}]> '''
========================= 單表查詢之模糊查詢 =========================
數(shù)值方面模糊查詢
(1). price__lt 查詢價格小于80的數(shù)據(jù)
ret1 = Book.objects.filter(price__lt=80) print(ret1) # <QuerySet [<Book: Book object (4)>, <Book: Book object (5)>]>
(2). price__gt 查詢價格大于70的數(shù)據(jù)
ret2 = Book.objects.filter(price__gt=70) print(ret2) # <QuerySet [<Book: Book object (1)>, <Book: Book object (2)>, <Book: Book object (3)>, <Book: Book object (5)>, <Book: Book object (6)>]>
(3).查詢價格大于70且價格小于80的數(shù)據(jù)
ret3 = Book.objects.filter(price__gt=70,price__lt=80,) print(ret3) # <QuerySet [<Book: Book object (5)>]>
(4).查詢價格為列表中的數(shù)據(jù)
ret4 = Book.objects.filter(price__in=[100,200]) print(ret4) # <QuerySet [<Book: Book object (1)>]>
======== 內(nèi)容方面模糊查詢
===包含方面查詢:
(1).查詢title字段包含小寫字母”o“的數(shù)據(jù) 區(qū)分大小寫
ret1 = Book.objects.filter(title__contains="o") print(ret1) # <QuerySet [<Book: Book object (5)>, <Book: Book object (6)>]> # 查詢title字段包含小寫字母”O(jiān)“的數(shù)據(jù) ret2 = Book.objects.filter(title__contains="O") print(ret2) # <QuerySet []> # 沒有數(shù)據(jù)顯示為空
(2).不區(qū)分大小寫查詢
ret = Book.objects.filter(title__icontains="O") print(ret) # <QuerySet []>
===開頭結(jié)尾查詢:
1、查詢以”C“為開頭的數(shù)據(jù) 區(qū)分大小寫
ret1 = Book.objects.filter(title__startswith='C') print(ret1) # <QuerySet [<Book: Book object (5)>, <Book: Book object (6)>]>
2、查詢以”c“為開頭的數(shù)據(jù) 區(qū)分大小寫
ret1 = Book.objects.filter(title__startswith='c') print(ret1) # <QuerySet []>
3、查詢以”c“為開頭的數(shù)據(jù) 不區(qū)分大小寫
ret1 = Book.objects.filter(title__istartswith='c') print(ret1) # <QuerySet [<Book: Book object (5)>, <Book: Book object (6)>]>
4、查詢以”n“為結(jié)尾的數(shù)據(jù) 區(qū)分大小寫
ret1 = Book.objects.filter(title__endswith='n') print(ret1) # <QuerySet [<Book: Book object (1)>]>
5、查詢以”N“為結(jié)尾的數(shù)據(jù) 區(qū)分大小寫
ret1 = Book.objects.filter(title__endswith='N') print(ret1) # <QuerySet []>
6、查詢以”N“為結(jié)尾的數(shù)據(jù) 不區(qū)分大小寫
ret1 = Book.objects.filter(title__iendswith='N') print(ret1) # <QuerySet [<Book: Book object (1)>]>
========== 日期方面查詢
1、 查詢年份為2014
ret1 = Book.objects.filter(pub_date__year=2014,) print(ret1) # <QuerySet [<Book: Book object (1)>, <Book: Book object (6)>]>
2、 查詢年份為2014 月份為12
ret2=Book.objects.filter(pub_date__year=2014,pub_date__month=12) print(ret2) # <QuerySet [<Book: Book object (6)>]>
3、 查詢年份為2014 月份為12 天數(shù)為3的數(shù)據(jù)
ret3 = Book.objects.filter(pub_date__year=2014,pub_date__month=12,pub_date__day=3) print(ret3) # <QuerySet [<Book: Book object (6)>]>
刪除記錄和修改記錄
1、 刪除:delete()方法 調(diào)用者:Queryset對象 和 model對象
ret = Book.objects.filter(title="C++").delete() # Queryset對象調(diào)用 print(ret) # (1, {'app01.Book': 1}) ret1 = Book.objects.filter(publish="海洋出版社").first().delete() # Queryset對象調(diào)用 print(ret1) # (1, {'app01.Book': 1})
2、 修改記錄:update()方法 調(diào)用者: Queryset對象
ret = Book.objects.filter(title="C#").update(price=99)# print(ret) # 2
多表操作
數(shù)據(jù)庫關(guān)系:
- 一對一
- 一對多
- 多對多
一、創(chuàng)建模型
實例:我們來假定下面這些概念,字段和關(guān)系
作者模型:一個作者有姓名和年齡。
作者詳細模型:把作者的詳情放到詳情表,包含生日,手機號,家庭住址等信息。作者詳情模型和作者模型之間是一對一的關(guān)系(one-to-one)
出版商模型:出版商有名稱,所在城市以及email。
書籍模型: 書籍有書名和出版日期,一本書可能會有多個作者,一個作者也可以寫多本書,所以作者和書籍的關(guān)系就是多對多的關(guān)聯(lián)關(guān)系(many-to-many);一本書只應(yīng)該由一個出版商出版,所以出版商和書籍是一對多關(guān)聯(lián)關(guān)系(one-to-many)。
模型建立如下:
class Publish(models.Model): ''' 出版社信息表 ''' nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) city = models.CharField(max_length=32) tel = models.IntegerField() email = models.EmailField() class Book(models.Model): ''' 書籍表 ''' nid = models.AutoField(primary_key=True) title = models.CharField(max_length=32) price = models.DecimalField(decimal_places=2,max_digits=8) pub_date = models.DateField() # 與Publish表建立一對多的關(guān)系 外鍵建立在多的一方:ForeignKey(to="關(guān)系表",to_field="關(guān)聯(lián)字段",on_delete=models.CASCADE) publish = models.ForeignKey(to="Publish",to_field="nid",on_delete=models.CASCADE) # 與Author表建立多對多的關(guān)系 ManyToManyField(to="關(guān)系表",) authors = models.ManyToManyField(to="Author",) class AuthorDetail(models.Model): ''' 作者詳情表 ''' nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) email = models.EmailField(max_length=32) addr = models.CharField(max_length=32) class Author(models.Model): ''' 作者表 ''' nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) # 與作者詳情表為一對一關(guān)系 使用OneToOneField(to="關(guān)系表",to_field="關(guān)聯(lián)字段",on_delete=models.CASCADE) # 在django 2.0 以上版本 需要加上 on_delete=models.CASCADE # 不然會報錯 ”TypeError: __init__() missing 1 required positional argument: 'on_delete'“ authordetail = models.OneToOneField(to="AuthorDetail",to_field="nid" ,on_delete=models.CASCADE) # 在django 2.0 以上版本 需要加上 on_delete=models.CASCADE
注意:
在django 2.0 以上版本 需要加上 “ on_delete=models.CASCADE ”, 不然會報錯 ”TypeError: __init__() missing 1 required positional argument: 'on_delete'“
執(zhí)行命令后生產(chǎn)表如下:

其中表“app01_book_authors” 是ORM根據(jù)models中的關(guān)聯(lián)關(guān)系生成的,不是我們手動創(chuàng)建的
# 與Author表建立多對多的關(guān)系 ManyToManyField(to="關(guān)系表",) authors = models.ManyToManyField(to="Author",)
注意事項:
- 表的名稱myapp_modelName,是根據(jù) 模型中的元數(shù)據(jù)自動生成的,也可以覆寫為別的名稱
- id 字段是自動添加的
- 對于外鍵字段,Django 會在字段名上添加"_id" 來創(chuàng)建數(shù)據(jù)庫中的列名
- 這個例子中的CREATE TABLE SQL 語句使用PostgreSQL 語法格式,要注意的是Django 會根據(jù)settings 中指定的數(shù)據(jù)庫類型來使用相應(yīng)的SQL 語句。
- 定義好模型之后,你需要告訴Django _使用_這些模型。你要做的就是修改配置文件中的INSTALL_APPSZ中設(shè)置,在其中添加models.py所在應(yīng)用的名稱。
- 外鍵字段 ForeignKey 有一個 null=True 的設(shè)置(它允許外鍵接受空值 NULL),你可以賦給它空值 None
一、添加記錄:
(1)一對一添加
# 添加出版社信息(單表) pub = Publish.objects.create(nid=1,name="人民出版社",city="北京",tel=1234456,email="12156@qq.com") pub = Publish.objects.create(name="海南出版社",city="海南",tel=1232316,email="2421356@qq.com")
數(shù)據(jù)庫數(shù)據(jù):

(2)一對多添加
往書籍Book表中添加數(shù)據(jù),并關(guān)聯(lián)出版社Publish表
# 方式一 # book_obj = Book.objects.create(nid=2,title="java",price=480,pub_date="2018-05-06",publish_id=1) # print(book_obj.title) # print(book_obj.price) # print(book_obj.publish) # print(book_obj.publish.city) # print(book_obj.publish.email) # print(book_obj.publish.tel) # print(book_obj.publish.tel) # print(book_obj.publish_id) # 方式二 # 先取出一個Publish對象pub_obj 然后讓publish=pub_obj Django會根據(jù)book表里的publish關(guān)系獲取到對應(yīng)的出版社id 然后進行關(guān)聯(lián) # pub_obj = Publish.objects.filter(nid=1).first() # book_obj = Book.objects.create(title="lua",price=12312,pub_date="2011-02-16",publish=pub_obj) # # print(book_obj.publish) # Publish object (1) # print(book_obj.publish.city) # 北京 # print(book_obj.publish.email) # 12156@qq.com # print(book_obj.publish.tel) # 1234456 # print(book_obj.publish_id) # 1
數(shù)據(jù)庫數(shù)據(jù):表app01_book

(3)多對多添加
現(xiàn)在往作者表:Author、作者詳情表AuthDetail中添加數(shù)據(jù),并進行關(guān)聯(lián)
# 創(chuàng)建作者信息 AuthorDetail.objects.create(email="123123@qq.com",addr="sdfasdf") AuthorDetail.objects.create(email="421233@qq.com",addr="gesdf") AuthorDetail.objects.create(email="23145@qq.com",addr="hainan") AuthorDetail.objects.create(email="34212@qq.com",addr="beijing") Author.objects.create(name="Tom",authordetail_id=1) Author.objects.create(name="Jane",authordetail_id=2) Author.objects.create(name="Tone",authordetail_id=3) Author.objects.create(name="Jin",authordetail_id=4) # 給python關(guān)聯(lián)作者 book1 = Book.objects.get(title='python') book2 = Book.objects.get(title='java') book1.authors.add(1) book1.authors.add(2) # 上面兩步等同于 # book1.authors.add(*[1,2]) book2.authors.add(2,3) # 解決關(guān)聯(lián)信息 book1.authors.remove(1) # 單條解除 book1.authors.clear() # 全部解除 print(book2.authors.all()) # <QuerySet [<Author: Tom>, <Author: Jin>]>
表app01_author:

表app01_authordetail :

表app01_book_authors :

二、查詢記錄:
=========================基于對象的跨表查詢===========================
正反向查詢:
''' 查詢分為正向和反向查詢 比如表A和表B 關(guān)聯(lián)屬性在A中 根據(jù)字段進行查詢:obj.關(guān)聯(lián)屬性 正向查詢: A----------------------->B 根據(jù)表名進行查詢:obj.表名小寫_set.all() 反向查詢: B------------------------>A '''
一對多查詢
''' 一對多: 正向查詢: Book--------------->Publish book_obj.publish 反向查詢: Publish --------------->Book pub_obj.book_set ''' # 表Book和表Publish(一對多) 關(guān)聯(lián)屬性publish在Book中 # 查詢書名python的出版社名字(正向查詢) book = Book.objects.filter(title='python').first() # 獲取Book對應(yīng)的對象 print(book.publish.name) # 人民出版社 # 查詢?nèi)嗣癯霭嫔绲某霭娴乃袝?反向查詢) pub_obj = Publish.objects.filter(name="人民出版社").first() # 獲取Publish對應(yīng)的對象 ret = pub_obj.book_set.all() # 獲取對應(yīng)的書籍 print(ret) # <QuerySet [<Book: python>, <Book: java>, <Book: go>, <Book: lua>]>
多對多查詢
''' 多對多: 正向查詢: Book--------------->Author book_obj.authors 反向查詢: Author --------------->Book author_obj.book_set.all() ''' # 查詢書籍python的所有作者名字(正向查詢) book_obj = Book.objects.filter(title="python").first() ret = book_obj.authors.all() print(ret) # <QuerySet [<Author: Tom>, <Author: Jane>]> # 查詢書籍Tom的所有書籍名字(反向查詢) author_obj = Author.objects.filter(name="Tom").first() ret = author_obj.book_set.all() print(ret) # <QuerySet [<Book: java>, <Book: python>]>
一對一查詢
''' 一對一: 因為是一對一關(guān)系 所以查詢結(jié)果是唯一的 正向查詢: Author--------------->Authordetail book_obj.authordetail 反向查詢: Authordetail --------------->Author authordetail_obj.author ''' # 查詢Tom的地址 author_obj = Author.objects.filter(name="Tom").first() print(author_obj.authordetail.addr) # sdfasdf # 查詢郵箱為23145@qq.com的姓名和年齡 authordetail_obj = AuthorDetail.objects.filter(email="23145@qq.com").first() print(authordetail_obj.author.name) # Tone
=========================基于雙下滑線的模糊查詢 ========================
查詢方式:
''' 正向查詢用字段 反向查詢用 "表名小寫__屬性“ 從而告訴ORM引擎 join 哪張表 '''
一對多:
查詢書名為python的出版社名字
''' sql語句查詢: select app01_publish.name from app01_book inner join app01_publish on app01_book.title="python" and app01_book.nid = app01_publish.nid; '''
方式1 通過Book表join與其關(guān)聯(lián)的Publish表,屬于正向查詢;再按照字段 publish 告知ORM join Publish表
ret1 = Book.objects.filter(title="python").values("publish__name") print(ret1) # <QuerySet [{'publish__name': '人民出版社'}]>
方式二:通過Publish表join與其關(guān)聯(lián)的Book表,屬于反向查詢;再按照表名小寫 book__title 告知ORM引擎 join Book表
ret2 = Publish.objects.filter(book__title="python").values("name") print(ret2) # <QuerySet [{'name': '人民出版社'}]>
兩種方式的sql語句:
方式1 打印的sql語句: (0.001) SELECT "app01_publish"."name" FROM "app01_book" INNER JOIN "app01_publish" ON ("app01_book"."publish_id" = "app01_publish"."nid") WHERE "app01_book"."title" = 'python' LIMIT 21; args=('python',) 方式2 打印的sql語句: (0.000) SELECT "app01_publish"."name" FROM "app01_publish" INNER JOIN "app01_book" ON ("app01_publish"."nid" = "app01_book"."publish_id") WHERE "app01_book"."title" = 'python' LIMIT 21; args=('python',)
從sql語句可以看出 ,兩種方式的sql語句都是一樣的 只不過順序顛倒了下
多對多:
現(xiàn)在用雙下劃線查詢上面的例子:
# 查詢書籍python的所有作者名字(正向查詢) # 方式一:通過Book表join與其關(guān)聯(lián)的Author表 屬于正向查詢;再通過字段”authors“告知ORM join Author表 ret = Book.objects.filter(title="python").values("authors__name") print(ret) # <QuerySet [{'authors__name': 'Tom'}, {'authors__name': 'Jane'}]> # 方式二:通過Author表join與其關(guān)聯(lián)的Book表,屬于反向查詢;按表名小寫book告知ORM引擎join book_authors表 ret = Author.objects.filter(book__title="python").values("name") print(ret) # <QuerySet [{'name': 'Tom'}, {'name': 'Jane'}]>
一對一
# 查詢Jane的addr # 方式一:通過Author表join與其關(guān)聯(lián)的Authordetail表 屬于正向查詢;再按照字段authordetail 告知ORM join Authordetail表表 ret = Author.objects.filter(name="Jane").values("authordetail__addr") print(ret) # <QuerySet [{'authordetail__addr': 'gesdf'}]> # 方式一:通過Authordetail表join與其關(guān)聯(lián)的Author表 屬于反向查詢;再按照表明小寫“author 告知ORM join Author表 ret = AuthorDetail.objects.filter(author__name="Jane").values("addr") print(ret) # <QuerySet [{'addr': 'gesdf'}]>
連續(xù)跨表查詢
查詢地址以“h”開頭的所有作者出版的 書籍以及出版社名稱
方式一:
''' 拆分:以作者為根 查詢對應(yīng)的書籍名稱以及其出版社名稱 查詢地址以“h”開頭的所有作者 出版的書籍以及出版社名稱 涉及的表 :Author,AuthorDetail,Book,Publish Author與AuthorDetail有關(guān)聯(lián) 且屬于正向查詢 所以使用字段 authordetail 找出對應(yīng)的作者 --> Author.objects.filter(authordetail__addr__startswith="h") Author與Book有關(guān)聯(lián),且屬于反向查詢,所以使用小寫表名獲取書籍名稱 --> values("book__title") Author和Publish沒有關(guān)聯(lián),所以需要使用連續(xù)跨表查詢 values("book__publish__name") '''
ret = Author.objects.filter(authordetail__addr__startswith="h").values("book__title","book__publish__name") print(ret) # <QuerySet [{'book__title': 'java', 'book__publish__name': '人民出版社'}]>
方式二:
''' 拆分:以書籍為根 查詢關(guān)系:Book --> Author --> AuthorDetail --> Publish 查詢地址以“h”開頭的所有作者出版的書籍 以及出版社名稱 涉及的表 :Author,AuthorDetail,Book,Publish Book與AuthorDetail沒有關(guān)聯(lián) 所以需要使用連續(xù)跨表查詢 --> Book.objects.filter(authors__authordetail__addr__startswith="h") Book與Publish有關(guān)聯(lián),且屬于正向查詢 所以使用字段 publish 獲取出版社名字-> values('title',"publish__name") '''
ret = Book.objects.filter(authors__authordetail__addr__startswith="h").values('title',"publish__name") print(ret) # <QuerySet [{'title': 'java', 'publish__name': '人民出版社'}]>
聚合查詢
aggregate():聚合管理器, 需配合聚合函數(shù)使用 (Avg,Max,Min,Count,..)
注意:aggregate() 返回的是一個字典 不再是Queryset集合
示例:
from django.db.models import Avg,Max,Min,Count # 導(dǎo)入聚合函數(shù) ret = Book.objects.all().aggregate(Avg("price")) print(ret) # {'price__avg': Decimal('3335.5')} price__avg是ORM根據(jù)聚合函數(shù)和屬性以雙下劃線拼成的,也可以自定義鍵名 ret = Book.objects.all().aggregate(avg_price=Avg("price")) print(ret) # {'avg_price': Decimal('3335.5')} ret = Book.objects.all().aggregate(Max("price"),Min("price"),Count("price")) # 獲取最高價格和最低價格 書籍數(shù)量 print(ret) # {'price__max': Decimal('12312'), 'price__min': Decimal('100'), 'price__count': 4}
分組查詢
單表分組查詢:
先創(chuàng)建一個員工表:
class Empers(models.Model): ''' 員工信息詳情表 ''' nid = models.AutoField(primary_key=True) department = models.CharField(max_length=32) name = models.CharField(max_length=32) email = models.EmailField(max_length=32) salary = models.IntegerField() provience = models.CharField(max_length=32)
添加數(shù)據(jù):
Empers.objects.create(name="join",email="sdsfs21@qq.com",salary="5333",department="開發(fā)部",provience="北京") Empers.objects.create(name="tom",email="52342s21@qq.com",salary="5377",department="開發(fā)部",provience="上海") Empers.objects.create(name="jane",email="21321@qq.com",salary="6000",department="銷售部",provience="天津") Empers.objects.create(name="愛爾蘭新",email="efas21@qq.com",salary="12000",department="后勤部",provience="北京")
查詢示例:
# 查詢所有部門及其員工的平均薪資 ret = Empers.objects.values("department").annotate(Avg("salary")) print(ret) # <QuerySet [{'department': '后勤部', 'salary__avg': 12000.0}, {'department': '開發(fā)部', 'salary__avg': 5355.0}, {'department': '銷售部', 'salary__avg': 6000.0}]> # 查詢所有省份及其員工的人數(shù) ret = Empers.objects.values("provience").annotate(Count("name")) print(ret) # <QuerySet [{'provience': '上海', 'name__count': 1}, {'provience': '北京', 'name__count': 2}, {'provience': '天津', 'name__count': 1}]>
總結(jié):
ORM語法:單表模型.objects.values("group by的字段").annotate(聚合函數(shù)(“字段”))
單表模型.objects.values("group by的字段") 相當于 sql語句的:“select * from 表名 group by 字段”
注意:
在單表查詢中annotate是以前面的字段進行分組統(tǒng)計的,如果分組的字段包含主鍵,因為主鍵是唯一的,所以分組就是沒有意義的
多表分組查詢:
示例1:
''' Book 表: nid title pub_date publish_id price 1 python 2018-05-06 1 100 2 java 2018-05-06 1 480 3 go 2018-08-26 1 450 4 lua 2011-02-16 1 12312 Publish 表: nid name city tel email 1 人民出版社 北京 1234456 12156@qq.com 14 海南出版社 海南 1232316 2421356@qq.com 15 天津出版社 天津 2311312 34221356@qq.com # 查詢所有書籍及其出版社的名字 sql語句查詢: select Book.title,Publish.name from Book inner join Publish on Book.publish_id = Publish.nid # 查詢每個出版社的名字及其出版書籍的個數(shù) sql語句查詢: 先join兩張表: select * from app01_book inner join app01_publish on app01_book.publish_id = app01_publish.nid nid title pub_date publish_id price nid name city tel email 1 python 2018-05-06 1 100 1 人民出版社 北京 1234456 12156@qq.com 2 java 2018-05-06 14 480 14 海南出版社 海南 1232316 2421356@qq.com 3 go 2018-08-26 1 450 1 人民出版社 北京 1234456 12156@qq.com 4 lua 2011-02-16 1 12312 1 人民出版社 北京 1234456 12156@qq.com 分組查詢sql語句: select app01_publish.name,Count("title") from app01_book inner join app01_publish on app01_book.publish_id = app01_publish.nid group by app01_publish.nid 結(jié)果: id name Count("title") 1 人民出版社 3 2 海南出版社 1 '''
現(xiàn)在使用ORM語句進行查詢:
# 方式一:通過主鍵進行分組 然后再獲取想要的字段 # ret = Publish.objects.values("nid").annotate(c=Count("book__title")) # print(ret) # <QuerySet [{'nid': 1, 'c': 3}, {'nid': 14, 'c': 1}, {'nid': 15, 'c': 0}]> ret = Publish.objects.values("nid").annotate(c=Count("book__title")).values("name","c") print(ret) # <QuerySet [{'name': '人民出版社', 'c': 3}, {'name': '海南出版社', 'c': 1}, {'name': '天津出版社', 'c': 0}]> # 方式二:直接根據(jù)需分組的字段進行分組 ret = Publish.objects.values("name").annotate(c=Count("book__title")) print(ret) # <QuerySet [{'name': '人民出版社', 'c': 3}, {'name': '天津出版社', 'c': 0}, {'name': '海南出版社', 'c': 1}]>
示例二:查詢每一個作者的名字以及出版過的書籍的最高價格
''' sql語句查詢: select name,Max("app01_book".price) from app01_author inner join app01_authordetail on app01_author.authordetail_id = app01_authordetail.nid inner join app01_book on app01_author.nid = app01_book.nid group by app01_author.name ''' ret = Author.objects.values("pk").annotate(max_price=Max("book__price")).values("name","max_price") print(ret) # <QuerySet [{'name': 'Tom', 'max_price': Decimal('480')}, {'name': 'Jane', 'max_price': Decimal('480')}, {'name': 'Tone', 'max_price': Decimal('480')}, {'name': 'Jin', 'max_price': Decimal('480')}]> # 等同于下面語句 ret = Author.objects.all().annotate(max_price=Max("book__price")).values("name","max_price") print(ret) # <QuerySet [{'name': 'Tom', 'max_price': Decimal('480')}, {'name': 'Jane', 'max_price': Decimal('480')}, {'name': 'Tone', 'max_price': Decimal('480')}, {'name': 'Jin', 'max_price': Decimal('480')}]> ret = Author.objects.annotate(max_price=Max("book__price")).values("name","max_price") print(ret) # <QuerySet [{'name': 'Tom', 'max_price': Decimal('480')}, {'name': 'Jane', 'max_price': Decimal('480')}, {'name': 'Tone', 'max_price': Decimal('480')}, {'name': 'Jin', 'max_price': Decimal('480')}]>
總結(jié):
多表分組模型:
模型一:
Author.objects.values("pk"). annotate(max_price=Max("book__price")). values("name","max_price") 關(guān)鍵字“每一個”后的表.objects.values("分組字段").annotate.(聚合函數(shù)("關(guān)聯(lián)表__統(tǒng)計字段")).values("需要展示的字段")
模型二:
Author.objects.all(). annotate(max_price=Max("book__price")).values("name","max_price")
關(guān)鍵字“每一個”后的表.objects.all().annotate.(聚合函數(shù)("關(guān)聯(lián)表__統(tǒng)計字段")).values("需要展示的字段")
注意:all()可加可不加,結(jié)果都是一樣的 不同之處在于下面的寫法 values(“”)中的字段可以取根表的所有字段以及統(tǒng)計的字段
解析:以 關(guān)鍵字“每一個”后的表 為根,通過values()進行分組;
然后通過分組管理器(annotate)配合聚合函數(shù)獲取“關(guān)聯(lián)表的統(tǒng)計字段”的數(shù)據(jù)
最后使用values("字段")獲取需要的字段數(shù)據(jù)
extra方法:
在Django中,有些時間查詢語句是ORM無法完成轉(zhuǎn)換的,就像獲取在datatime中的年月日,直接從數(shù)據(jù)庫是無法查詢的,我們可以個extra方法
格式: extra(select = {"自定義字段":“date_format(‘時間字段’,'%%Y-%%m-%%d')”}):
extra是將Queryset對象增加 一個自定義的字段,返回的結(jié)果還是Queryset對象。
date_list = Article.objects.filter(user=user).extra(select={"y_m_date":"date_format(create_time,'%%Y/%%m/%%d')"}).values("y_m_date").annotate(c=Count("nid")).values_list("y_m_date","c")
print(date_list)
#結(jié)果
<QuerySet [('2020/03/23', 1)]>
TruncMonth方法
除了extra方法之外,Django還給我們封裝了一個”TruncMonth “方法
from django.db.models.functions import TruncMonth

在上圖中, TruncMont把“timestamp”進行截取,只截取到月份,然后賦值給month,原理和extra一樣,也是增加了一個鍵值對,返回的也是Queryset對象
ret = models.Article.objects.filter(user=user).annotate(month=TruncMonth("create_time")).values("month").annotate( c=Count("nid")).values_list("month", "c") print("ret----->",ret) # 結(jié)果 <QuerySet [(datetime.datetime(2020, 3, 1, 0, 0), 1)]>
===================== F與Q查詢 ==================
F查詢:
# 查詢評論數(shù)大于閱讀數(shù)的書籍 ret = Book.objects.all().filter(comment_num__gt=F("read_num")) print(ret) # <QuerySet [<Book: python>, <Book: go>]> # 將所有書籍的價格增加20 ret = Book.objects.update(price=F("price")+20)
Q查詢:
Q有三種關(guān)聯(lián)方式:且、或、非
且:和符號 “ & 匹配使用,用戶連接多個參數(shù)
或:和符號 ”|“ 匹配使用,用于選擇多個條件中的一個
非:和符號”~“ 匹配使用,用戶否定某條件,后面必須跟 ”|“符號
示例:
from django.db.models import Q # 查詢書名為python 且 價格為120的書籍 python 120 #方式一:正常寫法 ret = Book.objects.filter(title="python",price=220).values("title","price") print(ret) # <QuerySet [{'title': 'python', 'price': Decimal('220.00')}]>
# 方式二:使用 Q ret = Book.objects.filter(Q(title="python") & Q(price=220)).values("title","price") print(ret) # <QuerySet [{'title': 'python', 'price': Decimal('220.00')}]> # 查詢書名為python 或者 價格為120的書籍 ret = Book.objects.filter(Q(title="python") | Q(price=120)).values("title","price") print(ret) # <QuerySet [{'title': 'python', 'price': Decimal('220.00')}]> # 查詢書名非python 或者 價格為120的書籍 ret = Book.objects.filter(~Q(title="python") | Q(price=120)).values("title","price") print(ret) # <QuerySet [{'title': 'java', 'price': Decimal('600.00')}, {'title': 'go', 'price': Decimal('220.00')}, # {'title': 'lua', 'price': Decimal('12432.00')}]>

浙公網(wǎng)安備 33010602011771號