web-dev-qa-db-fra.com

MongoKit vs MongoEngine vs Flask-MongoAlchemy pour Flask

Quelqu'un a-t-il des expériences avec MongoKit, MongoEngine ou Flask-MongoAlchemy for Flask?

Lequel préfères-tu? Expériences positives ou négatives?. Trop d'options pour un Flask-Newbie.

71
r0sk

J'ai investi beaucoup de temps à évaluer les populaires ORM Python pour MongoDB. C'était un exercice exhaustif, car je voulais vraiment en choisir un.

Ma conclusion est qu'un ORM supprime le plaisir de MongoDB. Aucun ne semble naturel, ils imposent des restrictions similaires à celles qui m'ont fait m'éloigner des bases de données relationnelles en premier lieu.

Encore une fois, je voulais vraiment utiliser un ORM, mais maintenant je suis convaincu que l'utilisation de pymongo directement est la voie à suivre. Maintenant, je suis un modèle qui englobe MongoDB, pymongo et Python.

Une architecture orientée ressources conduit à des représentations très naturelles. Par exemple, prenez la ressource utilisateur suivante:

from werkzeug.wrappers import Response
from werkzeug.exceptions import NotFound

Users = pymongo.Connection("localhost", 27017)["mydb"]["users"]


class User(Resource):

    def GET(self, request, username):
        spec = {
            "_id": username,
            "_meta.active": True
        }
        # this is a simple call to pymongo - really, do
        # we need anything else?
        doc = Users.find_one(spec)
        if not doc:
            return NotFound(username)
        payload, mimetype = representation(doc, request.accept)
        return Response(payload, mimetype=mimetype, status=200)

    def PUT(self, request, username):
        spec = {
            "_id": username,
            "_meta.active": True
        }
        operation = {
            "$set": request.json,
        }
        # this call to pymongo will return the updated document (implies safe=True)
        doc = Users.update(spec, operation, new=True)
        if not doc:
            return NotFound(username)
        payload, mimetype = representation(doc, request.accept)
        return Response(payload, mimetype=mimetype, status=200)

La classe de base Resource ressemble à

class Resource(object):

    def GET(self, request, **kwargs):
        return NotImplemented()

    def HEAD(self, request, **kwargs):
        return NotImplemented()

    def POST(self, request, **kwargs):
        return NotImplemented()

    def DELETE(self, request, **kwargs):
        return NotImplemented()

    def PUT(self, request, **kwargs):
        return NotImplemented()

    def __call__(self, request, **kwargs):
        handler = getattr(self, request.method)
        return handler(request, **kwargs)

Notez que j'utilise la spécification WSGI directement et que je tire parti de Werkzeug si possible (d'ailleurs, je pense que Flask ajoute une complication inutile à Werkzeug) .

La fonction representation prend les en-têtes Accept de la requête et produit une représentation appropriée (par exemple, application/json, ou text/html). Ce n'est pas difficile à mettre en œuvre. Il ajoute également le Last-Modified entête.

Bien sûr, votre entrée doit être nettoyée et le code, tel que présenté, ne fonctionnera pas (je veux dire à titre d'exemple, mais il n'est pas difficile de comprendre mon point).

Encore une fois, j'ai tout essayé, mais cette architecture a rendu mon code flexible, simple et extensible.

83
Escualo