MongoEngine文檔翻譯__新手教程(二)定義文檔

在MongoDB裏面,一條文檔大體至關於關係型數據庫裏面的一行。在關係型數據庫裏面,行是被存儲在表裏面,而且有一個嚴格的結構。MongoDB裏面把文檔存儲在集合裏面而不是存在表裏面,最根本上的不一樣就是在數據庫層面上沒有強制的結構限制。 html

    定義一個文檔綱要 python

    MongoEngine容許你爲文檔定義一個綱要這能夠幫你減小編碼錯誤,讓你利用現有的字段來定義各類功能的函數。 mongodb

    定義一個文檔的綱要,首先須要建立一個繼承 Document 的類。文檔的字段都被做爲這個繼承類的屬性。 數據庫

[python]
  1. from mongoengine import *  
  2. import datetime  
  3.   
  4. class Page(Document):  
  5.     title = StringField(max_length=200, required=True)  
  6.     date_modified = DateTimeField(default=datetime.datetime.now)  
     動態文檔綱要

    MongoDB的一個好處就是爲集合定義動態的綱要,這在有動態文檔的場景下能讓數據有組織,有計劃的存儲。 api

    動態文檔與通常文檔的工做方式同樣,可是任何爲它們設置的數據或屬性也會被存儲 app

[python] 
  1. from mongoengine import *  
  2.   
  3. class Page(DynamicDocument):  
  4.     title = StringField(max_length=200, required=True)  
  5.   
  6. # Create a new page and add tags  
  7. >>> page = Page(title='Using MongoEngine')  
  8. >>> page.tags = ['mongodb''mongoengine']a>>> page.save()  
  9.   
  10. >>> Page.objects(tags='mongoengine').count()  
  11. >>> 1  

    

    字段 ide

    在默認狀況下,字段能夠不須要。讓一個字段強制存在,能夠將這個字段的 require 關鍵字設置爲 true 。字段也能夠有驗證限制。字段也能夠設置默認值,在字段沒有被提供值的時候會用到。可使用的字段類型以下: 函數

    字段參數

    db_field(default: None) post

        mongodb字段名 ui

    name(default: None)

       mongoengine字段名

    required(default: False)

       若是設置爲True,那麼在存儲數據的時候,若是這個字段爲空,在驗證的時候會產生ValidateError。

    default(default: None)

       爲字段設置默認值。

       default這個參量的定義是遵循 the general rules on Python,實例以下:

[python] 
  1. class ExampleFirst(Document):  
  2.     # Default an empty list  
  3.     values = ListField(IntField(), default=list)  
  4.   
  5. class ExampleSecond(Document):  
  6.     # Default a set of values  
  7.     values = ListField(IntField(), default=lambda: [1,2,3])  
  8.   
  9. class ExampleDangerous(Document):  
  10.     # This can make an .append call to  add values to the default (and all the following objects),  
  11.     # instead to just an object  
  12.     values = ListField(IntField(), default=[1,2,3])  
    unique(default: False)

       若是設置爲True,那麼同一個collection裏面不能有一個document與它的值相同。

    unique_with(default: None)

       讓一個字段與該字段一同設置爲unique

    primary_key(default: False)

        若是設置爲True,那麼這個字段被設置爲主鍵。

    choices(default: None)

       當字段的值須要限制的時候設置一個可迭代的list或者tuple,也能夠是一個嵌套的tuple。

    

[python]
  1. SIZE = (('S''Small'),  
  2.         ('M''Medium'),  
  3.         ('L''Large'),  
  4.         ('XL''Extra Large'),  
  5.         ('XXL''Extra Extra Large'))  
  6.   
  7.   
  8. class Shirt(Document):  
  9.     size = StringField(max_length=3, choices=SIZE)  
或者只包含值的也能夠
[python]
  1. SIZE = ('S''M''L''XL''XXL')  
  2.   
  3. class Shirt(Document):  
  4.     size = StringField(max_length=3, choices=SIZE)  

    help_text(default: None)

      在使用這個字段的時候輸出幫助---在使用表單的時候用到。

    verbose_name(default: None)

      爲這個字段起更能讓人接受的名字---在使用表單的時候用到。

列表字段

mongodb裏面容許你存儲list。給document添加一個list字段,使用ListField類型,ListField把另外一個類型的對象做爲它的第一個參數,用來指定在list裏面存儲的數據類型。

[python]
  1. class Page(Document):  
  2.     tags = ListField(StringField(max_length=50))  
嵌入的document
mongodb可以存儲嵌入的document。須要爲這些document定義Schemata,它們也是規範的document。

定義嵌入的document的時候,像往常同樣定義一個document,可是要繼承EmbeddedDocument而不是Document

[python]
  1. class Comment(EmbeddedDocument):  
  2.     content = StringField()  
在document中嵌入另外一個document,使用   EmbeddedDocumentField 類型。第一個參數是嵌入document的類:

[python]
  1. class Page(Document):  
  2.     comments = ListField(EmbeddedDocumentField(Comment))  
  3.   
  4. comment1 = Comment(content='Good work!')  
  5. comment2 = Comment(content='Nice article!')  
  6. page = Page(comments=[comment1, comment2])  

字典字段
一般,會使用嵌入document來代替字典----總的來講字典不支持任何類型檢查與約束。但是,有時候你不知道你想存儲的數據是什麼類型,這時候使用   DictField會比較合適:

[python]
  1. class SurveyResponse(Document):  
  2.     date = DateTimeField()  
  3.     user = ReferenceField(User)  
  4.     answers = DictField()  
  5.   
  6. survey_response = SurveyResponse(date=datetime.now(), user=request.user)  
  7. response_form = ResponseForm(request.POST)  
  8. survey_response.answers = response_form.cleaned_data()  
  9. survey_response.save()  

引用字段

引用字段用來引用在數據庫裏面存儲的其餘document,使用 ReferenceField  ,在構造器中把另外一個document的類做爲第一個參數,而後就能夠簡單地指定document到這個字段。

[python]
  1. class User(Document):  
  2.     name = StringField()  
  3.   
  4. class Page(Document):  
  5.     content = StringField()  
  6.     author = ReferenceField(User)  
  7.   
  8. john = User(name="John Smith")  
  9. john.save()  
  10.   
  11. post = Page(content="Test Page")  
  12. post.author = john  
  13. post.save()  
User對象自動成爲了引用類,在檢索Page的時候會間接引用User。

當引用字段引用的是自身的時候,在ReferenceField 的構造器中添加 'self' 做爲它的參數,若是引用還未定義的document,則使用應用類的類名做爲構造器參數:

[python]
  1. class Employee(Document):  
  2.     name = StringField()  
  3.     boss = ReferenceField('self')  
  4.     profile_page = ReferenceField('ProfilePage')  
  5.   
  6. class ProfilePage(Document):  
  7.     content = StringField()  

使用ListField的一對多   
若是你想利用一個引用的list來實現一對多,那麼引用會被存儲成  DBRefs ,那麼須要查詢的時候,你也須要經過這個對象來進行查詢。

[python]
  1. class User(Document):  
  2.     name = StringField()  
  3.   
  4. class Page(Document):  
  5.     content = StringField()  
  6.     authors = ListField(ReferenceField(User))  
  7.   
  8. bob = User(name="Bob Jones").save()  
  9. john = User(name="John Smith").save()  
  10.   
  11. Page(content="Test Page", authors=[bob, john]).save()  
  12. Page(content="Another Page", authors=[john]).save()  
  13.   
  14. # Find all pages Bob authored  
  15. Page.objects(authors__in=[bob])  
  16.   
  17. # Find all pages that both Bob and John have authored  
  18. Page.objects(authors__all=[bob, john])  

處理刪除引用的document

默認狀況下,mongodb不會檢查數據的完整性,若是刪除了其餘document正在引用的document會引起一致性的問題。mongoengine的ReferenceField 添加了一些功能來維持數據一致性,爲沒一個引用提供了刪除規則。刪除規則經過聲明ReferenceField 的reverse_delete_rule 屬性來指定,就像這樣:

[python]
  1. class Employee(Document):  
  2.     ...  
  3.     profile_page = ReferenceField('ProfilePage', reverse_delete_rule=mongoengine.NULLIFY)  
這個例子中的聲明定義了若是一個Employee對象刪除,與它關聯的ProfilePage也會刪除。若是一批Employee對象被刪除,那麼與它關聯的ProfilePage也會被刪除。

它的值也能夠被設置成以下的常量:

mongoengine.DO_NOTHING

    這是默認值不作任何事。在刪除的時候速度比較快,可是會帶來數據不一致和空引用的問題。

mongoengine.DENY

    若是仍有document引用到這個對象,那麼會阻止刪除

mongoengine.NULLIFY    

         任何對象的字段關聯到這個對象的若是被刪除,那麼這個document也會被刪除,關聯關係做廢。

mongoengine.CASCADE

         任何對象的字段引用到這個對象的會被先刪除

mongoengine.PULL

        移除對於對象的引用關係

通用引用字段

一種次選的引用字段也是存在的, GenericReferenceField 。它可讓你引用任何類型的document,所以它不用其餘document的類來做爲它的參數:

[python]
  1. class Link(Document):  
  2.     url = StringField()  
  3.   
  4. class Post(Document):  
  5.     title = StringField()  
  6.   
  7. class Bookmark(Document):  
  8.     bookmark_object = GenericReferenceField()  
  9.   
  10. link = Link(url='http://hmarr.com/mongoengine/')  
  11. link.save()  
  12.   
  13. post = Post(title='Using MongoEngine')  
  14. post.save()  
  15.   
  16. Bookmark(bookmark_object=link).save()  
  17. Bookmark(bookmark_object=post).save()  
惟一性約束
mongoengine裏面容許你制定字段在collection裏面的值是惟一的,經過在構造器裏面指定  unique=True

若是你想在數據庫裏存儲已存在的value的document,會引起OperationError。你也能夠經過使用unique_with來設置多字段的惟一性約束,它的值能夠是一個字段名,或者是存儲了字段名的list或tuple。

[python]
  1. class User(Document):  
  2.     username = StringField(unique=True)  
  3.     first_name = StringField()  
  4.     last_name = StringField(unique_with='first_name')  

在保存時跳過document驗證

你能夠在使用save()的時候經過設置validate=False 來在保存的時候跳過驗證

[python]
  1. class Recipient(Document):  
  2.     name = StringField()  
  3.     email = EmailField()  
  4.   
  5. recipient = Recipient(name='admin', email='root@localhost ')  
  6. recipient.save()               # will raise a ValidationError while  
  7. recipient.save(validate=False# won't  
Document Collection

document對象是直接繼承於Document ,會在數據庫裏面擁有它們本身的collection。這個collection的名字默認就是類的名字,被轉化成了小寫。若是你想改變這個collection的名字,能夠在類裏面建立一個字典屬性叫meta,而後能夠隨意設置這個collection的名字了。  

[python]
  1. class Page(Document):  
  2.     title = StringField(max_length=200, required=True)  
  3.     meta = {'collection''cmsPage'}  
索引
你能夠在document裏面指定索引來使查詢的時候速度更快。這個能夠經過在meta字典裏聲明一個叫鍵爲 'indexes', 值爲存放索引規則的list的鍵值對來實現,一個索引規則能夠是一個字段名,或者是由幾個字段名組成的tuple,也能夠是一個包含完整索引聲明的字典。能夠在字段名前面加上+ 或者-來指定索引的順序。這隻會在聯合索引中有效果。

[python]
  1. class Page(Document):  
  2.     title = StringField()  
  3.     rating = StringField()  
  4.     meta = {  
  5.         'indexes': ['title', ('title''-rating')]  
  6.     }  
meta字典中還有一下的選項可選:

fields (Default: None)
        產生索引的字段,聲名的方法與以上同樣。

types (Default: True)

        索引是否應該添加 _type字段

sparse (Default: False)

        索引是否須要備份

unique (Default: False)

        索引是否須要備份

地理空間索引

地理空間索引會自動爲全部的 GeoPointField  建立。 

也能夠來明確地指定地理空間索引。這在你須要定義一個 DictField  的子域或者本身定製的包含一個點的字段的索引的時候頗有用。建立地理空間索引的時候須要在字段名前面加 *:
[python]
  1. class Place(Document):  
  2.     location = DictField()  
  3.     meta = {  
  4.         'indexes': [  
  5.             '*location.point',  
  6.         ],  
  7.     }  
順序
在meta裏面設置ordering的值能夠指定你的 QuerySet  的默認順序。在   QuerySet 被建立的時候順序規則會被應用 ,它也能夠經過使用   order_by()  來複寫。
[python]
  1. from datetime import datetime  
  2.   
  3. class BlogPost(Document):  
  4.     title = StringField()  
  5.     published_date = DateTimeField()  
  6.   
  7.     meta = {  
  8.         'ordering': ['-published_date']  
  9.     }  
  10.   
  11. blog_post_1 = BlogPost(title="Blog Post #1")  
  12. blog_post_1.published_date = datetime(20101500 ,0)  
  13.   
  14. blog_post_2 = BlogPost(title="Blog Post #2")  
  15. blog_post_2.published_date = datetime(20101600 ,0)  
  16.   
  17. blog_post_3 = BlogPost(title="Blog Post #3")  
  18. blog_post_3.published_date = datetime(20101700 ,0)  
  19.   
  20. blog_post_1.save()  
  21. blog_post_2.save()  
  22. blog_post_3.save()  
  23.   
  24. # get the "first" BlogPost using default ordering  
  25. # from BlogPost.meta.ordering  
  26. latest_post = BlogPost.objects.first()  
  27. assert latest_post.title == "Blog Post #3"  
  28.   
  29. # override default ordering, order BlogPosts by "published_date"  
  30. first_post = BlogPost.objects.order_by("+published_date").first()  
  31. assert first_post.title == "Blog Post #1"  
共享鍵
若是你的collection是共享的,那麼你須要指定一個存儲共享鍵的tuple, 使用 mongoengine.Document.meta裏面的shard_key屬性,
[python]
  1. class LogEntry(Document):  
  2.     machine = StringField()  
  3.     app = StringField()  
  4.     timestamp = DateTimeField()  
  5.     data = StringField()  
  6.   
  7.     meta = {  
  8.         'shard_key': ('machine''timestamp',)  
  9.     }  
Document繼承
爲了建立一個你定義的類型的document,你必須繼承document而且加上一些你須要的字段和方法。若是這不是一個直接繼承document的子類,那麼這個類的數據不會存放在本身的collection中,而會存放在它的父類的collection裏面。這能在檢索關聯的document的時候提供更多的方便。
[python]
  1. # Stored in a collection named 'page'  
  2. class Page(Document):  
  3.     title = StringField(max_length=200, required=True)  
  4.   
  5.     meta = {'allow_inheritance'True}  
  6.   
  7. # Also stored in the collection named 'page'  
  8. class DatedPage(Page):  
  9.     date = DateTimeField()  
處理現有的數據
爲了改正這種層次的document涉及的檢索,在數據庫裏面的document會存儲另兩個屬性:_cls 和 _types。這些在mongoengine的接口中對用戶是隱藏的,可能在使用mongoengine處理一個已經存在的數據庫的時候不會呈現出來。你可能會須要禁止這個類的繼承,方法以下:
[python]
  1. # Will work with data in an existing collection named 'cmsPage'  
  2. class Page(Document):  
  3.     title = StringField(max_length=200, required=True)  
  4.     meta = {  
  5.         'collection''cmsPage',  
  6.         'allow_inheritance'False,  
  7.     }  
相關文章
相關標籤/搜索