RethinkORM is a small wrapper class to help make working with documents in RethinkDB easier, and in a more Pythonic way.
When I found RethinkDB, I was amazed at how easy everything seemed to be, however one thing that I missed was how the data was just a Python list or dict rather than a full wrapper class. So I figured a good way to learn the general use of the Python RethinkDB driver was to write a general wrapper class that functioned a bit like an ORM, providing some easier to work with data and objects.
Changes from Version 0.2.0¶
- Relicensed from GPL v3 to MIT.
- Several names have changed, primarially: protectedItems is now protected_items, primaryKey is now primary_key, orderBy in collections is now order_by. There are probably others that I’m missing however.
- The ability to join tables or models within a collection have been removed for now (it was mostly broken anyways).
- The find classmethod on models has been removed (For now, until I come up with a better way of doing this).
- fromRawEntry is not outdated, and can be replaced by just instantiating a new model with the data.
- The models no longer keep track of if a document is new and just use the RethinkDB drivers upsert ability to insert or update a document.
- Passing a key and data will now no longer raise an exception, but instead return a new model.
- Providing only id as a keyword argument to the model will cause it to assume the document is in the database, and it will attempt to get that document.
pip install RethinkORM
This library provides the RethinkModel class which provides a base class that works as a mapper between a rethink document and a Python object, along with the RethinkCollection class to represent a group of documents which match a ReQL query.
First, lets setup the basic rethink connection and get a sample database and table made. I choose to go with this pattern, providing an option for passing the connection object into the models, because I don’t quite like the ORMs which try to fully replace the underlying driver. This also gives a nice easy way to use standard ReQL for operations that are beyond the scope of what these models are for.
>>> import rethinkdb as r >>> from rethinkORM import RethinkModel >>> from rethinkORM import RethinkCollection >>> conn = r.connect('localhost', 28015) >>> a = r.db_create("example").run(conn) >>> conn.use("example") >>> conn.repl() <rethinkdb.net.Connection ...>
>>> a = r.table_create("stargates").run()
Now we can create a model that we’ll be working with.
>>> class Stargate(RethinkModel): ... table = "stargates"
And now we can create an actual document using this model. Create is a classmethod that will return a new Stargate object with the ID of the newly created document, with the passed data. In this case: location, and description.
>>> earth_gate = Stargate.create(location="Earth", description="The first of two gates found on earth. Found in Egypt")
If you do not call .repl() on the rethink connection, you can also pass conn to the model like so:
>>> earth_gate = Stargate.create(location="Earth", description="The first of two gates found on earth. Found in Egypt", connection=conn)
If you did not want to immediately save the document upon creation you can instead call the .new() classmethod:
>>> atlantis_gate = Stargate.new(location="City of Atlantis", description="The gate in the gate room of the lost city of the ancients, reached from Earth by using a ZPM and dialling an additional 9th symbol.")
You can then make changes to this document, and when you are finished, call .save() which will save the document and set the objects ID to the newly created documents ID.
>>> atlantis_gate.save() True
Getting a collection of documents is also easy through the use of RethinkCollection. Simply give RethinkCollection the classref of your model, in our case Stargate and look at the documents property. This will fetch all of the documents within the table defined by the Stargate model (the stargates table in this case). RethinkCollection also provides several helpers such as accepting a pre built ReQL query, limiting of results, sorting the documents and filtering them based off of field values.
>>> gates = RethinkCollection(Stargate) >>> gates.documents [<RethinkModel ...>, <RethinkModel ...>]
>>> a = r.db_drop("example").run()
A Few Minor Warnings¶
- I am a second year university student working towards a Computer Engineering degree, so not only do I have limited time to keep this maintained, but I also probably won’t write the best code ever.
- This takes some influence from the Python Django RethinkDB ORM and other ORM systems, however I haven’t really followed a standard pattern for the interface for this module. If someone wants to make this more standardized feel free to, and just submit a pull request, I’ll look it over and probably will give it the go ahead. For more information see below.
- While this is now on its second major version, the code is still maturing a bit so chances are stuff will still break. Again, see below for information about contributing patches or features.
All code for this can be found online at github. If something is broken, or a feature is missing, please submit a pull request or open an issue. Most things I probably won’t have time to get around to looking at too deeply, so if you want it fixed, a pull request is the way to go. In your pull request please provide an explaniation as to what your request is for, and what benefit it provides. Also please try to follow PEP8 as best a possible.
Unittests are included in the tests/ directory and are ran every commit thanks to travis-ci.org and this documentation is kindly hosted and automatically rebuilt by readthedocs.org. Test coverage is also provided by coveralls.io.
If you would like to run the tests on your own all you have to do is:
Tests require nose and coverage to be installed.
This is released this under the MIT License as found in the LICENSE.txt file. Enjoy!
Heads up, version 1.0.0 has a different license than previous releases: The pre v1.0.0 releases were licensed under the GPL v3 License.
This project will try to follow the semantic versioning guide lines, as laid out here: SemVer, as best as possible.