Update: It's possible to use simple JOINs via the django-dbindexer now.
This means you can use the Django ORM (
from django.db import models) directly with MongoDB. Even better, you can write code that can run on both MongoDB and App Engine (via our App Engine backend) and possibly also SQL. For example, this website is running Django-nonrel on App Engine, but the same code also works with the MongoDB backend and even with Django's SQL backends. So, Django-nonrel allows for writing portable Django apps. This portability will often only be possible between non-relational DBs, but for many simple apps SQL should work, too.
You're probably wondering by now: Does the admin interface work? Yes, but it's limited by MongoDB's query capabilities. For example, you can't do JOINs (except for JOINs made possible by django-dbindexer).
First, install pymongo, for example via "
easy_install pymongo". Then, clone the MongoDB backend (or download the source) and install it by running "
python setup.py install". Next, clone the Django-nonrel repository (or download the source) and install it via "
python setup.py install". Finally, clone the djangotoolbox repository (or download the source) and install it via "
python setup.py install". If you want to test everything with this website's code you can also clone the allbuttonspressed repository.
The last step is to specify the MongoDB backend and djangotoolbox in your settings.py:
That's it. You can now use MongoDB with Django's ORM.
What can ya do?
The most notable unsupported field type is
ManyToManyField. It's no problem if that field is in your model, but you can't access it because it requires JOIN support which obviously doesn't exist on non-relational databases. Actually, any query that spans relations (via "
Profile.objects.filter(user__username='someone')) won't work.
This leads to the problem that you can't edit users in the admin interface, but there's a simple workaround which automatically gets applied when you add "djangotoolbox" to your
These lookup types are supported:
ForeignKeydue to a Django bug)
You can also use
QuerySet.exclude() with those lookup types.
Uniqueness constraints on fields and via
unique_together are supported, too.
Here's a little summary of the advanced Django features that are not supported:
- JOINs (except for JOINs made possible by django-dbindexer)
- many-to-many relations
- multi-table inheritance
Important: string-based primary keys
Normally, when you create a model the primary key is an integer. For example
post.id is a string on MongoDB (e.g.,
u'4bd212d9ccdec2510f000000'). In contrast, on SQL and App Engine it's an integer. So, what's the implication for you?
Always write code that works with both string and integer-based primary keys. This also applies to urlpatterns. In particular, when passing an id from your view's URL to a query just leave int/string handling to Django's
QuerySet. For example,
Post.objects.get(id=object_id) will work correctly on SQL even if
object_id is actually a string containing a number (
object_id = '32'). This ensures that your code is portable to other backends.
- simple queries on a single model work as expected
- keep MongoDB limitations in mind when formulating queries
- JOINs (except for JOINs made possible by django-dbindexer), many-to-many relations, and multi-table inheritance don't work
- write portable code that works with string and integer-based primary keys
- join the Django-nonrel discussion group if you want to contribute
You should read 4 things to know for NoSQL Django coders if you want to learn more about nonrel development with Django. That post also discusses some parts of this website's code.
Do you already have an idea for a neat project which could be built with Django-nonrel and MongoDB? Would you like to port an existing Django app? Do you have any questions? Please leave a comment.