diff --git a/docs/patterns/index.rst b/docs/patterns/index.rst index 78a66a1d..2737d695 100644 --- a/docs/patterns/index.rst +++ b/docs/patterns/index.rst @@ -34,7 +34,7 @@ Snippet Archives `_. jquery errorpages lazyloading - mongokit + mongoengine favicon streaming deferredcallbacks diff --git a/docs/patterns/mongoengine.rst b/docs/patterns/mongoengine.rst new file mode 100644 index 00000000..61697171 --- /dev/null +++ b/docs/patterns/mongoengine.rst @@ -0,0 +1,140 @@ +.. mongoengine-pattern: + +MongoEngine in Flask +==================== + +Using a document database rather than a full DBMS gets more common these days. +This pattern shows how to use MongoEngine, a document mapper library, to +integrate with MongoDB. + +This pattern requires a running MongoDB server, MongoEngine_ and Flask-MongoEngine_ +libraries installed:: + + pip install flask-mongoengine + +.. _MongoEngine: http://mongoengine.org +.. _Flask-MongoEngine: http://docs.mongoengine.org/projects/flask-mongoengine/en/latest/>`_ + +Configuration +------------- + +Basic setup can be done by defining ``MONGODB_SETTINGS`` on App config and then +creating a ``MongoEngine`` instance:: + + from flask import Flask + from flask_mongoengine import MongoEngine + + app = Flask(__name__) + app.config['MONGODB_SETTINGS'] = { + 'host': "mongodb://localhost:27017/mydb" + } + db = MongoEngine(app) + + +Mapping Documents +----------------- + +To declare models that will represent your Mongo documents, just create a class that +inherits from ``Document`` and declare each of the fields:: + + from mongoengine import * + + + class Movie(Document): + + title = StringField(required=True) + year = IntField() + rated = StringField() + director = StringField() + actors = ListField() + +If the model has embedded documents, use ``EmbeddedDocument`` to defined the fields of +the embedded document and ``EmbeddedDocumentField`` to declare it on the parent document:: + + class Imdb(EmbeddedDocument): + + imdb_id = StringField() + rating = DecimalField() + votes = IntField() + + + class Movie(Document): + + ... + imdb = EmbeddedDocumentField(Imdb) + + +Creating Data +------------- + +Just create the objects and call ``save()``:: + + bttf = Movie(title="Back To The Future", year=1985) + bttf.actors = [ + "Michael J. Fox", + "Christopher Lloyd" + ] + bttf.imdb = Imdb(imdb_id="tt0088763", rating=8.5) + bttf.save() + + +Queries +------- + +Use the class ``objects`` attribute to make queries:: + + bttf = Movies.objects(title="Back To The Future").get() # Throw error if not unique + +``objects`` is an iterable. Query operators may be user by concatenating it with the document +key using a double-underscore:: + + some_theron_movie = Movie.objects(actors__in=["Charlize Theron"]).first() + + for recents in Movie.objects(year__gte=2017): + print(recents.title) + +Available operators are as follows: + +* ``ne`` -- not equal to +* ``lt`` -- less than +* ``lte`` -- less than or equal to +* ``gt`` -- greater than +* ``gte`` -- greater than or equal to +* ``not`` -- negate a standard check, may be used before other operators (e.g. + ``Q(age__not__mod=5)``) +* ``in`` -- value is in list (a list of values should be provided) +* ``nin`` -- value is not in list (a list of values should be provided) +* ``mod`` -- ``value % x == y``, where ``x`` and ``y`` are two provided values +* ``all`` -- every item in list of values provided is in array +* ``size`` -- the size of the array is +* ``exists`` -- value for field exists + +String queries +-------------- + +The following operators are available as shortcuts to querying with regular +expressions: + +* ``exact`` -- string field exactly matches value +* ``iexact`` -- string field exactly matches value (case insensitive) +* ``contains`` -- string field contains value +* ``icontains`` -- string field contains value (case insensitive) +* ``startswith`` -- string field starts with value +* ``istartswith`` -- string field starts with value (case insensitive) +* ``endswith`` -- string field ends with value +* ``iendswith`` -- string field ends with value (case insensitive) +* ``match`` -- performs an $elemMatch so you can match an entire document within an array + +Accessing PyMongo MongoClient +----------------------------- + +If, for some reason, you want to access PyMongo instance, use ``get_connection`` function:: + + from mongoengine.connection import get_connection + + conn = get_connection() + collection = conn.mydb.movie + collection({'title': u'Days of Thunder'}) + +For more information about MongoEngine, head over to the +`website `_. diff --git a/docs/patterns/mongokit.rst b/docs/patterns/mongokit.rst deleted file mode 100644 index 9d1b3e2a..00000000 --- a/docs/patterns/mongokit.rst +++ /dev/null @@ -1,144 +0,0 @@ -.. mongokit-pattern: - -MongoKit in Flask -================= - -Using a document database rather than a full DBMS gets more common these days. -This pattern shows how to use MongoKit, a document mapper library, to -integrate with MongoDB. - -This pattern requires a running MongoDB server and the MongoKit library -installed. - -There are two very common ways to use MongoKit. I will outline each of them -here: - - -Declarative ------------ - -The default behavior of MongoKit is the declarative one that is based on -common ideas from Django or the SQLAlchemy declarative extension. - -Here an example :file:`app.py` module for your application:: - - from flask import Flask - from mongokit import Connection, Document - - # configuration - MONGODB_HOST = 'localhost' - MONGODB_PORT = 27017 - - # create the little application object - app = Flask(__name__) - app.config.from_object(__name__) - - # connect to the database - connection = Connection(app.config['MONGODB_HOST'], - app.config['MONGODB_PORT']) - - -To define your models, just subclass the `Document` class that is imported -from MongoKit. If you've seen the SQLAlchemy pattern you may wonder why we do -not have a session and even do not define a `init_db` function here. On the -one hand, MongoKit does not have something like a session. This sometimes -makes it more to type but also makes it blazingly fast. On the other hand, -MongoDB is schemaless. This means you can modify the data structure from one -insert query to the next without any problem. MongoKit is just schemaless -too, but implements some validation to ensure data integrity. - -Here is an example document (put this also into :file:`app.py`, e.g.):: - - from mongokit import ValidationError - - def max_length(length): - def validate(value): - if len(value) <= length: - return True - # must have %s in error format string to have mongokit place key in there - raise ValidationError('%s must be at most {} characters long'.format(length)) - return validate - - class User(Document): - structure = { - 'name': unicode, - 'email': unicode, - } - validators = { - 'name': max_length(50), - 'email': max_length(120) - } - use_dot_notation = True - def __repr__(self): - return '' % (self.name) - - # register the User document with our current connection - connection.register([User]) - - -This example shows you how to define your schema (named structure), a -validator for the maximum character length and uses a special MongoKit feature -called `use_dot_notation`. Per default MongoKit behaves like a python -dictionary but with `use_dot_notation` set to ``True`` you can use your -documents like you use models in nearly any other ORM by using dots to -separate between attributes. - -You can insert entries into the database like this: - ->>> from yourapplication.database import connection ->>> from yourapplication.models import User ->>> collection = connection['test'].users ->>> user = collection.User() ->>> user['name'] = u'admin' ->>> user['email'] = u'admin@localhost' ->>> user.save() - -Note that MongoKit is kinda strict with used column types, you must not use a -common `str` type for either `name` or `email` but unicode. - -Querying is simple as well: - ->>> list(collection.User.find()) -[] ->>> collection.User.find_one({'name': u'admin'}) - - -.. _MongoKit: http://bytebucket.org/namlook/mongokit/ - - -PyMongo Compatibility Layer ---------------------------- - -If you just want to use PyMongo, you can do that with MongoKit as well. You -may use this process if you need the best performance to get. Note that this -example does not show how to couple it with Flask, see the above MongoKit code -for examples:: - - from MongoKit import Connection - - connection = Connection() - -To insert data you can use the `insert` method. We have to get a -collection first, this is somewhat the same as a table in the SQL world. - ->>> collection = connection['test'].users ->>> user = {'name': u'admin', 'email': u'admin@localhost'} ->>> collection.insert(user) - -MongoKit will automatically commit for us. - -To query your database, you use the collection directly: - ->>> list(collection.find()) -[{u'_id': ObjectId('4c271729e13823182f000000'), u'name': u'admin', u'email': u'admin@localhost'}] ->>> collection.find_one({'name': u'admin'}) -{u'_id': ObjectId('4c271729e13823182f000000'), u'name': u'admin', u'email': u'admin@localhost'} - -These results are also dict-like objects: - ->>> r = collection.find_one({'name': u'admin'}) ->>> r['email'] -u'admin@localhost' - -For more information about MongoKit, head over to the -`website `_.