Not Logged In

aiomongodel 0.1.0.dev0

An asynchronous ODM similar to PyMODM on top of Motor an asynchronous
Python MongoDB driver. Works on Python 3.5 and up. Some features
such as asynchronous comprehensions require at least Python 3.6. aiomongodel
can be used with asyncio as well as with Tornado.

Install

Install aiomongodel using pip:

pip install https://github.com/ilex/aiomongodel/archive/master.zip

Getting Start

Modeling

To create a model just create a new model class, inherit it from
aiomongodel.Document class, list all the model fields and place
a Meta class with model meta options. To create a subdocument, create
a class with fields and inherit it from aiomongodel.EmbeddedDocument.

# models.pyfromdatetimeimportdatetimefrompymongoimportIndexModel,DESCENDINGfromaiomongodelimportDocument,EmbeddedDocumentfromaiomongodel.fieldsimport(StrField,BoolField,ListField,EmbDocField,RefField,SynonymField,IntField,FloatField,DateTimeField,ObjectIdField)classUser(Document):_id=StrField(regex=r'[a-zA-Z0-9_]{3, 20}')is_active=BoolField(default=True)posts=ListField(RefField('models.Post'),default=lambda:list())quote=StrField(required=False)# create a synonym fieldname=SynonymField(_id)classMeta:collection='users'classPost(Document):# _id field will be added automatically as# _id = ObjectIdField(defalut=lambda: ObjectId())title=StrField(allow_blank=False,max_length=50)body=StrField()created=DateTimeField(default=lambda:datetime.utcnow())views=IntField(default=0)rate=FloatField(default=0.0)author=RefField(User,mongo_name='user')comments=ListField(EmbDocField('models.Comment'),default=lambda:list())classMeta:collection='posts'indexes=[IndexModel([('created',DESCENDING)])]default_sort=[('created',DESCENDING)]classComment(EmbeddedDocument):_id=ObjectIdField(default=lambda:ObjectId())author=RefField(User)body=StrField()# `s` property of the fields can be used to get a mongodb string name# to use in queriesassertUser._id.s=='_id'assertUser.name.s=='_id'# name is synonymassertPost.title.s=='title'assertPost.author.s=='user'# field has mongo_nameassertPost.comments.body.s=='comments.body'# compound name

CRUD

frommotor.motor_asyncioimportAsyncIOMotorClientasyncdefgo(db):# create model's indexesawaitUser.q(db).create_indexes()# CREATE# create using save# Note: if do_insert=False (default) save performs a replace# with upsert=True, so it does not raise if _id already exists# in db but replace document with that _id.u=awaitUser(name='Alexandro').save(db,do_insert=True)assertu.name=='Alexandro'assertu._id=='Alexandro'assertu.is_activeisTrueassertu.posts==[]assertu.quoteisNone# create using createu=awaitUser.create(db,name='Francesco')# using queryu=awaitUser.q(db).create(name='Ihor',is_active=False)# READ# get by idu=awaitUser.q(db).get('Alexandro')assertu.name=='Alexandro'# findusers=awaitUser.q(db).find({User.is_active.s:True}).to_list(10)assertlen(users)==2# using for loopusers=[]asyncforuserinUser.q(db).find({User.is_active.s:False}):users.append(user)assertlen(users)==1# in Python 3.6 an up use async comprehensionsusers=[userasyncforuserinUser.q(db).find({})]assertlen(users)==3# UPDATEu=awaitUser.q(db).get('Ihor')u.is_active=Trueawaitu.save(db)assert(awaitUser.q(db).get('Ihor')).is_activeisTrue# using update (without data validation)# object is reloaded from db after update.awaitu.update(db,{'$push':{User.posts.s:ObjectId()}})# DELETEu=awaitUser.q(db).get('Ihor')awaitu.delete(db)loop=asyncio.get_event_loop()client=AsyncIOMotorClient(io_loop=loop)db=client.aiomongodel_testloop.run_until_complete(go(db))

Validation

Use model’s validate method to validate model’s data. If
there are any invalid data an aiomongodel.errors.ValidationError
will raise.

Note

Creating model object or assigning it with invalid data does
not raise errors! Be careful while saving model without validation.

classModel(Document):name=StrField(max_length=7)value=IntField(gt=5,lte=13)data=FloatField()defgo():m=Model(name='xxx',value=10,data=1.6)# validate data# should not raise any errorm.validate()# invalid data# note that there are no errors while creating# model with invalid datainvalid=Model(name='too long string',value=0)try:invalid.validate()exceptaiomongodel.errors.ValidationErrorase:asserte.as_dict()=={'name':'length is greater than 7','value':'value should be greater than 5','data':'field is required'}# using translation - you can translate messages# to your language or modify themtranslation={"field is required":"This field is required","length is greater than {constraint}":("Length of the field ""is greater than ""{constraint} characters"),# see all error messages in ValidationError docs# for missed messages default messages will be used}asserte.as_dict(translation=translation)=={'name':'Length of the field is greater than 7 characters','value':'value should be greater than 5','data':'This field is required'}

Models Inheritance

A hierarchy of models can be built by inheriting one model from another.
A aiomongodel.Document class should be somewhere in hierarchy for model
adn aiomongodel.EmbeddedDocument for subdocuments.
Note that fields are inherited but meta options are not.

classMixin:value=IntField()classParent(Document):name=StrField()classChild(Mixin,Parent):# also has value and name fieldsrate=FloatField()classOtherChild(Child):# also has rate and name fieldsvalue=FloatField()# overwrite value field from MixinclassSubDoc(Mixin,EmbeddedDocument):# has value fieldpass