# Copyright (c) 2011-2017, Dan Crosta # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # * Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. from flask import abort from pymongo import collection from pymongo import database from pymongo import mongo_client class MongoClient(mongo_client.MongoClient): """Wrapper for :class:`~pymongo.mongo_client.MongoClient`. Returns instances of Flask-PyMongo :class:`~flask_pymongo.wrappers.Database` instead of native PyMongo :class:`~pymongo.database.Database` when accessed with dot notation. """ def __getattr__(self, name): # noqa: D105 attr = super(MongoClient, self).__getattr__(name) if isinstance(attr, database.Database): return Database(self, name) return attr def __getitem__(self, item): # noqa: D105 attr = super(MongoClient, self).__getitem__(item) if isinstance(attr, database.Database): return Database(self, item) return attr class Database(database.Database): """Wrapper for :class:`~pymongo.database.Database`. Returns instances of Flask-PyMongo :class:`~flask_pymongo.wrappers.Collection` instead of native PyMongo :class:`~pymongo.collection.Collection` when accessed with dot notation. """ def __getattr__(self, name): # noqa: D105 attr = super(Database, self).__getattr__(name) if isinstance(attr, collection.Collection): return Collection(self, name) return attr def __getitem__(self, item): # noqa: D105 item_ = super(Database, self).__getitem__(item) if isinstance(item_, collection.Collection): return Collection(self, item) return item_ class Collection(collection.Collection): """Sub-class of PyMongo :class:`~pymongo.collection.Collection` with helpers. """ def __getattr__(self, name): # noqa: D105 attr = super(Collection, self).__getattr__(name) if isinstance(attr, collection.Collection): db = self._Collection__database return Collection(db, attr.name) return attr def __getitem__(self, item): # noqa: D105 item_ = super(Collection, self).__getitem__(item) if isinstance(item_, collection.Collection): db = self._Collection__database return Collection(db, item_.name) return item_ def find_one_or_404(self, *args, **kwargs): """Find a single document or raise a 404. This is like :meth:`~pymongo.collection.Collection.find_one`, but rather than returning ``None``, cause a 404 Not Found HTTP status on the request. .. code-block:: python @app.route("/user/") def user_profile(username): user = mongo.db.users.find_one_or_404({"_id": username}) return render_template("user.html", user=user) """ found = self.find_one(*args, **kwargs) if found is None: abort(404) return found