9,Django-13條基礎-單表查詢-外鍵-多對多-聚合和分組查詢-F-Q-事物

/ORM操做13條基礎-單表查詢-外鍵-多對多-聚合和分組查詢-F-Q-事物html

 

day74
1. 內容回顧
    1. ORM 
        1. 13條
            1. 返回queryset的
                all()
                filter()
                exclude()
                order_by()
                reverse()
                distinct()
                values()
                values_list()
            2. 返回對象的
                get()
                first()
                last()
            3. 返回布爾值
                exists()
            4. 返回數字
                count()
        2. django使用mysql數據庫的步驟
            1. 建立一個mysql數據庫
            2. 配置
                DATABASES = {
                    'default': {
                        'ENGINE': 'django.db.backends.mysql',
                        'NAME': 'orm_homework',
                        'USER': 'root',
                        'PASSWORD': '',
                        'HOST': '127.0.0.1',
                        'PORT': 3306,
                    }
                }
            3. 告訴django使用pymysql鏈接你的mysql數據庫(mysqldb)
                在與settings同級目錄下的__init__.py中寫
                import pymysql
                pymysql.install_as_MySQLdb()
            4. 在APP下的models.py中寫類(繼承Model)
                
            5. 執行數據庫遷移的命令
                python manage.py makemigrations # 記錄models的變動記錄
                python manage.py migrate        # 將變動記錄同步到數據庫中
            
        
        2. 週末做業
            見代碼
        3. OneToOneField(to='關聯的表')  (一對一)
            在ForeignKey基礎上加一個約束  unique=true

            1. 全部的內容能夠寫在一個表中
            2. 有的字段不常查,但有的字段查的很頻繁
        4. 外鍵ForeignKey
            book_obj.publisher       ——》 關聯的出版社對象
            book_obj.publisher_id   
            
            反向查詢:
                不指定related_name
                pub_obj.book_set    ——》關係管理對象
                指定related_name='books'
                pub_obj.books    ——》關係管理對象
        5. 多對多ManyToManyField
            book_obj.author
            多對多的方法:
                create()
                add()
                remove()
                set()
                clear()
        6. 單表的增刪改查
            create
            delete
            update()
            .屬性 = ''
            save()
        7. 進階
            1. 聚合和分組
                aggregate   終止子句
                annotate   
            2. F 和 Q
            
                ~取反
                & and
                |3. 事務 
                
2. 今日內容
    0. 登陸的實例
    
    
    1. cookie
        1. cookie是什麼?
            cookie是保存在瀏覽器上一組組鍵值對
            
        2. 特性:
            1. 是服務器讓瀏覽器設置的。瀏覽器有權利不設置。
            2. 訪問其餘頁面的時候攜帶着cookie。
        
        2. 能幹什麼?
            1. 作登陸
    
    
    
    2. session
        1. 保存在服務器上的鍵值對
        2. 一個cookie對應一個session
        流程:
            1. 給首次登陸的用戶設置一個cookie  session:asdasdasasdasdas
            2. 開闢一塊空間存session
            3. session中存要存的數據(鍵值對)
            4. 返回給瀏覽器cookie
            
        # 設置session
        request.session['is_login'] = 'True'
        # 獲取session
        request.session.get('is_login', '')
            
            
            
        
            
        
            
                
                
                
                
筆記

 

 

https://www.cnblogs.com/maple-shaw/articles/9403501.htmlpython

https://www.cnblogs.com/maple-shaw/articles/9323320.htmlmysql

https://www.cnblogs.com/maple-shaw/articles/9414626.html -練習題git

# 查找全部書名裏包含金老闆的書
    # ret=models.Book.objects.filter(title__icontains='金老闆').values_list('title')
    # print(ret)

    # 查找出版日期是2018年的書
    # ret=models.Book.objects.filter(publisher_date__year=2018).values_list('title','publisher_date')
    # print(ret)

    # 查找出版日期是2017年的書名
    # ret=models.Book.objects.filter(publisher_date__year=2017).values_list('title','publisher_date')
    # print(ret)


    # 查找價格大於10元的書
    # ret=models.Book.objects.filter(price__gt=10).values_list('title')
    # print(ret)

    # 查找價格大於10元的書名和價格
    # ret = models.Book.objects.filter(price__gt=10).values_list('title', 'price')
    # print(ret)

    # 查找memo字段是空的書
    # ret=models.Book.objects.filter(memo__isnull=True)
    # print(ret)


    # 查找在北京的出版社
    # ret=models.Publisher.objects.filter(city__icontains='北京').values_list('name','city')
    # print(ret)


    # 查找名字以沙河開頭的出版社
    # ret = models.Publisher.objects.filter(name__startswith='沙河').values_list('name', 'city')
    # print(ret)





    ############----------------重點-------------------------####################

    # 查找「沙河出版社」出版的全部書籍
    # ret=models.Book.objects.filter(publisher__name='沙河出版社').values_list('publisher__name','title')
    # print(ret)


    # 查找每一個出版社出版價格最高的書籍價格
    # ret=models.Publisher.objects.annotate(max=Max('books__price')).values_list('name','books__title','max')
    # print(ret)

    # ret=models.Book.objects.filter(publisher__name='沙河出版社')
    # print(ret)

    # ret=models.Publisher.objects.filter(books__title='跟金老闆學開車')
    # print(ret)

    # 查找每一個出版社的名字以及出的書籍數量
    # ret=models.Publisher.objects.annotate(num=Count('books')).values_list('name','num')
    # print(ret)


    # 查找做者名字裏面帶「小」字的做者
    # ret=models.Author.objects.filter(name__contains='小').values_list('name')
    # print(ret)
    # ret=models.Author.objects.all().values_list('name')
    # print(ret)

    # 查找年齡大於30歲的做者
    # ret=models.Author.objects.filter(age__gt=30).values_list('name','age','authors__title')
    # print(ret)

    # 查找手機號是155開頭的做者
    # ret=models.Author.objects.filter(phone__startswith=155).values_list('name','phone')
    # print(ret)
    # ret=models.Author.objects.all().values_list('phone')
    # print(ret)

    # 查找手機號是155開頭的做者的姓名和年齡
    # ret=models.Author.objects.filter(phone__startswith=155).values_list('name','age')
    # print(ret)


    # 查找每一個做者寫的價格最高的書籍價格
    # ret=models.Author.objects.annotate(max=Max('authors__price')).values_list('name','authors__price')
    # print(ret)

    # 查找每一個做者的姓名以及出的書籍數量
    # ret=models.Author.objects.all().annotate(num=Count('authors')).values_list('name','num')
    # print(ret)




    # 查找書名是「跟金老闆學開車」的書的出版社
    # book_obj=models.Book.objects.filter(title='跟金老闆學開車')
    # ret=book_obj.publisher
    # print(ret)


    # 查找書名是「跟金老闆學開車」的書的出版社所在的城市

    # book_obj=models.Book.objects.get(title='跟金老闆學開車')
    # ret=book_obj.publisher.city
    # print(ret)

    # 查找書名是「跟金老闆學開車」的書的出版社的名稱
    # book_obj=models.Book.objects.filter(title='跟金老闆學開車')
    # ret=book_obj.publisher.name
    # print(ret)

    # 查找書名是「跟金老闆學開車」的書的出版社出版的其餘書籍的名字和價格
    # book_obj=models.Book.objects.get(title='跟金老闆學開車')
    # ret=book_obj.publisher.books.exclude(title='跟金老闆學開車').values_list('title','price')
    # print(ret)

    # ret=models.Publisher.objects.get(books__title='跟金老闆學開車').books.exclude(title='跟金老闆學開車').values_list('title','price')
    # print(ret)

    # obj=models.Publisher.objects.get(book__title='跟金老闆學開車').book_set.exclude(title='跟金老闆學開車').values_list('title','price')
    # ret=obj.book_set.all()
    # print(obj)

    # 查找書名是「跟金老闆學開車」的書的全部做者

    # ret=models.Book.objects.get(title='跟金老闆學開車').author.all()
    # print(ret)

    # 查找書名是「跟金老闆學開車」的書的做者的年齡
    # ret=models.Book.objects.get(title='跟金老闆學開車').author.all().values_list('age','name')
    # print(ret)


    # 查找書名是「跟金老闆學開車」的書的做者的手機號碼
    # ret=models.Book.objects.get(title='跟金老闆學開車').author.all().values_list('phone','name')
    # print(ret)

    # 查找書名是「跟金老闆學開車」的書的做者們的姓名以及出版的全部書籍名稱和價錢
    # book_obj = models.Book.objects.get(title='跟金老闆學開車')
    # ret=book_obj.author.all()
    # for aut in ret:
    #     print(aut)
    #     ret=aut.authors.all().values_list('title','price')
    #     print(ret)

    # ret=models.Author.objects.filter(authors__title='跟金老闆學開車').values('name','authors__title','authors__price')
    # print(ret)
練習題答案-本身作的

 

sql

 

/數據庫

 

/django

 

/瀏覽器

 

QuerySet API reference

https://docs.djangoproject.com/en/1.11/ref/models/querysets/服務器

 

/cookie

 

/

 

/

 

 

 /

先創建項目,各項配置,鏈接數據庫,操做的是出版社,書籍,做者,存在外鍵,多對多關係

 

在Python腳本中調用Django環境

import os

if __name__ == '__main__':
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "BMS.settings")
#上面的代碼,在manage.py文件裏也有,能夠考慮複製過來

   #引入django import django django.setup()   
  #引入models
from app01 import models books = models.Book.objects.all() print(books)

 

注意:

1,在項目下建一個文件夾,而後建一個py文件,把上面代碼粘貼進去,

2,寫好語句後, 右鍵執行便可,不用在啓動django項目,直接看結果,

 

示例代碼:

import os

if __name__ == '__main__':
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "orm_practice.settings")


    import django
    django.setup()

    from app01 import models
    ret = models.Person.objects.all()
    print(ret[0],'**',type(ret),'**',type(ret[0]))

輸出結果

ret=models.Person.objects.all()
#類型是類,QuerySet對象
type(ret)---><class 'django.db.models.query.QuerySet'>
    
ret[0]
Person object    

type(ret[0])
<class 'app01.models.Person'>

 /

 

 

 /

order_by的默認排序, ordering=('id','age'),ID同樣,再按age進行排序,

class Person(models.Model):
    id=models.AutoField(primary_key=True)
    name=models.CharField(max_length=32)
    age=models.IntegerField()
    birth=models.DateField()

    def __str__(self):
        return "<Person obj:{} {}>".format(self.id,self.name)
    
    # 加上這個以後,默認取出來就是已經排序的
    class Meta:
        #後面要寫元組,
        ordering=('id')
默認取出來已經排序了,

下面再寫的取出來就是倒序了

ret=models.Person.objects.all().reverse()

也能夠這樣寫,

models.Person.objects.all().order_by('id').reverse()

 

具體演示代碼

import os

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

    from app01 import models


    # all  獲取全部對象   ——》 QuerySet
    ret = models.Person.objects.all()

    # get  獲取單獨的對象  ——》 對象
    # 找不到或者找到多個就報錯
    ret= models.Person.objects.get(id=1,name='阿旭')

    # filter 過濾 獲取全部知足條件的對象   ——》QuerySet
    ret = models.Person.objects.filter(id=1)

    # exclude  獲取不知足條件的全部對象
    ret = models.Person.objects.exclude(id=1)

    # values   ——》QuerySet  元素是字典
    # 不寫參數   默認全部字段的名字和值
    # 寫參數     拿到指定字段的名字和值
    ret = models.Person.objects.all().values('id','name')
    ret = models.Person.objects.values('id','name')
    # values_list   ——》QuerySet  元素是元組  只有值沒有字段名
    # 不寫參數   默認全部字段值
    # 寫參數     拿到指定字段值
    ret = models.Person.objects.values_list('name','id')
    # print(ret)

    # for i in ret :
    #     print(i,type(i))
    #  reverse 對已經排序的QuerySet進行反轉
    ret = models.Person.objects.all().reverse()


    # distinct 去重  ——》QuerySet


    # count 對QuerySet中的元素進行計數
    ret = models.Person.objects.filter(id=100).count()


    # first  取QuerySet中的第一個元素
    ret = models.Person.objects.all().first()

    # last  取QuerySet中的最後一個元素
    ret = models.Person.objects.all().last()
    ret = models.Person.objects.values_list().last()

    ret = models.Person.objects.filter(id=100).first()

    # exists 判斷查詢結果是否有值
    ret = models.Person.objects.filter(id=100).exists()
    # print(ret)

    # order_by 按字段進行排序 ——》QuerySet
    ret =models.Person.objects.order_by('age')
    print(ret)
具體演示代碼+註釋

 /

 

/

返回QuerySet對象的方法有:

all(),

filter(),

exclude(),

order_by(), 裏面能夠放多個參數

reverse(),對已經排序的進行翻轉

distinct(),去重

 

特殊的QuerySet

values()       返回一個可迭代的字典序列,裏面能夠放參數,放了參數就是僅顯示參數的內容,

values_list() 返回一個可迭代的元祖序列, 也能夠放參數,

 

返回具體對象的

get(), 取不到或者取到多個會報錯

first(), 取不到是Null

last().

 

返回布爾值的方法有:

exists()

返回數字的方法有:

count()

 

單表查詢的下劃線

id__lt,id__gt,id__in,id__range=[]是列表
name__contains='str'
name__icontains='str'
name__startswith='xx'
name__endswith='xx'
name__iendswith='xx'
birth__year

 


eq 就是 EQUAL等於 ne 就是 NOT EQUAL不等於 gt 就是 GREATER THAN大於  lt 就是 LESS THAN小於 gte 就是 GREATER THAN OR EQUAL 大於等於 lte 就是 LESS THAN OR EQUAL 小於等於

 

 

import os

if __name__ == '__main__':
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "orm_practice.settings")


    import django
    django.setup()

    from app01 import models
    ret = models.Person.objects.all()

    #小於10的,less than
    ret=models.Person.objects.filter(id__lt=10)

    #大於1的,great than
    ret=models.Person.objects.filter(id__gt=3)
    #大於等於3的,
    ret=models.Person.objects.filter(id__gt=3)
    #大於3小於5的,
    ret=models.Person.objects.filter(id__gt=3,id__lt=5)
    #取反,拿出小於等於3的,
    ret=models.Person.objects.exclude(id__gt=3)
    #還能夠設置範圍,還能夠換成exclude
    ret=models.Person.objects.filter(id__in=[1,3,5])
    #使用range,1和5都能取到,
    ret=models.Person.objects.filter(id__range=[1,5])
    #查選包含特定字符的,
    ret=models.Person.objects.filter(name__contains='')
    #注意加了一個i,是不區分大小寫的意思,
    ret=models.Person.objects.filter(name__icontains='')

    #表示以哪一個字符爲開頭
    ret=models.Person.objects.filter(name__startswith='')
    #以什麼結尾,
    ret=models.Person.objects.filter(name__endswith='')
    #加了一個i,不區分大小寫,
    ret=models.Person.objects.filter(name__iendswith='')
    
    #查找日期符合條件的,
    ret=models.Person.objects.filter(birth__year='2018')
    ret=models.Person.objects.filter(birth__month='09')
    ret=models.Person.objects.filter(birth__year='2018',birth__month='09')

    print(ret)
示例代碼

 

 

ForeignKey

Django終端打印SQL語句

在Django項目的settings.py文件中在最後複製粘貼以下代碼:

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console':{
            'level':'DEBUG',
            'class':'logging.StreamHandler',
        },
    },
    'loggers': {
        'django.db.backends': {
            'handlers': ['console'],
            'propagate': True,
            'level':'DEBUG',
        },
    }
}
打印SQL語句

 

即爲你的Django項目配置上一個名爲django.db.backends的logger實例便可查看翻譯後的SQL語句。

 

 

 

正向查詢

/

 

/

外鍵設置在書籍,經過book查詢publisher,稱之爲正向查詢,反過來就是反向查詢,

 

#book_obj.publishr是直接拿到了publisher對象了,關聯的出版社對象,
print(book_obj.publisher,type(book_obj.publisher))

輸出:Publisher object <class 'app01.models.Publisher'>

#區分兩者的sql語句條數
print(book_obj.publisher_id)
print(book_obj.publisher.id)

 

對象查找(跨表)

語法:

對象.關聯字段.字段

book_obj = models.Book.objects.first()  # 第一本書對象
print(book_obj.publisher)  # 獲得這本書關聯的出版社對象
print(book_obj.publisher.name)  # 獲得出版社對象的名稱

 

字段查找

models.Book.objects.filter(publisher__name='新華出版社')  #查出 出版社='新華出版社' 出版的全部書,

 

 

反向查找

此處就是publisher查找book

/

 

 

對象查找

語法:

obj.表名_set

 

拿到關聯對象

publisher_obj = models.Publisher.objects.first()  # 找到第一個出版社對象

books = publisher_obj.book_set.all() # 找到第一個出版社出版的全部書

titles = books.values_list("title") # 找到第一個出版社出版的全部書的書名

 

 

示例代碼1

import os

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

    django.setup()

    from app01 import models
    # 正向查詢   book ——》 publisher
    # 基於對象查詢
    # book_obj = models.Book.objects.get(id=1)
    # print(book_obj.id)
    # print(book_obj.title)
    # print(book_obj.publisher_id)
    # print(book_obj.publisher_id)  # 關聯的出版社對象
    # print(book_obj.publisher.id)  # 關聯的出版社對象
    # print(book_obj.publisher.name)

    # 基於字段查詢
    # ret= models.Book.objects.filter(publisher__name='沙河出版社')
    # ret= models.Book.objects.filter(publisher_id=1)
    # print(ret)


    # 反向查詢   publisher ——》 book
    # 基於對象的查詢
    # 一 —— 》 多    表名小寫_set ——》 管理對象   .all()  出版社關聯的全部書籍對象
    pub_obj = models.Publisher.objects.first()

    # 表名小寫_set
    # print(pub_obj)
    # ret = pub_obj.book_set.all()
    # print(pub_obj.book_set,type(pub_obj.book_set))
    # print(ret)

    # 指定了related_name  books
    # print(pub_obj.books.all())

    # 基於字段的查詢
    ret = models.Publisher.objects.filter(xx__title='跟太亮學開車')
    print(ret)
練習代碼

 

關於查找時,能夠簡化的寫法,

注意:

在models裏面須要對應設置,注意related_name的添加,  也是反向查詢用的,

class Book(models.Model):
    title=models.CharField(max_length=32)
    #下面一行是要關聯的外鍵
    publisher=models.ForeignKey('Publisher',related_name='books',on_delete=models.CASCADE)

 

 

 

 

字段查詢

ret=models.Publisher.objects.filter(books__title='這就是書名')  #此處的books__title books是related_name
#若是下面圖片的related_query_name='xx',寫了,上面的books__title就要換成:xx__title,

與圖片的關係

 

create

pub_obj=models.Publisher.objects.first()
pub_obj.books.create(title='跟老男孩學思想')

 /

 

 

 /

 

ManyToManyField,多對多的管理

class RelatedManager

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

它存在於下面兩種狀況:

  1. 外鍵關係的反向查詢
  2. 多對多關聯關係

簡單來講就是當 點後面的對象 可能存在多個的時候就可使用如下的方法。

 

拿到管理對象,

    author_obj=models.Author.objects.get(id=1)
    # books就是設置的那個多對多,books=models.ManyToManyField('Book')
    print(author_obj.books,type(author_obj.books))
    #拿到管理對象,
    # 輸出:app01.Book.None <class 'django.db.models.fields.related_descriptors
    print(author_obj.books.all())
    #拿到QuerySet
    #輸出:<QuerySet [<Book: <Person obj:5 跟太亮學開車>>, <Book: <Person obj:6 跟太白學燙頭>>]>

 

方法

create

#create

    # 1,建立書籍對象(與出版社進行關聯)
    # 2,該對象和做者
    author_obj = models.Author.objects.get(id=1)

  
  此處的books就是以前的->
books=models.ManyToManyField('Book')
    author_obj.books.create(title='XX與嫂子的故事',publisher_id=1)

 /

 

/

 

/

add:把指定的model對象添加到關聯對象集中。

add()括號裏面能夠放一個或多個數據, 能夠放id,還能夠放對象,

#給做者添加書籍,
    author_obj = models.Author.objects.get(id=1)
    #能夠添加一個或多個,add()
    # author_obj.books.add(9)
    author_obj.books.add(5,6,8,9)

區分與set的不一樣
author_obj.books.set([1,6,8,9]) 

 

另外一種添加方式

   author_obj=models.Author.objects.get(id=1)
    # 獲取指定id的書籍
    books=models.Book.objects.filter(id__in=[1,6,8,9])
    #須要打散才能進行傳參
    author_obj.books.add(*books)

 

 

set:更新model對象的關聯對象。

與add對比使用,add是添加的一個id,或者一個對象,

set能夠添加列表,或者queryset集合,

    author_obj=models.Author.objects.get(id=1)
    books=models.Book.objects.filter(id__in=[1,6,8,9])

    # 下面兩行的代碼是等價的,
    # author_obj.books.set([1,6,8,9])
    author_obj.books.set(books)

 

 

/

 

/

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

author_obj=models.Author.objects.get(id=1)
books=models.Book.objects.filter(id__in=[1,6,8,9])
# remove
能夠移除一個或多個
author_obj.books.remove(1)
author_obj.books.remove(6,8,9)

# 能夠移除對象
author_obj.books.remove(*books)

 

clear()

從關聯對象集中移除一切對象。

author_obj=models.Author.objects.get(id=1)

#把跟這個做者關聯的書,都清空掉,
author_obj.books.clear()

 

 

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

設置null=True

就是刪除出版社跟書的對應關係時,外鍵沒有了,往數據庫寫的時候,寫不進去,須要設置null=True才能寫進去,

在models裏設置Book類,而後執行兩條命令.

 

注意:

  1. 對於全部類型的關聯字段,add()、create()、remove()和clear(),set()都會立刻更新數據庫。換句話說,在關聯的任何一端,都不須要再調用save()方法。

設置null=True

publisher=models.ForeignKey('Publisher',related_name='books',on_delete=models.CASCADE,null=True)

 

設置null=True以後,示例代碼

   pub_obj=models.Publisher.objects.get(id=1)

    #一對多的管理對象remove不能使用id,使用對象
    # pub_obj.books.remove(models.Book.objects.get(id=5))

    #清空這個出版社下全部關聯的書,
    pub_obj.books.clear()

 /

 

/

 

聚合查詢和分組查詢

 

models裏面,Book類添加包含小數的字段

price=models.DecimalField(max_digits=5,decimal_places=2)

 

聚合

1,aggregate的使用,觀察輸出結果,

ret=models.Book.objects.all().aggregate(Avg('price'))
print(ret,type(ret))
# 輸出:{'price__avg': 50.0} <class 'dict'>

還能夠更名字
ret=models.Book.objects.all().aggregate(make_name=Avg('price'))
print(ret,type(ret))
# {'make_name': 50.0} <class 'dict'>

還能夠多放參數
ret=models.Book.objects.all().aggregate(Avg('price'),Max('price'))


 

2,能夠更名字,還能夠多放參數,

/

 

/

 

分組

1,統計每本書的做者個數

# 統計每本書的做者個數
    #.all能夠省略不寫,
    # ret=models.Book.objects.all().annotate(Count('author'))
    ret=models.Book.objects.annotate(Count('author'))
    for i in ret.values():
        print(i)

 

輸出結果

'''輸出:
        {'id': 1, 'title': '宮保雞丁指南', 'publisher_id': 1, 'price': Decimal('10.00'), 'author__count': 1}
{'id': 2, 'title': '包子真貴', 'publisher_id': 4, 'price': Decimal('20.00'), 'author__count': 1}
{'id': 3, 'title': '陶馨園真便宜', 'publisher_id': 5, 'price': Decimal('30.00'), 'author__count': 1}
{'id': 4, 'title': '護國寺豆汁真騷', 'publisher_id': 3, 'price': Decimal('40.00'), 'author__count': 0}
{'id': 5, 'title': '跟太亮學開車', 'publisher_id': 1, 'price': Decimal('50.00'), 'author__count': 1}
{'id': 6, 'title': '跟太白學燙頭', 'publisher_id': 1, 'price': Decimal('60.00'), 'author__count': 1}
{'id': 7, 'title': '新華字典', 'publisher_id': 2, 'price': Decimal('70.00'), 'author__count': 1}
{'id': 8, 'title': '戴綠與嫂子的故事', 'publisher_id': 1, 'price': Decimal('80.00'), 'author__count': 0}
{'id': 9, 'title': '跟老男孩學思想', 'publisher_id': 1, 'price': Decimal('90.00'), 'author__count': 0}
    '''
輸出結果

 

2,統計每一個出版社最便宜的書,

ret=models.Publisher.objects.annotate(Min('books__price')).values()
    for i in ret.values():
        print(i)

 

3,統計不止一個做者的圖書,

#統計不止一個做者的圖書,
    ret=models.Book.objects.annotate(count=Count('author')).filter(count__gt=1)
    print(ret)
 

4,查詢做者出的書的總價格

# 查詢做者出的書的總價格
    ret=models.Author.objects.annotate(sum=Sum('books__price')).values()
    print(ret)

 

 

F查詢個Q查詢

 

先進行導入

from django.db.models import F

 

示例代碼

# F查詢
    from django.db.models import F
    # ret=models.Book.objects.filter(sale__gt=50).values()
    #F查詢,直接查出sale大於kucun的,
    ret=models.Book.objects.filter(sale__gt=F('kucun')).values()
    #還能夠加減數值
    ret=models.Book.objects.filter(sale__gt=F('kucun')+30).values()
    print(ret)

 

對數據的修改:update與save的區別,save的效率要慢,

#對數據的修改,
    models.Book.objects.all().update(sale=100)

    #區分update與save的差異,

    book_obj=models.Book.objects.get(id=1)
    book_obj.sale=0
    book_obj.save()
    

 

Q查詢

filter() 等方法中的關鍵字參數查詢都是一塊兒進行「AND」 的。

 若是你須要執行更復雜的查詢(例如OR語句),你可使用Q對象

先進行導入

from django.db.models import Q

 

ret=models.Book.objects.filter(Q(id__lt=3)|Q(id__gt=5))
    # print(ret)
    for i in ret:
        print(i)

    ret = models.Book.objects.filter(Q(id__gt=3)&Q(id__lt=9))
    # print(ret)
    for i in ret:
        print(i)

 

還能夠進行取反

ret=models.Book.objects.filter(~Q(id__lt=3)|Q(id__gt=5))
    # print(ret)
    for i in ret:
        print(i)

 

/

事物:要成功都成功,要失敗都失敗,

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))
View Code

 

 

 

Django ORM執行原生SQL

# extra
# 在QuerySet的基礎上繼續執行子語句
# extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None)

# select和select_params是一組,where和params是一組,tables用來設置from哪一個表
# Entry.objects.extra(select={'new_id': "select col from sometable where othercol > %s"}, select_params=(1,))
# Entry.objects.extra(where=['headline=%s'], params=['Lennon'])
# Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"])
# Entry.objects.extra(select={'new_id': "select id from tb where id > %s"}, select_params=(1,), order_by=['-nid'])

舉個例子:
models.UserInfo.objects.extra(
                    select={'newid':'select count(1) from app01_usertype where id>%s'},
                    select_params=[1,],
                    where = ['age>%s'],
                    params=[18,],
                    order_by=['-age'],
                    tables=['app01_usertype']
                )
                """
                select 
                    app01_userinfo.id,
                    (select count(1) from app01_usertype where id>1) as newid
                from app01_userinfo,app01_usertype
                where 
                    app01_userinfo.age > 18
                order by 
                    app01_userinfo.age desc
                """


# 執行原生SQL
# 更高靈活度的方式執行原生SQL語句
# from django.db import connection, connections
# cursor = connection.cursor()  # cursor = connections['default'].cursor()
# cursor.execute("""SELECT * from auth_user where id = %s""", [1])
# row = cursor.fetchone()


ORM 執行原生SQL的方法
View Code

 

 

QuerySet方法大全

##################################################################
# PUBLIC METHODS THAT ALTER ATTRIBUTES AND RETURN A NEW QUERYSET #
##################################################################

def all(self)
    # 獲取全部的數據對象

def filter(self, *args, **kwargs)
    # 條件查詢
    # 條件能夠是:參數,字典,Q

def exclude(self, *args, **kwargs)
    # 條件查詢
    # 條件能夠是:參數,字典,Q

def select_related(self, *fields)
    性能相關:表之間進行join連表操做,一次性獲取關聯的數據。

    總結:
    1. select_related主要針一對一和多對一關係進行優化。
    2. select_related使用SQL的JOIN語句進行優化,經過減小SQL查詢的次數來進行優化、提升性能。

def prefetch_related(self, *lookups)
    性能相關:多表連表操做時速度會慢,使用其執行屢次SQL查詢在Python代碼中實現連表操做。

    總結:
    1. 對於多對多字段(ManyToManyField)和一對多字段,可使用prefetch_related()來進行優化。
    2. prefetch_related()的優化方式是分別查詢每一個表,而後用Python處理他們之間的關係。

def annotate(self, *args, **kwargs)
    # 用於實現聚合group by查詢

    from django.db.models import Count, Avg, Max, Min, Sum

    v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id'))
    # SELECT u_id, COUNT(ui) AS `uid` FROM UserInfo GROUP BY u_id

    v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id')).filter(uid__gt=1)
    # SELECT u_id, COUNT(ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) > 1

    v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id',distinct=True)).filter(uid__gt=1)
    # SELECT u_id, COUNT( DISTINCT ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) > 1

def distinct(self, *field_names)
    # 用於distinct去重
    models.UserInfo.objects.values('nid').distinct()
    # select distinct nid from userinfo

    注:只有在PostgreSQL中才能使用distinct進行去重

def order_by(self, *field_names)
    # 用於排序
    models.UserInfo.objects.all().order_by('-id','age')

def extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None)
    # 構造額外的查詢條件或者映射,如:子查詢

    Entry.objects.extra(select={'new_id': "select col from sometable where othercol > %s"}, select_params=(1,))
    Entry.objects.extra(where=['headline=%s'], params=['Lennon'])
    Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"])
    Entry.objects.extra(select={'new_id': "select id from tb where id > %s"}, select_params=(1,), order_by=['-nid'])

 def reverse(self):
    # 倒序
    models.UserInfo.objects.all().order_by('-nid').reverse()
    # 注:若是存在order_by,reverse則是倒序,若是多個排序則一一倒序


 def defer(self, *fields):
    models.UserInfo.objects.defer('username','id')
    或
    models.UserInfo.objects.filter(...).defer('username','id')
    #映射中排除某列數據

 def only(self, *fields):
    #僅取某個表中的數據
     models.UserInfo.objects.only('username','id')
     或
     models.UserInfo.objects.filter(...).only('username','id')

 def using(self, alias):
     指定使用的數據庫,參數爲別名(setting中的設置)


##################################################
# PUBLIC METHODS THAT RETURN A QUERYSET SUBCLASS #
##################################################

def raw(self, raw_query, params=None, translations=None, using=None):
    # 執行原生SQL
    models.UserInfo.objects.raw('select * from userinfo')

    # 若是SQL是其餘表時,必須將名字設置爲當前UserInfo對象的主鍵列名
    models.UserInfo.objects.raw('select id as nid from 其餘表')

    # 爲原生SQL設置參數
    models.UserInfo.objects.raw('select id as nid from userinfo where nid>%s', params=[12,])

    # 將獲取的到列名轉換爲指定列名
    name_map = {'first': 'first_name', 'last': 'last_name', 'bd': 'birth_date', 'pk': 'id'}
    Person.objects.raw('SELECT * FROM some_other_table', translations=name_map)

    # 指定數據庫
    models.UserInfo.objects.raw('select * from userinfo', using="default")

    ################### 原生SQL ###################
    from django.db import connection, connections
    cursor = connection.cursor()  # cursor = connections['default'].cursor()
    cursor.execute("""SELECT * from auth_user where id = %s""", [1])
    row = cursor.fetchone() # fetchall()/fetchmany(..)


def values(self, *fields):
    # 獲取每行數據爲字典格式

def values_list(self, *fields, **kwargs):
    # 獲取每行數據爲元祖

def dates(self, field_name, kind, order='ASC'):
    # 根據時間進行某一部分進行去重查找並截取指定內容
    # kind只能是:"year"(年), "month"(年-月), "day"(年-月-日)
    # order只能是:"ASC"  "DESC"
    # 並獲取轉換後的時間
        - year : 年-01-01
        - month: 年-月-01
        - day  : 年-月-日

    models.DatePlus.objects.dates('ctime','day','DESC')

def datetimes(self, field_name, kind, order='ASC', tzinfo=None):
    # 根據時間進行某一部分進行去重查找並截取指定內容,將時間轉換爲指定時區時間
    # kind只能是 "year", "month", "day", "hour", "minute", "second"
    # order只能是:"ASC"  "DESC"
    # tzinfo時區對象
    models.DDD.objects.datetimes('ctime','hour',tzinfo=pytz.UTC)
    models.DDD.objects.datetimes('ctime','hour',tzinfo=pytz.timezone('Asia/Shanghai'))

    """
    pip3 install pytz
    import pytz
    pytz.all_timezones
    pytz.timezone(‘Asia/Shanghai’)
    """

def none(self):
    # 空QuerySet對象


####################################
# METHODS THAT DO DATABASE QUERIES #
####################################

def aggregate(self, *args, **kwargs):
   # 聚合函數,獲取字典類型聚合結果
   from django.db.models import Count, Avg, Max, Min, Sum
   result = models.UserInfo.objects.aggregate(k=Count('u_id', distinct=True), n=Count('nid'))
   ===> {'k': 3, 'n': 4}

def count(self):
   # 獲取個數

def get(self, *args, **kwargs):
   # 獲取單個對象

def create(self, **kwargs):
   # 建立對象

def bulk_create(self, objs, batch_size=None):
    # 批量插入
    # batch_size表示一次插入的個數
    objs = [
        models.DDD(name='r11'),
        models.DDD(name='r22')
    ]
    models.DDD.objects.bulk_create(objs, 10)

def get_or_create(self, defaults=None, **kwargs):
    # 若是存在,則獲取,不然,建立
    # defaults 指定建立時,其餘字段的值
    obj, created = models.UserInfo.objects.get_or_create(username='root1', defaults={'email': '1111111','u_id': 2, 't_id': 2})

def update_or_create(self, defaults=None, **kwargs):
    # 若是存在,則更新,不然,建立
    # defaults 指定建立時或更新時的其餘字段
    obj, created = models.UserInfo.objects.update_or_create(username='root1', defaults={'email': '1111111','u_id': 2, 't_id': 1})

def first(self):
   # 獲取第一個

def last(self):
   # 獲取最後一個

def in_bulk(self, id_list=None):
   # 根據主鍵ID進行查找
   id_list = [11,21,31]
   models.DDD.objects.in_bulk(id_list)

def delete(self):
   # 刪除

def update(self, **kwargs):
    # 更新

def exists(self):
   # 是否有結果


QuerySet方法大全
View Code

 

#統計不止一個做者的圖書,
ret=models.Book.objects.annotate(count=Count('author')).filter(count__gt=1)
print(ret)

相關文章
相關標籤/搜索