Django ORM的簡單總結
我們繼續昨天的內容使用Oracle中的emp,dept來學習Django ORM,今天做一些總結和擴充套件,希望你能有所收穫。
先來說下兩張表emp,dept。
emp表的資料如下:
dept表的資料如下:
然後我們就開始吧,有的同學說我的資料還沒有初始化,可以移步上一篇找到指令碼。
對於QuerysetAPI的內容,如果看文件有非常多的解釋和介紹,很難抓到重點,我就從我的認知來梳理一下。
1. QuerySet 建立物件的方法
>>> from scott.models import emp
>>> from scott.models import dept
先得到所有的資料。
>>> emp.objects.all()
[<emp: 7369 SMITH> , <emp: 7499 ALLEN> , <emp: 7521 WARD> , <emp: 7566 JONES> , <emp: 7654 MARTIN> , <emp: 7698 BLAKE> , <emp: 7782 CLARK> , <emp: 7788 SCOTT> , <emp: 7839 KING> , <emp: 7844 TURNER> , <emp: 7876 ADAMS> , <emp: 7900 JAMES> , <emp: 7902 FORD> , <emp: 7934 MILLER> , <emp: 9999 SHUNPING>]
>>> dept.objects.all()
[<dept: 10 ACCOUNTING> , <dept: 20 RESEARCH> , <dept: 30 SALES> , <dept: 40 OPERATIONS>]
第一種方法是使用create
>>> dept.objects.create( dname= 'DEV',loc= 'Beijing')
<dept: 41 DEV>
第二種是初始化另外一個物件,save完成
>>> newdept = dept( dname= 'TEST',loc= 'ShangHai')
>>> newdept.save()
第三種和第二種有些類似,可以對立面的屬性根據需求改變。
>>> #method 3
>>> newdept.dname
'TEST'
>>> newdept=dept()
>>> newdept.dname
u''
>>> newdept.dname= 'OPS'
>>> newdept.loc= 'Guangzhou'
>>> newdept.save()
第四種會做一個判斷,有點類似資料庫立面的create or replace,注意此處的返回是一個布林值。
>>> dept.objects.get_or_create( dname= 'DBA',loc= 'Shenzhen')
(<dept: 44 DBA> , True) 2.查詢語句根據主鍵查詢
>>> dept.objects.get( pk= 10)
<dept: 10 ACCOUNTING>
得到top n的資料
>>> dept.objects.all()[: 5]
[<dept: 10 ACCOUNTING> , <dept: 20 RESEARCH> , <dept: 30 SALES> , <dept: 40 OPERATIONS> , <dept: 41 DEV>]
使用get方法,返回的是一行
>>> dept.objects.get( dname= 'DBA')
<dept: 44 DBA>
使用filter的exact是精確匹配,和上面的方法是等價的。
>>> dept.objects.filter( dname__exact= 'DBA')
[<dept: 44 DBA>]
忽略大小寫
>>> dept.objects.filter( dname__iexact= 'DBA')
[<dept: 44 DBA>]
查詢內容排除包含ACC的部門
>>> dept.objects.exclude( dname__contains= 'ACC')
[<dept: 20 RESEARCH> , <dept: 30 SALES> , <dept: 40 OPERATIONS> , <dept: 41 DEV> , <dept: 42 TEST> , <dept: 43 OPS> , <dept: 44 DBA>]
>>>
可以過濾和排除操作都使用
>>> dept.objects.filter( dname__contains= 'DB').exclude( dname= 'MBA')
[<dept: 44 DBA>] 3.刪除這種方法是查到指定的資料,然後直接刪除,還是有一些風險點的。
>>> dept.objects.filter( dname__contains= 'DB').delete()
或者分批刪除
>>> dept.objects.all()
[<dept: 10 ACCOUNTING> , <dept: 20 RESEARCH> , <dept: 30 SALES> , <dept: 40 OPERATIONS> , <dept: 41 DEV> , <dept: 42 TEST> , <dept: 43 OPS>]
>>> newdept=dept.objects.filter( dname__contains= 'DEV')
>>> newdept.delete()
全部刪除 ,先不操作
dept.objects.all().delete() 4.更新使用filter來過濾得到資料,然後使用update來更新
>>> dept.objects.filter( dname__contains= 'TEST')
[<dept: 42 TEST>]
>>> dept.objects.filter( dname__contains= 'TEST').update( dname= 'Test')
1L
>>>
>>> dept.objects.filter( dname__contains= 'Te')
[<dept: 42 Test>]
或者把初始化一個物件,更新這個物件
>>> newdept=dept.objects.get( dname= 'Test')
>>>
>>> newdept.dname
u'Test'
>>> dname= 'Test2'
>>> loc= 'Lanzhou'
>>> newdept.save()
5.迭代Queryset>>> newdept=dept.objects.all()
>>> for new in newdept:
... print(new.dname)
...
ACCOUNTING
RESEARCH
SALES
OPERATIONS
Test
OPS 6.鏈式查詢兩個filter來過濾
>>> dept.objects.filter( dname__contains= 'Test').filter( deptno= 42)
[<dept: 42 Test>]
先使用fileter過濾,然後使用exclude排除
>>> dept.objects.filter( dname__contains= 'Test').exclude( deptno= 4)
[<dept: 42 Test>] 7.top n的寫法得到前4行
>>> dept.objects.all()[: 4]
[<dept: 10 ACCOUNTING> , <dept: 20 RESEARCH> , <dept: 30 SALES> , <dept: 40 OPERATIONS>]
>>>
最後2行,有個技巧是用reverse()
>>> dept.objects.all().reverse()[: 2]
[<dept: 43 OPS> , <dept: 42 Test>]
最後1行,下標是從0開始
>>> dept.objects.all().reverse()[ 0]
<dept: 43 OPS>
>>> dept.objects.all().reverse()[ 1]
<dept: 42 Test>
或者使用order_by反向排序
>>> dept.objects.all().order_by( '-deptno')[: 2]
[<dept: 43 OPS> , <dept: 42 Test>]
有的同學可能疑惑order_by和reverse的效能差別。我們繼續往下看。
8.得到呼叫的SQL語句方法1:
>>> print str(dept.objects.all().order_by( '-deptno').distinct().query)
SELECT DISTINCT `dept`.`deptno` , `dept`.`dname` , `dept`.`loc` FROM `dept` ORDER BY `dept`.`deptno` DESC
>>>
>>> print str(dept.objects.all().reverse().distinct().query)
SELECT DISTINCT `dept`.`deptno` , `dept`.`dname` , `dept`.`loc` FROM `dept` ORDER BY `dept`.`deptno` DESC
可見兩者是等價的,所以我們就很容易理解reverse()和order_by的差別了,實現不同,但是結果相同。 方法2:使用query.__str__()來得到
>>> dept.objects.all().reverse().distinct().query. __str__()
u'SELECT DISTINCT `dept`.`deptno`, `dept`.`dname`, `dept`.`loc` FROM `dept` ORDER BY `dept`.`deptno` DESC'
方法3:在settings.py裡面補充下面的內容,然後在python shell模式下,可以看到呼叫的SQL
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console': {
'class': 'logging.StreamHandler',
} ,
} ,
'loggers': {
'django.db.backends': {
'handlers': [ 'console'] ,
'level': 'DEBUG' if DEBUG else 'INFO',
} ,
} ,
} 8.得到返回結果 values_list
可以使用values_list來實現,比如返回dname和deptno列
>>> dept.objects.values_list( 'dname','deptno')
[( u'ACCOUNTING', 10L) , ( u'RESEARCH', 20L) , ( u'SALES', 30L) , ( u'OPERATIONS', 40L) , ( u'Test', 42L) , ( u'OPS', 43L)]
>>>
初始化一個物件,列印出結果
>>> newdept=dept.objects.values_list( 'dname','deptno')
>>> newdept
[( u'ACCOUNTING', 10L) , ( u'RESEARCH', 20L) , ( u'SALES', 30L) , ( u'OPERATIONS', 40L) , ( u'Test', 42L) , ( u'OPS', 43L)]
可以使用list方法
>>> list(newdept)
[( u'ACCOUNTING', 10L) , ( u'RESEARCH', 20L) , ( u'SALES', 30L) , ( u'OPERATIONS', 40L) , ( u'Test', 42L) , ( u'OPS', 43L)]
>>>
使用values_list的結果,格式和上面還是有一些差別的。
>>> dept.objects.values_list( 'dname',flat= True)
[ u'ACCOUNTING', u'RESEARCH', u'SALES', u'OPERATIONS', u'Test', u'OPS']
可以加入flat選項,只輸出指定的列
>>> print str(dept.objects.values_list( 'dname',flat= True).query)
SELECT `dept`.`dname` FROM `dept` ORDER BY `dept`.`deptno` ASC
9.得到返回結果 values
>>> dept.objects.values( 'dname')
[{ 'dname': u'ACCOUNTING'} , { 'dname': u'RESEARCH'} , { 'dname': u'SALES'} , { 'dname': u'OPERATIONS'} , { 'dname': u'Test'} , { 'dname': u'OPS'}]
>>>
>>> dept.objects.values_list( 'dname')
[( u'ACCOUNTING',) , ( u'RESEARCH',) , ( u'SALES',) , ( u'OPERATIONS',) , ( u'Test',) , ( u'OPS',)]
>>>
兩者返回的並不是真正的列表或字典,也是queryset 10.列的別名
可以使用extra來指定別名
>>> dept.objects.all().extra( select={ 'dname': 'Dname'})
[<dept: 10 ACCOUNTING> , <dept: 20 RESEARCH> , <dept: 30 SALES> , <dept: 40 OPERATIONS> , <dept: 42 Test> , <dept: 43 OPS>]
>>>
如果不確定裡面的引數代表的含義,可以得到解析的SQL來對比一下,就很清楚了。
>>> print str(dept.objects.all().extra( select={ 'dname': 'Dname'}).query)
SELECT (Dname) AS `dname` , `dept`.`deptno` , `dept`.dname , `dept`.`loc` FROM `dept` ORDER BY `dept`.`deptno` ASC
>>>
>>> print str(dept.objects.all().extra( select={ 'Dname': "dname"}).query)
SELECT (dname) AS `Dname` , `dept`.`deptno` , `dept`.`dname` , `dept`.`loc` FROM `dept` ORDER BY `dept`.`deptno` ASC
>>>
>>> print str(dept.objects.all().extra( select={ 'dname': 'Dname'}).defer( 'dname').query)
SELECT (Dname) AS `dname` , `dept`.`deptno` , `dept`.`loc` FROM `dept` ORDER BY `dept`.`deptno` ASC
11.聚合運算
我們常見的是這種:
##計算個數
>>> print str(dept.objects.all().extra( select={ 'dname': 'Dname'}).defer( 'dname').count())
6
如果是做聚合運算,就需要用到Count,Avg,Sum了。
##做聚合結算,需要匯入Count,使用annotate
>>> from django.db.models import Count
>>> dept.objects.all().values( 'dname').annotate( count=Count( 'dname')).values( 'dname','count')
[{ 'dname': u'ACCOUNTING', 'count': 1} , { 'dname': u'RESEARCH', 'count': 1} , { 'dname': u'SALES', 'count': 1} , { 'dname': u'OPERATIONS', 'count': 1} , { 'dname': u'Test', 'count': 1} , { 'dname': u'OPS', 'count': 1}]
不過值得一提的是,裡面的group by的部分是個硬骨頭,因為group by會預設帶有主鍵列,對於一些特殊的場景,就會有些乏力了,比如這種SQL,在目前的實現中是不能直接支援的。
select deptno_id ,count(*) from emp group by deptno_id;
都會間接轉換為如下的方式,就有些尷尬了。
select deptno_id ,count(*) from emp group by empno;
如果手工強轉,就會拋錯了。
>>> a=emp.objects.raw( 'select deptno_id,count(*) count from emp group by deptno_id')
>>> a[ 0]
( 0.000) select deptno_id ,count(*) count from emp group by deptno_id; args=()
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/usr/local/lib/python2.7/site-packages/django/db/models/query.py", line 1323, in __getitem__
return list(self)[k]
File "/usr/local/lib/python2.7/site-packages/django/db/models/query.py", line 1296, in __iter__
raise InvalidQuery( 'Raw query must include the primary key')
InvalidQuery: Raw query must include the primary key
12.Inner Join和聚合運算
inner join,注意下面的deptno__dname的部分。
>>> emp.objects.values( 'deptno__dname').annotate( sum=Sum( 'deptno')).values( 'deptno','sum').query. __str__()
u'SELECT `emp`.`deptno_id`, SUM(`emp`.`deptno_id`) AS `sum` FROM `emp` INNER JOIN `dept` ON ( `emp`.`deptno_id` = `dept`.`deptno` ) GROUP BY `emp`.`empno` ORDER BY `emp`.`empno` ASC, `emp`.`ename` ASC'
12.select_related查詢
這種方式的一大好處就是會自動關聯查詢,呼叫一次會自動獲取相關的資料。
我們可以對比下它和通常方式的差別。
使用傳統的方式,如果需要關聯查詢,會在後臺反覆呼叫關聯查詢。
>>> emp.objects.all()[: 10]
( 0.001) SELECT `emp`.`empno` , `emp`.`ename` , `emp`.`job` , `emp`.`mgr` , `emp`.`hiredate` , `emp`.`sal` , `emp`.`deptno_id` FROM `emp` ORDER BY `emp`.`empno` ASC , `emp`.`ename` ASC LIMIT 10; args=()
[<emp: 7369 SMITH> , <emp: 7499 ALLEN> , <emp: 7521 WARD> , <emp: 7566 JONES> , <emp: 7654 MARTIN> , <emp: 7698 BLAKE> , <emp: 7782 CLARK> , <emp: 7788 SCOTT> , <emp: 7839 KING> , <emp: 7844 TURNER>]
初始化物件,得到關聯資料的情況
>>> a=emp.objects.all()[: 10][ 0]
( 0.000) SELECT `emp`.`empno` , `emp`.`ename` , `emp`.`job` , `emp`.`mgr` , `emp`.`hiredate` , `emp`.`sal` , `emp`.`deptno_id` FROM `emp` ORDER BY `emp`.`empno` ASC , `emp`.`ename` ASC LIMIT 1; args=()
>>> a.ename
u'SMITH'
>>> a.deptno --可以看到又做了一次查詢
( 0.002) SELECT `dept`.`deptno` , `dept`.`dname` , `dept`.`loc` FROM `dept` WHERE `dept`.`deptno` = 20; args=( 20,)
<dept: 20 RESEARCH>
而使用select_related就可以解決這個問題。
只查一次資料庫 select_related
>>> a=emp.objects.all().select_related( 'deptno')[: 4][ 0]
( 0.001) SELECT `emp`.`empno` , `emp`.`ename` , `emp`.`job` , `emp`.`mgr` , `emp`.`hiredate` , `emp`.`sal` , `emp`.`deptno_id` , `dept`.`deptno` , `dept`.`dname` , `dept`.`loc` FROM `emp` INNER JOIN `dept` ON ( `emp`.`deptno_id` = `dept`.`deptno` ) ORDER BY `emp`.`empno` ASC , `emp`.`ename` ASC LIMIT 1; args=()
>>> a.ename
u'SMITH'
反覆檢視,都不會多次呼叫新的SQL
>>> a.deptno
<dept: 20 RESEARCH>
>>> a.ename
u'SMITH'
>>> a.mgr
7902L
>>>
>>> a.deptno.dname --級聯查詢
u'RESEARCH'13.prefetched_related查詢對比prefetched related的好處
>>> a=emp.objects.all().filter( empno__in=( 7369,7521,7566))
>>> a
( 0.001) SELECT `emp`.`empno` , `emp`.`ename` , `emp`.`job` , `emp`.`mgr` , `emp`.`hiredate` , `emp`.`sal` , `emp`.`deptno_id` FROM `emp` WHERE `emp`.`empno` IN ( 7369, 7521, 7566) ORDER BY `emp`.`empno` ASC , `emp`.`ename` ASC LIMIT 21; args=( 7369, 7521, 7566)
[<emp: 7369 SMITH> , <emp: 7521 WARD> , <emp: 7566 JONES>]
迭代
>>> for t in a:
... print t.ename ,t.deptno
...
SMITH 20 RESEARCH
( 0.000) SELECT `dept`.`deptno` , `dept`.`dname` , `dept`.`loc` FROM `dept` WHERE `dept`.`deptno` = 30; args=( 30,)
WARD 30 SALES
( 0.000) SELECT `dept`.`deptno` , `dept`.`dname` , `dept`.`loc` FROM `dept` WHERE `dept`.`deptno` = 20; args=( 20,)
JONES 20 RESEARCH
初始化物件,使用in的方式來過濾資料
>>> a=emp.objects.all().filter( empno__in=( 7369,7521,7566)).prefetch_related( 'deptno')
>>> a
( 0.001) SELECT `emp`.`empno` , `emp`.`ename` , `emp`.`job` , `emp`.`mgr` , `emp`.`hiredate` , `emp`.`sal` , `emp`.`deptno_id` FROM `emp` WHERE `emp`.`empno` IN ( 7369, 7521, 7566) ORDER BY `emp`.`empno` ASC , `emp`.`ename` ASC LIMIT 21; args=( 7369, 7521, 7566)
( 0.000) SELECT `dept`.`deptno` , `dept`.`dname` , `dept`.`loc` FROM `dept` WHERE `dept`.`deptno` IN ( 20, 30) ORDER BY `dept`.`deptno` ASC; args=( 20, 30)
[<emp: 7369 SMITH> , <emp: 7521 WARD> , <emp: 7566 JONES>]
可以看到自始至終,都只有一次互動
>>> for t in a:
... print t.ename ,t.deptno
...
( 0.000) SELECT `emp`.`empno` , `emp`.`ename` , `emp`.`job` , `emp`.`mgr` , `emp`.`hiredate` , `emp`.`sal` , `emp`.`deptno_id` FROM `emp` WHERE `emp`.`empno` IN ( 7369, 7521, 7566) ORDER BY `emp`.`empno` ASC , `emp`.`ename` ASC; args=( 7369, 7521, 7566)
( 0.000) SELECT `dept`.`deptno` , `dept`.`dname` , `dept`.`loc` FROM `dept` WHERE `dept`.`deptno` IN ( 20, 30) ORDER BY `dept`.`deptno` ASC; args=( 20, 30)
SMITH 20 RESEARCH
WARD 30 SALES
JONES 20 RESEARCH來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/23718752/viewspace-2149271/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Django ORM 單表操作DjangoORM
- Django-ORM-單表操作DjangoORM
- Pygame的簡單總結GAM
- Django ORMDjangoORM
- 簡簡單單的總結,意如生活的平淡
- MySQL簡單總結MySql
- vuex簡單總結Vue
- django中orm的使用DjangoORM
- day52:django:ORM單表/多表操作DjangoORM
- Django ORM QuerySetDjangoORM
- django mysqlclient ormDjangoMySqlclientORM
- HTTP/2 特性的簡單總結HTTP
- HTML簡單知識的總結HTML
- RediSearch的簡單使用與總結Redis
- sql注入簡單總結SQL
- 列舉簡單總結
- OKhttpClient 簡單使用總結HTTPclient
- 03.Django-ORMDjangoORM
- Django ORM 多表操作DjangoORM
- 關於STL容器的簡單總結
- js閉包簡單總結JS
- odoo ORM API學習總結兼orm學習教程OdooORMAPI
- 初始化ArrayList的簡單方法總結
- Django model總結(上)Django
- es6,async簡單總結
- 前端模組化簡單總結前端
- Android熱修復簡單總結Android
- C++基礎簡單總結C++
- Java基礎集合簡單總結Java
- 學點簡單的Django之第一個Django程式Django
- django的orm有什麼優點DjangoORM
- HBase-Region太多的問題簡單總結
- GPU 渲染管線簡單總結(網上資料總結)GPU
- Django之ORM連表操作DjangoORM
- django知識點總結Django
- python 內建函式簡單總結Python函式
- Java 新特性總結——簡單實用Java
- 超簡單!正規表示式總結
- 設計模式簡單總結(待完善)設計模式