Django操作NOSQL(MongoDB)數據庫
每一個Django工程師在接觸NOSQL數據庫的時候,肯定都會思考一個問題:在Django中不能像操作普通的關系型數據庫(以下簡稱RDB) 一樣,操作NOSQL數據庫嗎?當然可以,Django工程師幾乎不需要什么學習成本,就能使用NOSQL數據庫——因為有mongoengine這個模 塊。
MongoEngine由Python語言寫成,提供一個很類似Django ORM的API,本文介紹mongoengine的基本使用,主要是數據結構的定義和內聯表單的使用。
Install & Begin
需要安裝兩個模塊,pymongo和mongoengine
pip install pymongo
現在我們以最快的方式利用Django對MongoDB進行操作,請在電腦旁放置一個秒表,理論上完成這些操作的時間不會超過3分鐘:
新建一個應用,其中新建一個 docs.py文件,代碼如下:from mongoengine import * connect('test') class User(Document): username = StringField(required=True) website = URLField() tags = ListField(StringField(max_length=16))
然后編輯views.py文件:
from django.http import HttpResponse from . import docs def index(request): user1 = docs.User( username='Perchouli', website='http://dmyz.org', tags = ['Web','Django','JS'] ) user1.save() Oid = user1.id return HttpResponse(Oid)
最后,把視圖加到URL中,訪問這個視圖可以看到返回的ObjectID,我們已經實現了對NOSQL數據庫的寫入和查找了。是不是和Django ORM幾乎一樣呢?
Philosophy
回頭說說代碼。docs.py中的語法很類似models.py,但兩者的用途完全不同。mongoengine是定義一個scheme,這些定義不會寫入到數據庫中。
在User中使用了三種Field,MongoDB是使用JSON格式存儲數據,所以寫入的值也可以是對象/數組/字典,mongoengine會 自動將Python數據格式轉換成JS數據格式,但必須按照之前的定義的Field類型來傳值。比如上例中的tags被定義為數組 (ListField),數組中的每個元素是字符(StringField),mongoengine只接受同樣類型的數據格式。
EmbeddedField
RDB對數據的組織是建立在“關系”之上的,比如我們要存儲某個用戶的Profile,它與用戶ID是多對一的關系,在RDB中,通常要新建一張名 為Profile的表,其中包含UserID和Profile,每一條數據對應一個Profile的記錄,這種方式多少顯得有些笨拙。NOSQL的出現解 決了這類問題,在NOSQL數據庫中使用內聯的方式,直接把Profile存在User下,調用User時就可以獲得Profile的數據了。
修改上例中的docs.py,增加Profile:
from mongoengine import * connect('test') #先定義名為Profile的EmbeddedDocument class Profile(EmbeddedDocument): gender = StringField() location = StringField() class User(Document): username = StringField(required=True) website = URLField() tags = ListField(StringField(max_length=16)) #添加到User profile = EmbeddedDocumentField(Profile)
再修改views.py,為了顯示區別這里輸出一個JSON格式的字符串:
from django.http import HttpResponse from . import docs def index(request): profile1 = docs.Profile(gender='male', location='Beijing') user1 = docs.User( username='Perchouli', website='http://dmyz.org', tags = ['Web','Django','JS'], profile = profile1 ) user1.save() user1_json = str(user1.to_mongo()) return HttpResponse(user1_json)
怎么讀取profile中的gender和location?我不說你可能也想到了: user1.profile.gender。其他的操作也一樣,都是用for來遍歷數據,查找、刪除也是類似的語法。
Afterword
mongoengine這種類似ORM的寫法提供了一個很好的過渡方式,但NOSQL數據庫畢竟不是構建于”關系”之上的,很多ORM的經驗并不適 用。其實操作NOSQL數據庫,對它進行增刪改查并不復雜,真正頭疼的是數據的建模,具體的業務邏輯,怎樣設計才能最大限度的發揮NOSQL數據庫的用途 等等一些列問題。mongoengine降低了Django工程師使用NOSQL數據庫的門檻,相信只要有更多的人參與其中,這類經驗會逐步豐富和完善 的。