关于非关系型数据库与关系型数据库在数据库(文档)或者表(集合)结构上的定义——the principal difference is that no schema is enforced at a database level(主要区别在于非关系型数据库在数据库级别没有被强制使用视图).
定义一个基础文档视图
To define a schema for a document, create a class that inherits from Document. Fields are specified by adding field objects as class attributes to the document class(创建一个继承了Document的模型类即可,然后为期添加字段属性)
假设我们在一个项目中实例化了MongoEngine:
db = MongoEngine()
然后我们在一个模型文件中去定义文档视图:
注意:field类型在定义文档视图的时候要正确选择
from app import db
class User(db.Document):
username = db.StringField(max_length=255, required=True)
email = db.EmailField(max_length=255)
password_hash = db.StringField(required=True)
create_time = db.DateTimeField(default=datetime.datetime.now, required=True)
last_login = db.DateTimeField(default=datetime.datetime.now, required=True)
is_email_confirmed = db.BooleanField(default=False)
Dynamic document schemas(动态文档视图)
DynamicDocument documents work in the same way as Document but any data / attributes set to them will also be saved(动态文档基本工作原理和和普通文档一样,只是在文档定义范围外被设置的属性也会保存在数据库中)
class Page(DynamicDocument):
title = StringField(max_length=200, required=True)
注意:
There is one caveat on Dynamic Documents: fields cannot start with _
Embedded documents(动态文档类型)
MongoDB has the ability to embed documents within other documents. Schemata may be defined for these embedded documents, just as they may be for regular documents. To create an embedded document, just define a document as usual, but inherit from EmbeddedDocument rather than Document(内嵌文档定义的时候继承的是EmbeddedDocument 而不是Document)
class Comment(EmbeddedDocument):
content = StringField()
class Page(Document):
comments = ListField(EmbeddedDocumentField(Comment))
title = StringField(max_length=200, required=True)
Skipping Document validation on save
page.save(validate=False) # won't
Document collections(文档集合设置)
Document classes that inherit directly from Document will have their own collection in the database. The name of the collection is by default the name of the class, converted to lowercase (so in the example above, the collection would be called page). If you need to change the name of the collection (e.g. to use MongoEngine with an existing database), then create a class dictionary attribute called meta on your document, and set collection to the name of the collection that you want your document class to use:
默认创建的模型类名就是集合名称的小写形式,如果想要改变集合的名称你就需要在类中创建一个类字典属性meta,然后设置你的集合名称,如下:
class Page(Document):
title = StringField(max_length=200, required=True)
meta = {'collection': 'cmsPage'}
Capped collections(设限的集合)
A Document may use a Capped Collection by specifying max_documents and max_size in the meta dictionary. max_documents is the maximum number of documents that is allowed to be stored in the collection, and max_size is the maximum size of the collection in bytes. max_size is rounded up to the next multiple of 256 by MongoDB internally and mongoengine before. Use also a multiple of 256 to avoid confusions. If max_size is not specified and max_documents is, max_size defaults to 10485760 bytes (10MB). The following example shows a Log document that will be limited to 1000 entries and 2MB of disk space,
通过在模型类的meta属性中定义max_documents以及max_size我们可以限制集合存储的记录数以及字节数,以下例子就是限制集合的记录数为1000,字节数2MB:
class Log(Document):
ip_address = StringField()
meta = {'max_documents': 1000, 'max_size': 2000000}
Indexes(索引)
You can specify indexes on collections to make querying faster. This is done by creating a list of index specifications called indexes in the meta dictionary, where an index specification may either be a single field name, a tuple containing multiple field names, or a dictionary containing a full index definition.
我们可以在模型类的meta字典属性中定义indexes来创建索引使得查询更快
class Page(Document):
category = IntField()
title = StringField()
rating = StringField()
created = DateTimeField()
meta = {
'indexes': [
'title',
'$title', # text index
'#title', # hashed index
('title', '-rating'),
('category', '_cls'),
{
'fields': ['created'],
'expireAfterSeconds': 3600
}
]
}
Ordering(排序)
A default ordering can be specified for your QuerySet using the ordering attribute of meta. Ordering will be applied when the QuerySet is created, and can be overridden by subsequent calls to order_by().
class BlogPost(Document):
title = StringField()
published_date = DateTimeField()
meta = {
'ordering': ['-published_date']
}
Shard keys (分片关键字)
If your collection is sharded, then you need to specify the shard key as a tuple, using the shard_key attribute of meta. This ensures that the shard key is sent with the query when calling the save() or update() method on an existing Document instance:
class LogEntry(Document):
machine = StringField()
app = StringField()
timestamp = DateTimeField()
data = StringField()
meta = {
'shard_key': ('machine', 'timestamp',)
}
Document inheritance(文档继承)
To create a specialised type of a Document you have defined, you may subclass it and add any extra fields or methods you may need. As this is new class is not a direct subclass of Document, it will not be stored in its own collection; it will use the same collection as its superclass uses. This allows for more convenient and efficient retrieval of related documents – all you need do is set allow_inheritance to True in the meta data for a document.:
# Stored in a collection named 'page'
class Page(Document):
title = StringField(max_length=200, required=True)
meta = {'allow_inheritance': True}
# Also stored in the collection named 'page'
class DatedPage(Page):
date = DateTimeField()