Package: eventsourcing-django
Event Sourcing with DjangoThis package supports using the Pythoneventsourcinglibrary
withDjango ORM.To use Django with your Python eventsourcing applications:install the Python packageeventsourcing_djangoadd'eventsourcing_django'to your Django project'sINSTALLED_APPSsettingmigrate your database for this Django appset the environment variablePERSISTENCE_MODULEto'eventsourcing_django'See below for more information.InstallationUse pip to install thestable distributionfrom the Python Package Index. Please note, it is recommended to
install Python packages into a Python virtual environment.$ pip install eventsourcing_djangoDjangoIf you are using Django 3.2 or later, add'eventsourcing_django'to your Django project'sINSTALLED_APPSsetting.INSTALLED_APPS = [
    ...
    'eventsourcing_django',
]If you are using Django 2.2, 3.0 or 3.1, please add'eventsourcing_django.apps.EventsourcingConfig'to your Django
project'sINSTALLED_APPSsetting.INSTALLED_APPS = [
    ...
    'eventsourcing_django.apps.EventsourcingConfig',
]To migrate your database, please run Django'smanage.py migratecommand.$ python manage.py migrate eventsourcing_djangoEvent sourcingDefine aggregates and applications in the usual way.fromeventsourcing.applicationimportApplicationfromeventsourcing.domainimportAggregate,eventfromuuidimportuuid5,NAMESPACE_URLclassTrainingSchool(Application):defregister(self,name):dog=Dog(name)self.save(dog)defadd_trick(self,name,trick):dog=self.repository.get(Dog.create_id(name))dog.add_trick(trick)self.save(dog)defget_tricks(self,name):dog=self.repository.get(Dog.create_id(name))returndog.tricksclassDog(Aggregate):@event('Registered')def__init__(self,name):self.name=nameself.tricks=[]@staticmethoddefcreate_id(name):returnuuid5(NAMESPACE_URL,f'/dogs/{name}')@event('TrickAdded')defadd_trick(self,trick):self.tricks.append(trick)Construct and use the application in the usual way.
SetPERSISTENCE_MODULEto'eventsourcing_django'in the application's environment.
You may wish to construct the application object on a signal
when the Django project is "ready". You can use theready()method of theAppConfigclass in theapps.pymodule of a
Django app.school=TrainingSchool(env={"PERSISTENCE_MODULE":"eventsourcing_django",})The application's methods may be called from Django views and forms.school.register('Fido')school.add_trick('Fido','roll over')school.add_trick('Fido','play dead')tricks=school.get_tricks('Fido')asserttricks==['roll over','play dead']For more information, please refer to the Pythoneventsourcinglibrary
and theDjangoproject.Management CommandsThe Django appeventsourcing_djangoships with the following management commands.Synchronise FollowersManually synchronise followers (i.e.ProcessApplicationinstances) with all of their
leaders, as defined in theeventsourcing.system.System's pipes.Usage$pythonmanage.pysync_followers[-n][-v{0,1,2,3}][follower[follower...]]Wherefollowerdenotes the name of a follower to synchronize. Not specifying any means
synchronisingall followersfound in the system.Relevant options:-n,--dry-run: Load and process all unseen events for the selected followers,
but roll back all changes at the end.-v {0,1,2,3},--verbosity {0,1,2,3}: Verbosity level; 0=minimal output, 1=normal
output, 2=verbose output, 3=very verbose output.For a full list of options, pass the--helpflag to the command.ExamplesTo synchronise all followers found in the runner:$pythonmanage.pysync_followersTo synchronise a single follower:$pythonmanage.pysync_followersTrainingSchoolThe command supports the regular-v/--verbosityoptional argument, as well as a-n/--dry-runflag.Note that running the command in dry-run modewillpull and process every new
event, though the changes will eventually be rolled back.Error handlingEach selected follower should have its own chance at synchronisation. Therefore, the
command will catch some exceptions on a per-follower basis and continue with the
remaining followers.The base Django exceptions that are caught areEmptyResultSet,FieldDoesNotExist,FieldError,MultipleObjectsReturned, andObjectDoesNotExist. The base exceptionEventSourcingErrorfrom theeventsourcinglibrary is also caught per follower.ConfigurationThis command needs to access aeventsourcing.system.Runnerinstance to query and act
on its followers. The runner's system is additionally the one defining the pipes between
leaders and followers.The default behaviour, without additional configuration, is to inspect all installed
Django apps and look for an instance ofeventsourcing.system.Runner. The attribute
name does not matter as long as it is public (i.e. not start with an underscore).# djangoproject/apps/my_es_app/apps.pyimporteventsourcing.systemfromdjango.appsimportAppConfigclassMyEventSourcedAppConfig(AppConfig):name="my_event_sourced_app"runner:eventsourcing.system.Runnerdefready(self)->None:self.runner=eventsourcing.system.SingleThreadedRunner(eventsourcing.system.System(...))This is usually enough unless you i) have multiple runners defined in one or more apps,
or ii) do not hold the runner(s) in Django apps. In which case, you should configure the
Django settingEVENTSOURCING_RUNNERin one of two ways:SetEVENTSOURCING_RUNNERto an app name's attribute. This attribute must be aeventsourcing.system.Runnerinstance.# djangoproject/settings.py...EVENTSOURCING_RUNNER="my_event_sourced_app.runner"SetEVENTSOURCING_RUNNERto a fully qualified function name. This function will be
called without arguments and should return aeventsourcing.system.Runnerinstance.# djangoproject/settings.py...EVENTSOURCING_RUNNER="djangoproject.runner_utils.get_runner"# djangoproject/runner_utils.pyimporteventsourcing.systemdefget_runner()->eventsourcing.system.Runner:return...All runner classes shipped with theeventsourcinglibrary are compatible.