Firestore
Generally Firestore in Datastore mode seems to provide a better "normal" database experience than Firestore in native mode,
so it is assumed that most users of gcloudc
will use the Datastore connector.
However, Firestore's native mode has the benefits of its realtime functionality, which may be a significant advantage for some use cases.
If you're using Firestore in native mode, beware of the following limitations.
Primary keys are stored as strings
Firestore always stores the primary key field as a string,
so if you don't override the primary key field on your models then you will get Django's default AutoField
,
which may cause surprises.
The AutoField
tries to store an integer.
In order to make sorting work correctly, gcloudc
will pad the integer with zeros so that all values are the same length.
This means that str(obj.pk)
, as might be used in a URL path,
will not necessarily give you the correct value to query for the object directly in the Firestore web console at
console.cloud.google.com.
To avoid this problem, one solution is to use the supplied AutoCharField
. E.g.:
from gcloudc.db.models.fields.firestore import AutoCharField
class MyModel(models.Model):
id = AutoCharField(primary_key=True)
This generates ID values in the same format that Firestore generates automatically.
Alternatively you can use Django's UUIDField
for your primary keys.
You can't sort by PK descending
Currently, sorting a query by primary key descending is not allowed. To get around this you need to duplicate the primary key onto a separate field and then order by that field. For example:
from gcloudc.db.backends.firestore.transaction import Transaction
class DenormalizedPK(models.Model):
uid = models.CharField(max_length=64, editable=False)
class Meta:
abstract = True
def save(self, *args, **kwargs):
if not self.pk:
# H! This generates a Firestore ID so that we can denormalize before save.
self.pk = Transaction(connection, None)._generate_id(str)
self.uid = self.pk
return super().save(*args, **kwargs)
Indexes are not generated by the local emulator
Unlike with the Datastore emulator, the local Firestore emulator does not generate index definitions for you.
However, it does provide a URL on localhost from which the indexes which would be required for
queries which have been performed during the current run of the emulator.
These indexes are provided in a different format to the one required in the firestore.indexes.json
file in which you must provide your index definitions for deployment.
To extract these indexes from the emulator and merge them into your firestore.indexes.json
file in
the correct format, gcloudc
provides a utility gcloudc.utils.firestore_indexes.update_firestore_indexes
.
update_firestore_indexes(
emulator_project,
emulator_config="firebase.json",
indexes_file="firestore.indexes.json"
)
You might want to call this in manage.py
before shutdown, perhaps only for certain commands,
or perhaps call it in specific tests. It's up to you.
Note that the emulator_project
argument appears to need to be the name of the project that the
emulator was started with, even if you're using the emulator in multi-project mode.
Presumably this may change in the future.