Welcome to OmMongo’s documentation!¶
Introduction¶
OmMongo is a layer on top of the Python MongoDB driver which adds client-side schema definitions, an easier to work with and programmatic query language, and a Document-Object mapper which allows python objects to be saved and loaded into the database in a type-safe way.
An explicit goal of this project is to be able to perform as many operations as possible without having to perform a load/save cycle since doing so is both significantly slower and more likely to cause data loss.
There’s more detail in the tutorial, but a small example is on this page below the contents of the documentation.
A Tour of OmMongo’s Features
Object-Document Mapping¶
Turn MongoDB documents into Python objects and vice-versa, add schemas and validatation to your models, and allow the separation of the python and mongo representations of your data.
- Support for all of the basic mongo types.
- Separate Python and Mongo names. Field and collection names can be overridden.
- Indexing on dict keys. MA provides a dict-like field which can have
arbitrary key and value types as well as allowing indexing on the keys —
not normally possible in Mongo. See:
KVField
- Computed values, generate from other fields.
See:
ComputedField
- Created and Modified fields based on the computed fields which record the date something was first created or last updated.
- Timezone support. A timezone can be passed using pytz and all dates will have timezone data attached and be converted to the given timezone.
- User-defined validation — Provide your own validation functions for
simple validations of fields. See
Field
- User-defined fields — For more customization, entirely new fields can be created
- A field that can hold arbitrary values:
AnythingField
- Validation happens at assignment time, so you’ll know exactly where
- Indexes are defined on the class
Sessions and Query Language¶
Type-safe queries. Queries are validated to make sure the values passed are allowed in the query fields.
Faux-Transactions. When using the session with the
with
statement updates are accumulated until the block is done, making it much less likely that a python error will leave your database in a bad state.Automatically Calculated Updates — The session object has an
ommongo.session.Session.update()
function which determines which fields are dirty and will execute the appropriate update operations to update the object in the database.Drop into raw Mongo. Most functions will accept raw pymongo instead of the ommongo objects. Type safety will be maintained either way
For example:
session.query('SomeClass').filter(SomeClass.name == foo).limit(5)
is perfectly valid, as is:
session.query(SomeClass).filter({'name':'foo'})
Installation¶
pip install OmMongo
You can also download the source code from the Python Package index or GitHub:
The source code is available at: https://github.com/bapakode/OmMongo
The PyPi page is located here: https://pypi.python.org/pypi/OmMongo/
Examples¶
>>> from ommongo.session import Session
>>> from ommongo.document import Document, Index
>>> from ommongo.fields import *
>>> # Subclasses of Document both provide the mapping needed for
... # queries as well as the classes for loading/saving objects.
... class User(Document):
... config_collection_name = 'users'
...
... # Setting the possible values by using fields
... first_name = StringField()
... last_name = StringField()
... age = IntField(min_value=0, required=False)
...
... # db_field allows a different DB field name than the one on the
... # python object
... email = StringField(db_field='email_address')
... bio = StringField(max_length=1000, required=False)
...
... # A computed field decorator allows values
... @computed_field(SetField(StringField()), deps=[bio])
... def keywords(obj):
... return set(obj.get('bio','').split(' '))
...
... kw_index = Index().ascending('keywords')
... name_index = Index().descending('first_name').ascending('last_name')
... email_index = Index().descending('email').unique()
...
... def __eq__(self, other):
... return self.email == other.email
...
... def __repr__(self):
... return 'User(email="%s")' % self.email
...
>>> me = User(first_name='Bapak', last_name='Kode', email='opensource@bapakode.org',
... bio='Bapakode is the author of OmMongo')
>>>
>>> me.keywords
set(['author', 'of', 'is', 'Bapakode', 'OmMongo', 'the'])
>>>
>>> # This connections to the DB and starts the session
... session = Session.connect('ommongo-intro')
>>> session.clear_collection(User) # clear previous runs of this code!
>>>
>>> # Insert on a session will infer the correct collection and push the object
... # into the database
... session.save(me)
>>> set(['author', 'of', 'is', 'Bapakode', 'OmMongo', 'the'])
>>>
>>> # Get a user with me's email address and OmMongo in their bio (via keywords)
... db_user = session.query(User).filter(User.email == 'opensource@bapakode.org').in_(User.keywords, 'OmMongo').one()
>>>
>>> db_user == me
True
>>>
>>> # Using filter_by for simple equality checking is easier
... session.query(User).filter_by(email='opensource@bapakode.org').in_(User.keywords, 'OmMongo').one()
User(email="opensource@bapakode.org")
>>>
>>> # It's also possible to do raw mongo filtering
... session.query(User).filter({'email':'opensource@bapakode.org', 'keywords':{'$in':['OmMongo']}}).one()
User(email="opensource@bapakode.org")
>>>