前言:前期开发直接对数据库进行CRUD,越到后期发现越发现效果不佳,所以查了查有没有类似ORM操作的工具。
发现以下几种mongodb的ODM:
PyMODM
PyMODM是一个类似于ORM的框架,位于PyMongo之上。PyMODM由MongoDB,Inc。的工程师维护,并且很快就采用了新的MongoDB功能。PyMODM是一个“核心”ODM,这意味着它提供了简单,可扩展的功能,其他库可以利用它来定位Django等平台。同时,PyMODM功能强大,足以用于自己开发应用程序。除了用于讨论项目的Gitter通道外,还提供了有关readthedocs的完整文档。
Humongolus
Humongolus是Python和MongoDB的轻量级ORM框架。这个名字来自MongoDB和Homunculus的组合(一个微型但完全形成的人体的概念)。Humongolus允许您使用强大的验证来创建模型/模式。它试图尽可能地使用pythonic并尽可能地暴露pymongo游标对象。该代码可从GitHub下载 。GitHub也提供了教程和用法示例。
Ming
Ming(the Merciless)是一个库,允许您在Python应用程序中对MongoDB数据库强制执行模式。它是由SourceForge在迁移到MongoDB的过程中开发的。有关 更多详细信息,请参阅介绍性博客文章。
MongoEngine
MongoEngine是另一个类似于ORM的层,位于PyMongo之上。它允许您使用受Django ORM启发的语法为文档和查询集合定义模式。该代码可在GitHub上获得 ; 有关更多信息,请参阅教程。
MotorEngine
MotorEngine是MongoEngine到Motor的一个端口,用于与Tornado异步访问。它实现了相同的建模API以便于数据移植,这意味着可以在MotorEngine中读取MongoEngine中定义的模型。该源 可在GitHub上获得。
uMongo
uMongo是一个Python MongoDB ODM。它的出现源于两个需求:缺乏异步ODM以及使用现有ODM进行文档(un)序列化的难度。适用于多个驱动程序:PyMongo,TxMongo,motor_asyncio和mongomock。该源可在GitHub上获得
经过对比最终选择了PyMODM,因为它有mongo对比官方的工程师维护,而且跟Django的ORM非常一致(之前一直用Django来着)。
官方文档如下:
https://pymodm.readthedocs.io/en/latest/getting-started.html
文档的介绍还可以,但是更多的还是要去摸索。
ODM层无非就是定义模型,然后进行增删查改。
定义模型:
from pymodm.connection import connect
connect("mongodb://localhost:27017/myDatabase", alias="ODM")
from pymodm import MongoModel, EmbeddedMongoModel, fields
import pymongo, pymongo.collation
class Role(MongoModel):
role_name = fields.CharField()
weight = fields.IntegerField(min_value=1, max_value=100)
menu_items = fields.ListField(blank=True)
class Meta:
connection_alias = 'ODM'
collection_name = 'role'
class User(MongoModel):
name = fields.CharField()
password = fields.CharField()
contact = fields.CharField(blank=True, default='')
gender = fields.IntegerField(min_value=0, max_value=1)
role = fields.ReferenceField(Role, on_delete=ReferenceField.CASCADE)
class Meta:
connection_alias = 'ODM'
collection_name = 'user'
indexes = [
pymongo.IndexModel([('name', pymongo.ASCENDING)], collation=pymongo.collation.Collation('zh'))
]
connection_alias = 'ODM' 是链接的别名,可以直接用别名连接。
indexes: 建立索引,提高查询速度
模型的定义和Django的几乎一模一样,它的类型包括:
['CharField', 'IntegerField', 'BigIntegerField', 'ObjectIdField',
'BinaryField', 'BooleanField', 'DateTimeField', 'Decimal128Field',
'EmailField', 'FileField', 'ImageField', 'FloatField',
'GenericIPAddressField', 'URLField', 'UUIDField',
'RegularExpressionField', 'JavaScriptField', 'TimestampField',
'DictField', 'OrderedDictField', 'ListField', 'PointField',
'LineStringField', 'PolygonField', 'MultiPointField',
'MultiLineStringField', 'MultiPolygonField', 'GeometryCollectionField',
'EmbeddedDocumentField', 'EmbeddedDocumentListField', 'ReferenceField']
主要分享ReferenceField, ListField, EmbeddedDocumentListField
ReferenceField:
这个是引用,相当于“外键”,它的删除规则有5种:
-
on_delete
: The action to take (if any) when the referenced object
is deleted. The delete rule should be one of the following:
* :attr:ReferenceField.DO_NOTHING
(default).什么都不做(默认)
* :attr:ReferenceField.NULLIFY
更改引用已删除对象的字段None
* :attr:ReferenceField.CASCADE
级联删除:删除引用的对象时,递归删除引用它的所有对象
* :attr:ReferenceField.DENY
不允许删除仍然引用它们的对象
* :attr:ReferenceField.PULL
如果删除的对象只是存储在列表中的许多其他引用中的一个,请从此列表中删除引用
ListField:
这个储存的是列表,如果没有这个对象查出来是[]
EmbeddedDocumentListField:
class Student(EmbeddedMongoModel):
name = fields.CharField()
age= fields.IntegerField()
class Classe(MongoModel):
name= fields.CharField()
student_items = fields.EmbeddedDocumentListField(Student, blank=True)
EmbeddedDocumentListField这个储存的是对象,先生成Student对象,再添加到列表中,最后保存到student_items中。注:Student没有自己的“_id”,也不能直接查。
CRUD
官方文档上有,不说了。
单条查询用get比较好,他有两个报错:
try:
user = User.objects.get({'_id': user_id})
except User.DoesNotExist:
# Handle User not existing.
pass
except User.MultipleObjectsReturned:
pass
else:
return user
2019.03.29补充:
构建好的模型在两个文件之间无法直接import引用,其中一个需要用字符串方式引用,这样的话就无法利用本身的五种删除规则,这里pymodm提供了register_delete_rule
函数,可用于一对一及一对多的删除:
# 删除用户,作者置空
User.register_delete_rule(Book, 'creator',pymodm.fields.ReferenceField.NULLIFY)
# 删除用户,书籍直接删除
User.register_delete_rule(Book, 'creator',pymodm.fields.ReferenceField.CASCADE)
# 删除用户,判断有对应的书籍时不准删除用户
User.register_delete_rule(Book, 'creator',pymodm.fields.ReferenceField.DENY)
或者举例:
class User(MongoModel):
name = fields.CharField()
password = fields.CharField()
book_items = fields.ListField(fields.ReferenceField(Book), blank=True)
当删除图书时,book_items中对应的一项将会是None,手动删除又很麻烦,于是可以注册删除规则如下:
# 删除书籍,用户的书籍册中对应书籍删除
Book.register_delete_rule(User, "book_items", pymodm.fields.ReferenceField.PULL)
此时再删除书籍时,作者对应的book_items中直接删除对应项,nice!
再补充一点,联合查询小记:
books = list(Book.objects.aggregate(
{'$lookup': {'from': User.Meta.collection_name, 'localField': 'creator', 'foreignField': '_id',
'as': 'creator'}},
{'$match': {'$or': [search_condition, search_condition_name]}},
{'$sort': {'name':ASCENDING,'year': ASCENDING}}, collation={'locale': 'zh'}))
pymodm确实很不错!