在咱們以前操做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', }, } }
數據庫裏數據以下數據庫
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
先來建立幾張表
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入門到放棄')
在咱們建立表的時候,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查詢了,先來看下數據表裏的數據
需求,查出全部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("測試")))
以前咱們全部進行的查詢都是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個基本特徵。
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))