Skip to content

Repository files navigation

Django ChangeSet

Linter and testsCodecov

Django ChangeSet is a simple Django app that will give your models the possibility to track all changes. It depends on django_userforeignkey to determine the current user doing the change(s).

Supported Python versions: 3.10 - 3.14. Supported Django versions: 5.2 and 6.0.

Detailed documentation is in the docs subdirectory.

Quick start

  1. Use pip to install and download django-changeset (and django-userforeignkey):
pip install django-changeset
  1. Add django_userforeignkey and django_changeset to your INSTALLED_APPS like this:
INSTALLED_APPS= [
...
'django_userforeignkey',
'django_changeset',
]
  1. Add django_userforeignkey.middleware.UserForeignKeyMiddleware to your MIDDLEWARE like this:
MIDDLEWARE= (
...
'django.contrib.auth.middleware.AuthenticationMiddleware',
...
'django_userforeignkey.middleware.UserForeignKeyMiddleware',
)

Note: Make sure to insert the UserForeignKeyMiddlewareafter Djangos AuthenticationMiddleware.

Example usage

Use RevisionModelMixin as a mixin class for your models and add the fields you want to track in the meta configuration using track_fields and track_related. Also add a generic relation to ChangeSet using changesets = ChangeSetRelation():

fromdjango.dbimportmodelsfromdjango_changeset.modelsimportRevisionModelMixinfromdjango_changeset.models.fieldsimportChangeSetRelationclassMyModel(models.Model, RevisionModelMixin):
classMeta:
track_fields= ('my_data', ) # track changes on my_datatrack_related= ('my_ref', ) # track changes on a related modelmy_data=models.CharField(max_length=64, verbose_name="Very important data you want to track")
my_ref=models.ForeignKey('SomeOtherModel', verbose_name="Very important relation", related_name='my_models')
# Generic Relation to ChangeSetchangesets=ChangeSetRelation()

Note: If you want to have access to the properties created_by, created_at, last_modified_by, last_modified_at, you need to inherit from CreatedModifiedByMixin aswell as RevisionModelMixin. For the Python MRO to work, you also have to create an abstract base model:

fromdjango.dbimportmodelsfromdjango_changeset.modelsimportCreatedModifiedByMixin, RevisionModelMixinfromdjango_changeset.models.fieldsimportChangeSetRelationclassBaseModel(models.Model):
""" BaseModel is needed for proper MRO within Python/Django Models """classMeta:
abstract=TruepassclassMyModel(BaseModel, RevisionModelMixin, CreatedModifiedByMixin):
classMeta:
track_fields= ('my_data', ) # track changes on my_datatrack_related= ('my_ref', ) # track changes on a related modelmy_data=models.CharField(max_length=64, verbose_name="Very important data you want to track")
my_ref=models.ForeignKey('SomeOtherModel', verbose_name="Very important relation", related_name='my_models')
# Generic Relation to ChangeSetchangesets=ChangeSetRelation()

Querying ChangeSets via the changesets relation

By inheriting from the RevisionModelMixin and CreatedModifiedByMixin mixins, and adding an attribute of type ChangeSetRelation (a GenericRelation for the changeset), the following features are added to your model:

  • Properties created_by, created_at, last_modified_by, last_modified_at are made available for each object (CreatedModifiedByMixin)
  • Relation changesets is made available, allowing you to run queries like this one: MyModel.objects.filter(changesets__changeset_type='I', changesets__user__username='johndoe')

Access ChangeSets and ChangeRecords

ToDo

You can access the changeset by calling the change_set property of an instance of MyModel as shown in the following example:

print("------- CHANGE SETS (", len(somemodel.changesets), ")---------")
forchange_setinsomemodel.changesets:
# print change_setprint("Change was carried out at ", change_set.date, " by user ", change_set.user, " on model ", change_set.object_type)
print(" + CHANGE RECORDS (", len(change_set.change_records.all()), "): ")
forchange_recordinchange_set.change_records.all():
print("\t", change_record)
print("\tIs change on a related field?", change_record.is_related)
# related fields: we only know that something new has been added. we know the PK, but not the object itselfprint("\t\tChanged field ", change_record.field_name, "(", change_record.field_verbose_name, ") from ",
change_record.old_value, "(display:", change_record.old_value_display, ") to")
print("\t\t ", change_record.new_value, "(display:", change_record.new_value_display, ")")
ifchange_record.is_related:
print("\t\tRelated Object Info: ", change_record.related_object)
# TODO:# change_set.created_at, change_set.created_by, change_set.last_modified_by, change_set.last_modified_atprint("-----")

Maintainers

This repository is currently maintained by

  • beachmachine
  • mikelandzelo173

Pull Requests are welcome.

License

Django ChangeSet uses the BSD-3 Clause License, see LICENSE file.

About

No description or website provided.

Topics

Resources

Stars

5 stars

Watchers

4 watching

Forks

Releases

Packages

Used by

Contributors

Languages