django -- ORM查詢

前戲

在咱們以前操做ORM中,你也許是啓動Django項目,經過地址訪問固定的函數,或者在pycharm裏的python console裏執行,第一種比較麻煩,並且每次都要啓動項目,寫路由,第二種雖然不須要寫路由,可是寫的東西保存不下來,只要關閉就沒有了。今天來經過python腳本的形式來寫,既不須要啓動項目,也能夠保存java

在項目下面建立一個python文件,裏面寫以下代碼python

import os if __name__ == "__main__": os.environ.setdefault("DJANGO_SETTINGS_MODULE", "項目名.settings") import django django.setup() from appTest01 import models  # 導入視圖函數
    obj = models.Person.objects.all() print(obj)

這樣咱們就能夠寫ORM語句,只須要右鍵運行就能夠了linux

若是想查看ORM轉爲的SQL語句,只須要在項目的settings.py裏寫以下代碼就能夠把SQL語句打印到控制檯上sql

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

ORM經常使用查詢

數據庫裏數據以下數據庫

import os if __name__ == "__main__": os.environ.setdefault("DJANGO_SETTINGS_MODULE", "orm_project.settings") import django django.setup() from appTest01 import models # all() 查詢全部結果,返回的是對象列表。若是要獲取對應的字段值,先取索引,在用.字段名
    # 好比下面的要獲取第二個姓名,ret[1].name
    ret = models.Person.objects.all() # print(ret) <QuerySet [<Person: Person object>, <Person: Person object>, <Person: Person object>]>

    # get() 查詢到的是對象,有且只能有一個,要否則會報錯,要獲取對應的字段值直接用.
    # 好比下面的要獲取姓名,ret.name
    ret = models.Person.objects.get(id=1) # print(ret) Person object

    # filter() 查詢出知足條件的對象,返回的是對象列表,獲取對應的值也要使用索引的方式
    ret = models.Person.objects.filter(id=1) # print(ret) <QuerySet [<Person: Person object>]>

    # exclude() 查詢出全部不知足條件的對象,返回的是對象列表,獲取對應的值也要使用索引的方式
    ret = models.Person.objects.exclude(id=1)[1] # print(ret.name) 王五

    # value() 具體的數據,沒有指定參數,獲取全部的字段數據,指定參數,獲取指定字段數據
    ret = models.Person.objects.values() # for i in ret:
    # print(i)
    ''' {'id': 1, 'name': 'zouzou', 'age': 25, 'birth': datetime.datetime(2019, 7, 19, 15, 7, 15, 296496, tzinfo=<UTC>)} {'id': 2, 'name': '張三', 'age': 43, 'birth': datetime.datetime(2019, 7, 20, 14, 4, 4, tzinfo=<UTC>)} {'id': 3, 'name': '王五', 'age': 23, 'birth': datetime.datetime(2019, 7, 28, 14, 4, 23, tzinfo=<UTC>)} '''

    # values_list() 具體的數據,沒有指定參數,獲取全部的字段數據,指定參數,獲取指定字段數據
    ret = models.Person.objects.values_list() # for i in ret:
    # print(i)
    ''' (1, 'zouzou', 25, datetime.datetime(2019, 7, 19, 15, 7, 15, 296496, tzinfo=<UTC>)) (2, '張三', 43, datetime.datetime(2019, 7, 20, 14, 4, 4, tzinfo=<UTC>)) (3, '王五', 23, datetime.datetime(2019, 7, 28, 14, 4, 23, tzinfo=<UTC>)) '''

    # order_by() 對查詢結果排序,前面加-表示降序,不寫表示升序
    # 能夠指定多個字段,若是第一個字段相同,則以第二個排,以此類推
    ret = models.Person.objects.all().order_by('-id')[0] # print(ret.id) 3

    # reverse() 對查詢結果反向排序,請注意reverse()一般只能在具備已定義順序的QuerySet上調用(在model類的Meta中指定ordering或調用order_by()方法)
    # ordering=('id',)
    ret = models.Person.objects.all().order_by('-id').reverse()[0] # print(ret.id) 1

    # distinct() 去重 從返回結果中剔除重複紀錄(若是你查詢跨越多個表,可能在計算QuerySet時獲得重複的結果。此時可使用distinct(),注意只有在PostgreSQL中支持按字段去重。)

    # count() 計數
    ret = models.Person.objects.all().count() # print(ret) 3

    # first() 返回第一條記錄,取值不須要按索引
    ret = models.Person.objects.all().first() # print(ret.name) zouzou

    # last() 返回最後一條記錄,取值不須要按索引
    ret = models.Person.objects.all().last() # print(ret.name) 王五

    # exists() 若是QuerySet包含數據,就返回True,不然返回False
    ret = models.Person.objects.filter(name='趙六').exists() # print(ret) False

總結:django

返回QuerySet對象的方法有併發

all()app

filter()ide

exclude()函數

order_by()

reverse()

distinct()

特殊的QuerySet

 values()         返回一個可迭代的字典序列

values_list()    返回一個可迭代的元組序列

返回具體對象的

get()

first()

last()

返回布爾值的

exists()

返回數字的

count()

雙下劃線方法

前面的都是查詢某個值等於什麼什麼的。可是咱們常常會查詢大於多少,好比成績大於60分的,這時候就要用到雙下滑線方法了

ret = models.Person.objects.filter(id__gt=1)  # id大於1
 ret = models.Person.objects.filter(id__gte=1)  # id大於等於1
 ret = models.Person.objects.filter(id__lt=3)  # id小於3
 ret = models.Person.objects.filter(id__lte=3)  # id小於等於3

 ret = models.Person.objects.filter(id__in=[1, 3])  # id爲1和3的
 ret = models.Person.objects.filter(id__gte=1, id__lte=3)  # id大於等於1而且小於等於3的
ret = models.Person.objects.filter(id__range=[1,3])  # id大於等於1而且小於等於3的
 ret = models.Person.objects.filter(name__contains='u')  # name裏包含字母u的,區分大小寫
ret = models.Person.objects.filter(name__icontains='u')  # name裏包含字母u的,不區分大小寫
 ret = models.Person.objects.filter(name__startswith='z')  # 以z開頭,區分大小寫
ret = models.Person.objects.filter(name__istartswith='z')  # 以z開頭,不區分大小寫
ret = models.Person.objects.filter(name__endswith='u')  # 以u結尾,區分大小寫
ret = models.Person.objects.filter(name__iendswith='u')  # 以u結尾,不區分大小寫
 ret = models.Person.objects.filter(birth__year='2019')  # 查詢年份爲2019

 ForeignKey查詢

先來建立幾張表

class Press(models.Model): name = models.CharField(max_length=32) def __str__(self): return '<Press %s-%s>'%(self.id,self.name) class Book(models.Model): title = models.CharField(max_length=32) price = models.IntegerField() publisher = models.ForeignKey(to='Press') def __str__(self): return '<Book %s-%s>'%(self.id, self.title) class Author(models.Model): name = models.CharField(max_length=32) books = models.ManyToManyField(to='Book')
建立表

往press表和book表裏添加一些數據,以下

book_obj = models.Book.objects.get(id=1) print(book_obj.title)  # linux
print(book_obj.price)  # 22
print(book_obj.publisher_id)  # 2
print(book_obj.publisher)  # publisher對應的上Press表,因此是press對象---》<Press 2-清華出版社>
print(book_obj.publisher.name)  # press裏對應的name---》清華出版社

查找上海出版社的書

常規寫法

models.Book.objects.filter(publisher_id=models.Press.objects.get(name='上海出版社').id)

結果:

<QuerySet [<Book: <Book 2-python入門到放棄>>, <Book: <Book 3-java直接放棄>>]>

高級寫法

obj = models.Book.objects.filter(publisher__name='上海出版社')

publisher__name ,前面的publisher爲Book表裏的字段,對應的結果是Press這個表對象,__name表示press表裏的name字段

反向查詢

上面的查詢是經過book表查詢press表的裏數據,由於外鍵是寫在book表裏的,咱們把這種叫作正向查詢

經過press表查詢book表裏的數據,咱們叫作反向查詢

經過press裏的id查找對應的書

obj = models.Press.objects.get(id=3) print(obj.book_set.all())

結果:

<QuerySet [<Book: <Book 2-python入門到放棄>>, <Book: <Book 3-java直接放棄>>]>

book_set,表名小寫_set獲得的是一個管理對象,若是要獲取全部的對象,在後面寫.all()

還有另外一種寫法是在表裏的字段後面寫上related_name

class Book(models.Model): title = models.CharField(max_length=32) price = models.IntegerField() publisher = models.ForeignKey(to='Press', related_name='mybook') def __str__(self): return '<Book %s-%s>'%(self.id, self.title)

上面的查詢就變成

obj = models.Press.objects.get(id=3) print(obj.mybook.all())

正向查詢書名也要用mybook_xxx='xxx' 

根據書名查詢出版社

常規寫法

obj = models.Press.objects.filter(id=models.Book.objects.get(title='python入門到放棄').publisher_id)

結果:

<QuerySet [<Press: <Press 3-上海出版社>>]>

高級寫法

obj = models.Press.objects.filter(book__title='python入門到放棄')

 ManyToManyField

在咱們建立表的時候,book和author是多對多的關係,先來看一下他們之間的關係

 

 set()  更新model對象的關聯對象

obj = models.Author.objects.get(id=1) # print(obj.name) 孫悟空
 obj.books.set(models.Book.objects.all())

obj = models.Author.objects.get(id=1) # print(obj.name) 孫悟空
 obj.books.set([1,3])

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

obj = models.Author.objects.get(id=1) # print(obj.name) 孫悟空
 obj.books.add(*[2,4])

add還能夠這樣寫

obj.books.add(1,2,3,4) obj.books.add(*models.Book.objects.all())

remove() 從關係對象中移除執行的model對象

obj = models.Author.objects.get(id=1) # print(obj.name) 孫悟空

obj.books.remove(1,4)

刪除所有

obj = models.Author.objects.get(id=1) # print(obj.name) 孫悟空
 obj.books.remove(*models.Book.objects.all())

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

obj = models.Author.objects.get(id=1) # print(obj.name) 孫悟空
 obj.books.clear()

建立書和對應的關係

obj = models.Author.objects.get(id=1) # print(obj.name) 孫悟空
 obj.books.create(title='一小時精通Django',price=66,publisher_id=3)

 

反向查詢

class Author(models.Model): name = models.CharField(max_length=32) books = models.ManyToManyField(to='Book')

由於books是寫在Author表裏,因此經過Author查詢book表裏的是正向查詢,經過book表查詢author表裏的是反向查詢

obj = models.Book.objects.get(id=5) print(obj.author_set.all())

反向查詢要使用表名_set

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

栗子

ForeignKey字段沒設置null=True時

class Book(models.Model): title = models.CharField(max_length=32) publisher = models.ForeignKey(to=Publisher)

沒有clear()和remove()方法:

>>> models.Publisher.objects.first().book_set.clear() Traceback (most recent call last): File "<input>", line 1, in <module> AttributeError: 'RelatedManager' object has no attribute 'clear'

當ForeignKey字段設置null=True時

class Book(models.Model): name = models.CharField(max_length=32) publisher = models.ForeignKey(to=Class, null=True)

此時就有clear()和remove()方法:

models.Publisher.objects.first().book_set.clear()

聚合查詢

在sql語句中,咱們知道聚合語句,好比查詢最大值,最小值,平均值等等。在ORM中,使用aggregate()來進行聚合查詢,首先須要導入

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

查詢價格最大是多少

from django.db.models import Max, Min, Avg, Sum, Count ret = models.Book.objects.aggregate(Max('price')) print(ret) ret = models.Book.objects.all().aggregate(Max('price')) print(ret)

結果:

{'price__max': 66} {'price__max': 66}

結果是一個字典格式,key爲「字段_聚合名」,若是你看它不爽,你也能夠自定義

from django.db.models import Max, Min, Avg, Sum, Count ret = models.Book.objects.aggregate(最大值=Max('price'),最小值=Min('price')) print(ret)

結果:

{'最大值': 66, '最小值': 22}

注意:若是你查詢了多個,有些聚合你本身定義了名稱,有些你沒有定義名稱,則沒有定義名稱的要放在前面(位置參數不能在關鍵字參數後面)

分組查詢

先來看一下數據表關係

查詢出每本書的做者

from django.db.models import Max, Min, Avg, Sum, Count ret = models.Book.objects.annotate(num=Count('author')) print(ret)

結果是QuerySet

<QuerySet [<Book: Book object>, <Book: Book object>, <Book: Book object>, <Book: Book object>, <Book: Book object>]>

使用.values()獲取全部

from django.db.models import Max, Min, Avg, Sum, Count ret = models.Book.objects.annotate(num=Count('author')).values() for i in ret: print(i)

結果:

{'id': 1, 'title': 'linux', 'price': 22, 'publisher_id': 2, 'num': 1} {'id': 2, 'title': 'python入門到放棄', 'price': 55, 'publisher_id': 3, 'num': 0} {'id': 3, 'title': 'java直接放棄', 'price': 22, 'publisher_id': 3, 'num': 1} {'id': 4, 'title': 'go精通', 'price': 54, 'publisher_id': 1, 'num': 2} {'id': 5, 'title': '一小時精通Django', 'price': 66, 'publisher_id': 3, 'num': 1}

能夠在value裏指定參數獲取想要的字段

from django.db.models import Max, Min, Avg, Sum, Count ret = models.Book.objects.annotate(num=Count('author')).values('title','num') for i in ret: print(i)

結果:

num對應的值就是這本書做者的個數

{'title': 'linux', 'num': 1} {'title': 'python入門到放棄', 'num': 0} {'title': 'java直接放棄', 'num': 1} {'title': 'go精通', 'num': 2} {'title': '一小時精通Django', 'num': 1}

統計每一個出版社最便宜的書的價格

from django.db.models import Max, Min, Avg, Sum, Count ret = models.Book.objects.values('publisher_id').annotate(min_num=Min('price')) for i in ret: print(i)

結果:

{'publisher_id': 1, 'min_num': 54} {'publisher_id': 2, 'min_num': 22} {'publisher_id': 3, 'min_num': 22}

由於不分組的結果

from django.db.models import Max, Min, Avg, Sum, Count ret = models.Book.objects.values('publisher_id') for i in ret: print(i)

結果:

{'publisher_id': 1} {'publisher_id': 2} {'publisher_id': 3} {'publisher_id': 3} {'publisher_id': 3}

統計不止一個做者的圖書

ret = models.Book.objects.annotate(num=Count('author')).filter(num__gt=1).values() for i in ret: print(i)

結果:

{'id': 4, 'title': 'go精通', 'price': 54, 'publisher_id': 1, 'num': 2}

查詢各個做者出的書的總價格

F查詢

在以前的查詢中,咱們都是拿某個字段對一個固定的值作比較,若是想用字段和字段作比較,就要用到F查詢了,先來看下數據表裏的數據

需求,查出全部num大於money的

from django.db.models import F ret = models.Book.objects.filter(num__gt=F('money')).values() for i in ret: print(i)

結果:

{'id': 1, 'title': 'linux', 'price': 22, 'publisher_id': 2, 'money': 23, 'num': 65} {'id': 4, 'title': 'go精通', 'price': 54, 'publisher_id': 1, 'money': 33, 'num': 88} {'id': 5, 'title': '一小時精通Django', 'price': 66, 'publisher_id': 3, 'money': 44, 'num': 99}

需求:給每一個num的值*2

以前的都是對某一條數據更新的,如

ret = models.Book.objects.get(id=2) ret.num=24 ret.save()

上面的這種寫法要進行save(),並且要寫更新的具體數值

使用update更新

ret = models.Book.objects.filter(id=2).update(num=50)

update就不須要save

ret = models.Book.objects.update(num=50)  # 對全部的數據更新

這兩種寫法都知足不了咱們的需求,咱們用F來實現,下面兩種結果是同樣的

from django.db.models import F ret = models.Book.objects.update(num=F('num')*2) ret = models.Book.objects.all().update(num=F('num')*2)

需求:在全部書名後面加上(測試)

ret = models.Book.objects.update(title=Concat(F("title"), Value("("), Value("測試"), Value(")")))

不須要()

ret = models.Book.objects.update(title=Concat(F("title"), Value("測試")))

Q查詢

以前咱們全部進行的查詢都是and關係的,若是要使用or關係的查詢,就要用Q查詢了。繼續看數據表數據

需求:查詢id小於3而且大於等於6的

from django.db.models import Q ret = models.Author.objects.filter(Q(id__lt=3) | Q(id__gte=6)).values() for i in ret: print(i)

結果:管道符( | )表示或的關係

{'id': 1, 'name': '孫悟空'} {'id': 2, 'name': '豬八戒'} {'id': 6, 'name': '蜘蛛精'} {'id': 7, 'name': '女兒國'} {'id': 8, 'name': '紫霞仙子'}

&表示而且的關係

from django.db.models import Q ret = models.Author.objects.filter(Q(id__lt=7) & Q(id__gte=6)).values() for i in ret: print(i)

結果:

{'id': 6, 'name': '蜘蛛精'}

~表示取反

from django.db.models import Q ret = models.Author.objects.filter(~Q(id__lt=7) & Q(id__gte=6)).values() for i in ret: print(i)

結果:

{'id': 7, 'name': '女兒國'} {'id': 8, 'name': '紫霞仙子'}

事務

事務(Transaction)是併發控制的基本單位。所謂的事務,它是一個操做序列,這些操做要麼都執行,要麼都不執行,它是一個不可分割的工做單位。例如,銀行轉帳工做:從一個帳號扣款並使另外一個帳號增款,這兩個操做要麼都執行,要麼都不執行。因此,應該把它們當作一個事務。事務是數據庫維護數據一致性的單位,在每一個事務結束時,都能保持數據一致性。
針對上面的描述能夠看出,事務的提出主要是爲了解決併發狀況下保持數據一致性的問題。
事務具備如下4個基本特徵。

  • Atomic(原子性):事務中包含的操做被看作一個邏輯單元,這個邏輯單元中的操做要麼所有成功,要麼所有失敗。
  • Consistency(一致性):只有合法的數據能夠被寫入數據庫,不然事務應該將其回滾到最初狀態。
  • Isolation(隔離性):事務容許多個用戶對同一個數據進行併發訪問,而不破壞數據的正確性和完整性。同時,並行事務的修改必須與其餘並行事務的修改相互獨立。
  • Durability(持久性):事務結束後,事務處理的結果必須可以獲得固化。
import os if __name__ == "__main__": os.environ.setdefault("DJANGO_SETTINGS_MODULE", "orm_project.settings") import django django.setup() from appTest01 import models try: from django.db import transaction with transaction.atomic(): 這裏寫要執行的ORM語句 except Exception as e: print(str(e))
相關文章
相關標籤/搜索