Modeling¶
MotorEngine uses the concept of models to interact with MongoDB. To create a model we inherit from the Document class:
-
class
motorengine.document.
Document
(_is_partly_loaded=False, _reference_loaded_fields=None, **kw) Base class for all documents specified in MotorEngine.
Let’s say we need an article model with title, description and published_date:
from motorengine.document import Document
from motorengine.fields import StringField, DateTimeField
class Article(Document):
title = StringField(required=True)
description = StringField(required=True)
published_date = DateTimeField(auto_now_on_insert=True)
That allows us to create, update, query and remove articles with extreme ease:
new_title = "Better Title %s" % uuid4()
def create_article():
Article.objects.create(
title="Some Article",
description="This is an article that really matters.",
callback=handle_article_created
)
def handle_article_created(article):
article.title = new_title
article.save(callback=handle_article_updated)
def handle_article_updated(article):
Article.objects.filter(title=new_title).find_all(callback=handle_articles_loaded)
def handle_articles_loaded(articles):
assert len(articles) == 1
assert articles[0].title == new_title
articles[0].delete(callback=handle_article_deleted)
def handle_article_deleted(number_of_deleted_items):
try:
assert number_of_deleted_items == 1
finally:
io_loop.stop()
io_loop.add_timeout(1, create_article)
io_loop.start()
Base Field¶
-
class
motorengine.fields.base_field.
BaseField
(db_field=None, default=None, required=False, on_save=None, unique=None, sparse=False)¶ This class is the base to all fields. This is not supposed to be used directly in documents.
Available arguments:
- db_field - The name this field will have when sent to MongoDB
- default - The default value (or callable) that will be used when first creating an instance that has no value set for the field
- required - Indicates that if the field value evaluates to empty (using the is_empty method) a validation error is raised
- on_save - A function of the form lambda doc, creating that is called right before sending the document to the DB.
- unique - Indicates whether an unique index should be created for this field.
- sparse - Indicates whether a sparse index should be created for this field. This also will not pass empty values to DB.
To create a new field, four methods can be overwritten:
- is_empty - Indicates that the field is empty (the default is comparing the value to None);
- validate - Returns if the specified value for the field is valid;
- to_son - Converts the value to the BSON representation required by motor;
- from_son - Parses the value from the BSON representation returned from motor.
Available Fields¶
-
class
motorengine.fields.string_field.
StringField
(max_length=None, *args, **kw)¶ Field responsible for storing text.
Usage:
name = StringField(required=True, max_length=255)
Available arguments (apart from those in BaseField):
- max_length - Raises a validation error if the string being stored exceeds the number of characters specified by this parameter
-
class
motorengine.fields.datetime_field.
DateTimeField
(auto_now_on_insert=False, auto_now_on_update=False, tz=None, *args, **kw)¶ Field responsible for storing dates.
Usage:
date = DateTimeField(required=True, auto_now_on_insert=True, auto_now_on_update=True)
Available arguments (apart from those in BaseField):
- auto_now_on_insert - When an instance is created sets the field to datetime.now()
- auto_now_on_update - Whenever the instance is saved the field value gets updated to datetime.now()
- tz - Defines the timezone used for auto_now_on_insert and auto_now_on_update and should be enforced on all
- values of this datetime field. To interpret all times as UTC use tz=datetime.timezone.utc (Defaults: to None, which means waht you put in comes out again)
-
class
motorengine.fields.uuid_field.
UUIDField
(db_field=None, default=None, required=False, on_save=None, unique=None, sparse=False)¶ Field responsible for storing
uuid.UUID
.Usage:
name = UUIDField(required=True)
-
class
motorengine.fields.url_field.
URLField
(db_field=None, default=None, required=False, on_save=None, unique=None, sparse=False)¶ Field responsible for storing URLs.
Usage:
name = URLField(required=True)
Available arguments (apart from those in BaseField): None
Note
MotorEngine does not implement the verify_exists parameter as MongoEngine due to async http requiring the current io_loop.
-
class
motorengine.fields.email_field.
EmailField
(db_field=None, default=None, required=False, on_save=None, unique=None, sparse=False)¶ Field responsible for storing e-mail addresses.
Usage:
name = EmailField(required=True)
Available arguments (apart from those in BaseField): None
-
class
motorengine.fields.int_field.
IntField
(min_value=None, max_value=None, *args, **kw)¶ Field responsible for storing integer values (
int()
).Usage:
name = IntField(required=True, min_value=0, max_value=255)
Available arguments (apart from those in BaseField):
- min_value - Raises a validation error if the integer being stored is lesser than this value
- max_value - Raises a validation error if the integer being stored is greather than this value
-
class
motorengine.fields.boolean_field.
BooleanField
(*args, **kw)¶ Field responsible for storing boolean values (
bool()
).Usage:
isActive = BooleanField(required=True)
BooleanField has no additional arguments available (apart from those in BaseField).
-
class
motorengine.fields.float_field.
FloatField
(min_value=None, max_value=None, *args, **kw)¶ Field responsible for storing floating-point values (
float()
).Usage:
name = FloatField(required=True, min_value=0.1, max_value=255.6)
Available arguments (apart from those in BaseField):
- min_value - Raises a validation error if the float being stored is lesser than this value
- max_value - Raises a validation error if the float being stored is greather than this value
-
class
motorengine.fields.decimal_field.
DecimalField
(min_value=None, max_value=None, precision=2, rounding='ROUND_HALF_UP', *args, **kw)¶ Field responsible for storing fixed-point decimal numbers (
decimal.Decimal
).Usage:
import decimal name = DecimalField(required=True, min_value=None, max_value=None, precision=2, rounding=decimal.ROUND_HALF_UP)
Available arguments (apart from those in BaseField):
min_value - Raises a validation error if the decimal being stored is lesser than this value
max_value - Raises a validation error if the decimal being stored is greather than this value
precision - Number of decimal places to store.
rounding - The rounding rule from the python decimal library:
- decimal.ROUND_CEILING (towards Infinity)
- decimal.ROUND_DOWN (towards zero)
- decimal.ROUND_FLOOR (towards -Infinity)
- decimal.ROUND_HALF_DOWN (to nearest with ties going towards zero)
- decimal.ROUND_HALF_EVEN (to nearest with ties going to nearest even integer)
- decimal.ROUND_HALF_UP (to nearest with ties going away from zero)
- decimal.ROUND_UP (away from zero)
- decimal.ROUND_05UP (away from zero if last digit after rounding towards zero would have been 0 or 5; otherwise towards zero)
Note
Decimal field stores the value as a string in MongoDB to preserve the precision.
-
class
motorengine.fields.binary_field.
BinaryField
(max_bytes=None, *args, **kwargs)¶ Field responsible for storing binary values.
Usage:
name = BinaryField(required=True)
Available arguments (apart from those in BaseField):
- max_bytes - The maximum number of bytes that can be stored in this field
-
class
motorengine.fields.json_field.
JsonField
(db_field=None, default=None, required=False, on_save=None, unique=None, sparse=False)¶ Field responsible for storing json objects.
Usage:
name = JsonField(required=True)
Available arguments (apart from those in BaseField): None
Note
If ujson is available, MotorEngine will try to use it. Otherwise it will fallback to the json serializer that comes with python.
-
class
motorengine.fields.objectid_field.
ObjectIdField
(db_field=None, default=None, required=False, on_save=None, unique=None, sparse=False)¶ Field responsible for storing object ids.
Usage:
objectid = ObjectIdField(required=True)
Multiple Value Fields¶
Embedding vs Referencing¶
Embedding is very useful to improve the retrieval of data from MongoDB. When you have sub-documents that will always be used when retrieving a document (i.e.: comments in a post), it’s useful to have them be embedded in the parent document.
On the other hand, if you need a connection to the current document that won’t be used in the main use cases for that document, it’s a good practice to use a Reference Field. MotorEngine will only load the referenced field if you explicitly ask it to, or if you set __lazy__ to False.
-
class
motorengine.fields.embedded_document_field.
EmbeddedDocumentField
(embedded_document_type=None, *args, **kw)¶ Field responsible for storing an embedded document.
Usage:
class Comment(Document): text = StringField(required=True) comment = EmbeddedDocumentField(embedded_document_type=Comment)
Available arguments (apart from those in BaseField):
- embedded_document_type - The type of document that this field accepts as an embedded document.
-
class
motorengine.fields.reference_field.
ReferenceField
(reference_document_type=None, *args, **kw)¶ Field responsible for creating a reference to another document.
Usage:
class User(Document): name = StringField(required=True) email = EmailField(required=True) owner = ReferenceField(reference_document_type=User)
Available arguments (apart from those in BaseField):
- reference_document_type - The type of document that this field accepts as a referenced document.