Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>I have invested a lot of time evaluating the popular Python ORMs for MongoDB. This was an exhaustive exercise, as I really wanted to pick one.</p> <p>My conclusion is that an ORM removes the fun out of MongoDB. None feels natural, they impose restrictions similar to the ones which made me move away from relational databases in the first place.</p> <p>Again, I really wanted to use an ORM, but now I am convinced that using <code>pymongo</code> directly is the way to go. Now, I follow a pattern which embraces MongoDB, <code>pymongo</code>, and Python. </p> <p>A Resource Oriented Architecture leads to very natural representations. For instance, take the following User resource:</p> <pre><code>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) </code></pre> <p>The <code>Resource</code> base class looks like</p> <pre><code>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) </code></pre> <p>Notice that I use the <code>WSGI</code> spec directly, and leverage <code>Werkzeug</code> where possible (by the way, I think that <code>Flask</code> adds an unnecessary complication to <code>Werkzeug</code>).</p> <p>The function <code>representation</code> takes the request's <code>Accept</code> headers, and produces a suitable representation (for example, <code>application/json</code>, or <code>text/html</code>). It is not difficult to implement. It also adds the <code>Last-Modified</code> header.</p> <p>Of course, your input needs to be sanitized, and the code, as presented, will not work (I mean it as an example, but it is not difficult to understand my point).</p> <p>Again, I tried everything, but this architecture made my code flexible, simple, and extensible.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload