!!! note
This guide assumes that you have at least a single instance of
[RabbitMQ](https://www.rabbitmq.com/) up and running. For other
messaging brokers/transports please see [transports](../transports).
django-cqrs works with Python 3.8 or later and has the following dependencies:
- Django >= 3.2
- pika >= 1.0.0
- kombu >= 4.6
- ujson >= 3.0.0
- django-model-utils >= 4.0.0
- python-dateutil >= 2.4
django-cqrs can be installed from pypi.org with pip:
$ pip install django-cqrs
Add dj_cqrs to Django INSTALLED_APPS
:
INSTALLED_APPS = [
...
'dj_cqrs',
...
]
and add the django-cqrs configuration:
CQRS = {
'transport': 'dj_cqrs.transport.RabbitMQTransport',
'url': 'amqp://guest:guest@rabbit:5672/'
}
To setup master models add the dj_cqrs.mixins.MasterMixin
to your model.
For example:
from django.db import models
from dj_cqrs.mixins import MasterMixin
class MyMasterModel(MasterMixin, models.Model):
CQRS_ID = 'my_model' # each model must have its unique CQRS_ID
my_field = models.CharField(max_length=100)
....
Since the MasterMixin
adds the cqrs_revision
and cqrs_updated
fields to the model, you must create a new migration for it:
$ ./manage.py makemigrations
$ ./manage.py migrate
$ ./manage.py runserver
Add dj_cqrs to Django INSTALLED_APPS
:
INSTALLED_APPS = [
...
'dj_cqrs',
...
]
and add the django-cqrs configuration:
CQRS = {
'transport': 'dj_cqrs.transport.RabbitMQTransport',
'url': 'amqp://guest:guest@rabbit:5672/',
'queue': 'my_replica', # Each replica service must have a unique queue.
}
To setup replica models add the dj_cqrs.mixins.ReplicaMixin
to each
model.
For example:
from django.db import models
from dj_cqrs.mixins import ReplicaMixin
class MyReplicaModel(ReplicaMixin, models.Model):
CQRS_ID = 'my_model'
my_field = models.CharField(max_length=100)
....
Since the ReplicaMixin
adds the cqrs_revision
and cqrs_updated
fields to the model, you must create a new migration for it:
$ ./manage.py makemigrations
$ ./manage.py migrate
$ ./manage.py cqrs_consume -w 2
And that's all!
Now every time you modify your master model, changes are replicated to
all services that have a replica model with the same CQRS_ID
.
The library allow us to send customized metadata from the Master models to the Replica ones.
There are two ways to specify what we want to include in this metadata, overriding the master function or setting a default generic function that will be executed for all masters.
Inside the Master model class you have to add the get_cqrs_meta function that will replace the default one (that returns an empty dict). For instance if you want to return the access of a given model instance inside the metadata you could do the following:
def get_cqrs_meta(self, **kwargs):
meta = super().get_cqrs_meta(**kwargs)
if self.is_owner():
meta['access']['owner'] = True
meta['access']['others'] = False
else:
meta['access']['owner'] = False
meta['access']['others'] = True
return meta
In the django settings you could configure a function that will be executed everytime an event is emitted in any Master:
from ... import get_cqrs_meta
CQRS = {
...
'master': {
...
'meta_function': get_cqrs_meta,
},
}
From the replica model you will now receive an additional parameter called meta that will contain all metadata set in the Master model. These data will be present in the following class functions:
For instance replacing the cqrs_update we could do something like:
def cqrs_update(self, sync, mapped_data, previous_data=None, meta=None):
if meta and not meta['access']['owner']:
# Call asynchronously external system to update some resource.
else:
# Call asynchronously internal system to update some resource.
return super().cqrs_update(sync, mapped_data, previous_data, meta)