ORM簡(jiǎn)介
ORM,全拼Object-Relation Mapping,中文意為對(duì)象-關(guān)系映射,是隨著面向?qū)ο蟮能浖_發(fā)方法發(fā)展而產(chǎn)生的。面向?qū)ο蟮拈_發(fā)方法是當(dāng)今企業(yè)級(jí)應(yīng)用開發(fā)環(huán)境中的主流開發(fā)方法摘能,關(guān)系數(shù)據(jù)庫是企業(yè)級(jí)應(yīng)用環(huán)境中永久存放數(shù)據(jù)的主流數(shù)據(jù)存儲(chǔ)系統(tǒng)。對(duì)象和關(guān)系數(shù)據(jù)是業(yè)務(wù)實(shí)體的兩種表現(xiàn)形式即寡,業(yè)務(wù)實(shí)體在內(nèi)存中表現(xiàn)為對(duì)象徊哑,在數(shù)據(jù)庫中表現(xiàn)為關(guān)系數(shù)據(jù)。內(nèi)存中的對(duì)象之間存在關(guān)聯(lián)和繼承關(guān)系聪富,而在數(shù)據(jù)庫中莺丑,關(guān)系數(shù)據(jù)無法直接表達(dá)多對(duì)多關(guān)聯(lián)和繼承關(guān)系。因此墩蔓,對(duì)象-關(guān)系映射ORM系統(tǒng)一般以中間件的形式存在梢莽,主要實(shí)現(xiàn)程序?qū)ο蟮疥P(guān)系數(shù)據(jù)庫數(shù)據(jù)的映射。面向?qū)ο笫菑能浖こ袒驹瓌t(如耦合奸披、聚合昏名、封裝)的基礎(chǔ)上發(fā)展起來的,而關(guān)系數(shù)據(jù)庫則是從數(shù)學(xué)理論發(fā)展而來的阵面,兩套理論存在顯著的區(qū)別轻局。為了解決這個(gè)不匹配的現(xiàn)象,對(duì)象關(guān)系映射技術(shù)應(yīng)運(yùn)而生洪鸭。O/R中字母O起源于"對(duì)象"(Object),而R則來自于"關(guān)系"(Relational)。幾乎所有的程序里面仑扑,都存在對(duì)象和關(guān)系數(shù)據(jù)庫览爵。在業(yè)務(wù)邏輯層和用戶界面層中,我們是面向?qū)ο蟮恼蛞.?dāng)對(duì)象信息發(fā)生變化的時(shí)候蜓竹,我們需要把對(duì)象的信息保存在關(guān)系數(shù)據(jù)庫中。目前流行的ORM產(chǎn)品如Java的Hibernate储藐,.Net的EntityFormerWork等俱济。
在MVC框架中的Model模塊中都包括ORM,對(duì)于開發(fā)人員主要帶來了如下好處:
- 實(shí)現(xiàn)了數(shù)據(jù)模型與數(shù)據(jù)庫的解耦钙勃,通過簡(jiǎn)單的配置就可以輕松更換數(shù)據(jù)庫蛛碌,而不需要修改代碼。
- 只需要面向?qū)ο缶幊谭温疲恍枰嫦驍?shù)據(jù)庫編寫代碼左医。
- 在MVC中Model中定義的類,通過ORM與關(guān)系型數(shù)據(jù)庫中的表對(duì)應(yīng)同木,對(duì)象的屬性體現(xiàn)對(duì)象間的關(guān)系,這種關(guān)系也被映射到數(shù)據(jù)表中跛十。
Django框架中ORM示意圖如下:
詳解模型類
定義屬性
Django根據(jù)屬性的類型確定以下信息:
- 當(dāng)前選擇的數(shù)據(jù)庫支持字段的類型
- 渲染管理表單時(shí)使用的默認(rèn)html控件
- 在管理站點(diǎn)最低限度的驗(yàn)證
django會(huì)為表創(chuàng)建自動(dòng)增長的主鍵列彤路,每個(gè)模型只能有一個(gè)主鍵列,如果使用選項(xiàng)設(shè)置某屬性為主鍵列后django不會(huì)再創(chuàng)建自動(dòng)增長的主鍵列芥映。
默認(rèn)創(chuàng)建的主鍵列屬性為id洲尊,可以使用pk代替,pk全拼為primary key奈偏。
注意:pk是主鍵的別名坞嘀,若主鍵名為id2,那么pk是id2的別名惊来。
屬性命名限制:
- 不能是python的保留關(guān)鍵字丽涩。
- 不允許使用連續(xù)的下劃線,這是由django的查詢方式?jīng)Q定的裁蚁,以后會(huì)詳細(xì)講解查詢矢渊。
- 定義屬性時(shí)需要指定字段類型,通過字段類型的參數(shù)指定選項(xiàng)枉证,語法如下:
屬性=models.字段類型(選項(xiàng))
字段類型
使用時(shí)需要引入django.db.models包矮男,字段類型如下:
- AutoField:自動(dòng)增長的IntegerField,通常不用指定室谚,不指定時(shí)Django會(huì)自動(dòng)創(chuàng)建屬性名為id的自動(dòng)增長屬性毡鉴。
- BooleanField:布爾字段崔泵,值為True或False。
- NullBooleanField:支持Null猪瞬、True管削、False三種值。
- CharField(max_length=字符長度):字符串撑螺。參數(shù)max_length表示最大字符個(gè)數(shù)含思。
- TextField:大文本字段,一般超過4000個(gè)字符時(shí)使用甘晤。
- IntegerField:整數(shù)含潘。
- DecimalField(max_digits=None, decimal_places=None):十進(jìn)制浮點(diǎn)數(shù)。參數(shù)max_digits表示總位數(shù)线婚。參數(shù)decimal_places表示小數(shù)位數(shù)遏弱。
- FloatField:浮點(diǎn)數(shù)。
- DateField[auto_now=False, auto_now_add=False]):日期塞弊。
- 1.參數(shù)auto_now表示每次保存對(duì)象時(shí)漱逸,自動(dòng)設(shè)置該字段為當(dāng)前時(shí)間,用于"最后一次修改"的時(shí)間戳游沿,它總是使用當(dāng)前日期饰抒,默認(rèn)為false。
- 2.參數(shù)auto_now_add表示當(dāng)對(duì)象第一次被創(chuàng)建時(shí)自動(dòng)設(shè)置當(dāng)前時(shí)間诀黍,用于創(chuàng)建的時(shí)間戳袋坑,它總是使用當(dāng)前日期,默認(rèn)為false眯勾。
注:參數(shù)auto_now_add和auto_now是相互排斥的枣宫,組合將會(huì)發(fā)生錯(cuò)誤。
- TimeField:時(shí)間吃环,參數(shù)同DateField也颤。
- DateTimeField:日期時(shí)間,參數(shù)同DateField郁轻。
- FileField:上傳文件字段翅娶。
- ImageField:繼承于FileField,對(duì)上傳的內(nèi)容進(jìn)行校驗(yàn)范咨,確保是有效的圖片故觅。
選項(xiàng)
通過選項(xiàng)實(shí)現(xiàn)對(duì)字段的約束,選項(xiàng)如下:
- null:如果為True渠啊,表示允許為空输吏,默認(rèn)值是False。
- blank:如果為True替蛉,則該字段允許為空白贯溅,默認(rèn)值是False拄氯。
對(duì)比:null是數(shù)據(jù)庫范疇的概念,blank是表單驗(yàn)證范疇的它浅。
- db_column:字段的名稱译柏,如果未指定,則使用屬性的名稱姐霍。
- db_index:若值為True, 則在表中會(huì)為此字段創(chuàng)建索引鄙麦,默認(rèn)值是False。
- default:默認(rèn)值镊折。
- primary_key:若為True胯府,則該字段會(huì)成為模型的主鍵字段,默認(rèn)值是False恨胚,一般作為AutoField的選項(xiàng)使用骂因。
- unique:如果為True, 這個(gè)字段在表中必須有唯一值,默認(rèn)值是False赃泡。
字段查詢
實(shí)現(xiàn)sql中where的功能寒波,調(diào)用過濾器filter()、exclude()升熊、get()俄烁,下面以filter()為例。
通過"屬性名_id"表示外鍵對(duì)應(yīng)對(duì)象的id值僚碎。
語法如下:
說明:屬性名稱和比較運(yùn)算符間使用兩個(gè)下劃線猴娩,所以屬性名不能包括多個(gè)下劃線。
屬性名稱__比較運(yùn)算符=值
條件運(yùn)算符
- 查詢等
exact:表示判等勺阐。
例:查詢編號(hào)為1的圖書。
list=BookInfo.objects.filter(id__exact=1)
可簡(jiǎn)寫為:
list=BookInfo.objects.filter(id=1)
- 模糊查詢
說明:如果要包含%無需轉(zhuǎn)義矛双,直接寫即可渊抽。
例:查詢書名包含'神'的圖書。
list = BookInfo.objects.filter(btitle__contains='神')
- startswith议忽、endswith:以指定值開頭或結(jié)尾懒闷。
例:查詢書名以'部'結(jié)尾的圖書
list = BookInfo.objects.filter(btitle__endswith='部')
以上運(yùn)算符都區(qū)分大小寫,在這些運(yùn)算符前加上i表示不區(qū)分大小寫栈幸,如iexact愤估、icontains、istartswith速址、iendswith
條件字段查詢
實(shí)現(xiàn)sql中where的功能玩焰,調(diào)用過濾器filter()、exclude()芍锚、get()昔园,下面以filter()為例蔓榄。
通過"屬性名_id"表示外鍵對(duì)應(yīng)對(duì)象的id值。
語法同上
配置mysql的數(shù)據(jù)庫日志
查看mysql數(shù)據(jù)庫日志可以查看對(duì)數(shù)據(jù)庫的操作記錄默刚。 mysql日志文件默認(rèn)沒有產(chǎn)生甥郑,需要做如下配置:
右鍵Navicat數(shù)據(jù)庫選擇運(yùn)行命令行界面:
show variables like "general_log%";
命令查看日志文件是否打開 如圖所示:
如果 general_log 的 Value 為OFF
則需要輸入命令:
SET GLOBAL general_log = 'ON';
日志的默認(rèn)位置在:/usr/local/mysql/data/zhangyus-MacBook-Pro.log
在terminal下運(yùn)行上面的命令:sudo tail -f /usr/local/mysql/data/zhangyus-MacBook-Pro.log
條件運(yùn)算符
- 詢等
exact:表示判等。
例:查詢編號(hào)為1的圖書荤西。
運(yùn)行
python manage.py shell
from booktest.models import *
BookInfo.objects.filter(id__exact=1)
可簡(jiǎn)寫為:
BookInfo.objects.filter(id=1)
在日志文件中會(huì)生成如下sql語句
SELECT `booktest_bookinfo`.`id`, `booktest_bookinfo`.`btitle`, `booktest_bookinfo`.`bpub_date`, `booktest_bookinfo`.`bread`, `booktest_bookinfo`.`bcomment`, `booktest_bookinfo`.`isDelete` FROM `booktest_bookinfo` WHERE `booktest_bookinfo`.`id` = 1
- 模糊查詢
- contains:是否包含澜搅。
說明:如果要包含%無需轉(zhuǎn)義,直接寫即可邪锌。
例:查詢書名包含'英雄'的圖書勉躺。
BookInfo.objects.filter(btitle__contains='英雄')
在日志文件中會(huì)生成如下sql語句
SELECT `booktest_bookinfo`.`id`, `booktest_bookinfo`.`btitle`, `booktest_bookinfo`.`bpub_date`, `booktest_bookinfo`.`bread`, `booktest_bookinfo`.`bcomment`, `booktest_bookinfo`.`isDelete` FROM `booktest_bookinfo` WHERE `booktest_bookinfo`.`btitle` LIKE BINARY '%英雄%'
- startswith、endswith:以指定值開頭或結(jié)尾秃流。
例:查詢書名以'部'結(jié)尾的圖書
BookInfo.objects.filter(btitle__endswith='部')
以上運(yùn)算符都區(qū)分大小寫赂蕴,在這些運(yùn)算符前加上i表示不區(qū)分大小寫,如iexact舶胀、icontains概说、istartswith、iendswith.
- 空查詢
isnull:是否為null嚣伐。
例:查詢書名不為空的圖書糖赔。
BookInfo.objects.filter(btitle__isnull=False)
- 范圍查詢
in:是否包含在范圍內(nèi)。
例:查詢編號(hào)為1或3或5的圖書
BookInfo.objects.filter(id__in=[1, 3, 5])
- 比較查詢
gt轩端、gte放典、lt、lte:大于基茵、大于等于奋构、小于、小于等于拱层。
例:查詢編號(hào)大于3的圖書
BookInfo.objects.filter(id__gt=3)
- 日期查詢
year弥臼、month、day根灯、week_day径缅、hour、minute烙肺、second:對(duì)日期時(shí)間類型的屬性進(jìn)行運(yùn)算纳猪。
例:查詢1980年發(fā)表的圖書。
BookInfo.objects.filter(bpub_date__year=1980)
例:查詢1980年1月1日后發(fā)表的圖書桃笙。
BookInfo.objects.filter(bpub_date__gt=date(1990, 1, 1))
F對(duì)象
之前的查詢都是對(duì)象的屬性與常量值比較氏堤,兩個(gè)屬性怎么比較呢? 答:使用F對(duì)象怎栽,被定義在django.db.models中丽猬。
語法如下:
F(屬性名)
例:查詢閱讀量大于等于評(píng)論量的圖書宿饱。
from django.db.models import F
BookInfo.objects.filter(bread__gte=F('bcomment'))
可以在F對(duì)象上使用算數(shù)運(yùn)算。
例:查詢閱讀量大于2倍評(píng)論量的圖書脚祟。
BookInfo.objects.filter(bread__gt=F('bcomment') * 2)
Q對(duì)象
多個(gè)過濾器逐個(gè)調(diào)用表示邏輯與關(guān)系谬以,同sql語句中where部分的and關(guān)鍵字。
例:查詢閱讀量大于20由桌,并且編號(hào)小于3的圖書为黎。
BookInfo.objects.filter(bread__gt=20,id__lt=3)
或
BookInfo.objects.filter(bread__gt=20).filter(id__lt=3)
如果需要實(shí)現(xiàn)邏輯或or的查詢,需要使用Q()對(duì)象結(jié)合|運(yùn)算符行您,Q對(duì)象被義在django.db.models中铭乾。
語法如下:
Q(屬性名__運(yùn)算符=值)
Q對(duì)象可以使用&、|連接娃循,&表示邏輯與炕檩,|表示邏輯或。
例:查詢閱讀量大于20捌斧,或編號(hào)小于3的圖書笛质,只能使用Q對(duì)象實(shí)現(xiàn)
BookInfo.objects.filter(Q(bread__gt=20) | Q(pk__lt=3))
Q對(duì)象前可以使用~操作符,表示非not捞蚂。
例:查詢編號(hào)不等于3的圖書妇押。
BookInfo.objects.filter(~Q(pk=3))
聚合函數(shù)
使用aggregate()過濾器調(diào)用聚合函數(shù)。聚合函數(shù)包括:Avg姓迅,Count敲霍,Max,Min丁存,Sum肩杈,被定義在django.db.models中。
例:查詢圖書的總閱讀量
from django.db.models import Sum
BookInfo.objects.aggregate(Sum('bread'))
注意aggregate的返回值是一個(gè)字典類型解寝,格式如下:
{'聚合類小寫__屬性名':值}
如:{'sum__bread':3}
使用count時(shí)一般不使用aggregate()過濾器锋恬。
例:查詢圖書總數(shù)
from django.db.models import Count
BookInfo.objects.count()
注意count函數(shù)的返回值是一個(gè)數(shù)字。