DEV Community

Luke Benstead for Potato

Posted on

Using Google Cloud Firestore with Django's ORM

Django has long been the most popular Python framework for developing web applications. One of its most powerful features is its built in object-relational mapper (ORM) which is designed to flexibly and safely interact with SQL databases in an abstract way.

A long time ago, a fork of Django called “Django-nonrel” experimented with the idea of using Django’s ORM with a non-relational database; what was then called the App Engine Datastore, but is now known as Google Cloud Datastore (or technically, Google Cloud Firestore in Datastore Mode). Since then a more recent project called "django-gcloud-connectors" has been developed by Potato to allow seamless ORM integration with Google Cloud Datastore.

The intention was always to expand that functionality to other Google hosted no-SQL databases, and today I’m pleased to announce that django-gcloud-connectors now has support for Google Cloud Firestore in Native Mode. This means you can now build a robust Django-powered website or API driven from a Firestore database which could for example be shared with your Firebase backed mobile application.

It might seem that using Django’s relational mapper on a non-relational database would be like forcing a square peg into a round hole - but it turns out that the Django ORM works quite elegantly with a non-relational database, and gives you the tools you need to build reusable patterns to get the most out of a massively scalable database.

Take for example the schemaless nature of a non-rel database like Cloud Datastore which allows each document to have different properties to the other documents in the same table; while powerful, in practice you generally need a schema to write code against and to ensure that your data remains consistent. Django’s model structure allows you to maintain a schema (with validation) that can change over time. You can leverage model signals, field defaults or request middleware to migrate data on the fly, without the need for running potentially slow or disruptive database migrations. You hardly need to worry about the database at all while developing, simply add a new model or field in your code and use it. Django with a non-relational database is great for rapid prototyping.

There are limitations of course; non-relational databases don’t do complex queries - you can’t perform joins; you can have foreign keys, but you can’t fetch or order across those relations in one database query; you can have many-to-many relationships, but not with Django’s ManyToManyField (you need to use a custom list field instead). You might just find some queries are impossible.

These limitations mean you have to solve problems in a slightly different way. You’ll find you’ll design your models around the queries you need to make; you’ll sometimes have to pre-calculate things when you save a document to make it possible to quickly query for it later, or perhaps use other services like Big Query or background task processing.

But you can almost always assume that once your code works, it’ll scale well no matter how much data you throw at it; there’s no risk of running an unindexed query on a million rows, or having to think about database replication or sharding. You can rapidly build a product for a startup and know that things will just ramp up when it hits the big time.

I highly recommend you give it a try, simply follow the instructions in the django-gcloud-connectors repository and you’ll be up and running in no time. If you’re hosting on Google App Engine you might also be interested in the Djangae project which provides useful utilities and Django apps to integrate with Google Cloud services.

Top comments (2)

youngfra profile image
Fraser Young

This integration with Google Cloud Firestore sounds promising. Are there any performance benchmarks available for using Django's ORM with Firestore compared to traditional SQL databases? Great post!

kazade profile image
Luke Benstead

We don't have any benchmarks at the moment, but I'll see if I can pull some together and write another post on the results :)