{"id":24983212,"url":"https://github.com/jazzband/django-fsm-log","last_synced_at":"2026-01-27T13:03:57.382Z","repository":{"id":38190560,"uuid":"13976113","full_name":"jazzband/django-fsm-log","owner":"jazzband","description":"Automatic logging for Django FSM","archived":false,"fork":false,"pushed_at":"2026-01-26T17:41:08.000Z","size":286,"stargazers_count":249,"open_issues_count":16,"forks_count":79,"subscribers_count":7,"default_branch":"master","last_synced_at":"2026-01-26T21:55:34.367Z","etag":null,"topics":["django","django-fsm","python"],"latest_commit_sha":null,"homepage":"https://django-fsm-log.readthedocs.io/en/latest/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jazzband.png","metadata":{"funding":{"custom":["https://jazzband.co/donate"]},"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2013-10-30T03:15:55.000Z","updated_at":"2026-01-26T17:41:46.000Z","dependencies_parsed_at":"2023-12-25T20:02:33.228Z","dependency_job_id":"c4224f59-9aad-41d4-9584-7f17b3108666","html_url":"https://github.com/jazzband/django-fsm-log","commit_stats":{"total_commits":219,"total_committers":29,"mean_commits":7.551724137931035,"dds":0.6986301369863014,"last_synced_commit":"03a8d5f57dd73dc2868873660213b89c42f86af3"},"previous_names":["gizmag/django-fsm-log"],"tags_count":23,"template":false,"template_full_name":null,"purl":"pkg:github/jazzband/django-fsm-log","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jazzband%2Fdjango-fsm-log","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jazzband%2Fdjango-fsm-log/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jazzband%2Fdjango-fsm-log/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jazzband%2Fdjango-fsm-log/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jazzband","download_url":"https://codeload.github.com/jazzband/django-fsm-log/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jazzband%2Fdjango-fsm-log/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28813230,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-27T12:25:15.069Z","status":"ssl_error","status_checked_at":"2026-01-27T12:25:05.297Z","response_time":168,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["django","django-fsm","python"],"created_at":"2025-02-04T09:13:29.012Z","updated_at":"2026-01-27T13:03:57.376Z","avatar_url":"https://github.com/jazzband.png","language":"Python","funding_links":["https://jazzband.co/donate"],"categories":[],"sub_categories":[],"readme":"# Django Finite State Machine Log\n\n[![test suite](https://github.com/jazzband/django-fsm-log/actions/workflows/test_suite.yml/badge.svg)](https://github.com/jazzband/django-fsm-log/actions/workflows/test_suite.yml)\n[![codecov](https://codecov.io/gh/jazzband/django-fsm-log/branch/master/graph/badge.svg)](https://codecov.io/gh/jazzband/django-fsm-log)\n[![Jazzband](https://jazzband.co/static/img/badge.svg)](https://jazzband.co/)\n[![pre-commit.ci status](https://results.pre-commit.ci/badge/github/jazzband/django-fsm-log/master.svg)](https://results.pre-commit.ci/latest/github/jazzband/django-fsm-log/master)\n[![Documentation Status](https://readthedocs.org/projects/django-fsm-log/badge/?version=latest)](https://django-fsm-log.readthedocs.io/en/latest/?badge=latest)\n\nProvides persistence of the transitions of your fsm's models. Backed by the excellent [Django FSM 2](https://github.com/django-commons/django-fsm-2)\npackage.\n\nLogs can be accessed before a transition occurs and before they are persisted to the database\nby enabling a cached backend. See [Advanced Usage](#advanced-usage)\n\n## Changelog\n\n## 5.0.2 ( 2026-01-27 )\n\n- Try to publish straight to pypi thanks to oicd trusted publishing process\n\n## 5.0.1 ( :x: )\n\n- switch from setuptools to hatchling\n\n## 5.0.0 ( :x: )\n\n- ⚠️ Drop python3.9 support\n- Add python3.14 support\n- Add django 5.2, 6.0 support\n\n## 4.0.5 ( :x: )\n\n- Switch to uv\n\n## 4.0.4 ( :x: )\n\n## 4.0.3 ( :x: )\n\n## 4.0.2 ( :x: )\n\n- Upgrade pypa/gh-action-pypi-publish as an attempt to fix publication of releases to pypi.\n\n## 4.0.1 (2025-01-07)\n\nSame as 4.0.0 with a fix on setup.py version\n\n## 4.0.0 (2025-01-07)\n\n- ⚠️ remove support for django 2.2 \u0026 4.0\n- ⚠️ remove support for python 3.7 \u0026 3.8\n- add support for django 5.1 and python 3.13\n- Switch to django-fsm-2\n\nDiscontinued supported versions will most likely continue to work.\n\n## 3.1.0 (2023-03-23)\n\n- `fsm_log_description` now accepts a default description parameter\n- Document `fsm_log_description` decorator\n- Add support for Django 4.1\n- Add compatibility for python 3.11\n\n### 3.0.0 (2022-01-14)\n\n- Switch to github actions (from travis-ci)\n- Test against django 3.2 and 4.0, then python 3.9 and 3.10\n- Drop support for django 1.11, 2.0, 2.1, 3.0, 3.1\n- Drop support for python 3.4, 3.5, 3.6\n- allow using StateLogManager in migrations [#95](https://github.com/jazzband/django-fsm-log/pull/95)\n\n### 2.0.1 (2020-03-26)\n\n- Add support for django3.0\n- Drop support for python2\n\n### 1.6.2 (2019-01-06)\n\n- Address Migration history breakage added in 1.6.1\n\n### 1.6.1 (2018-12-02)\n\n- Make StateLog.description field nullable\n\n### 1.6.0 (2018-11-14)\n\n- Add source state on transitions\n- Fixed `get_state_display` with FSMIntegerField (#63)\n- Fixed handling of transitions if target is None (#71)\n- Added `fsm_log_description` decorator (#1, #67)\n- Dropped support for Django 1.10 (#64)\n\n### 1.5.0 (2017-11-29)\n\n- cleanup deprecated code.\n- add codecov support.\n- switch to pytest.\n- add Admin integration to visualize past transitions.\n\n### 1.4.0 (2017-11-09)\n\n- Bring compatibility with Django 2.0 and drop support of unsupported versions\n  of Django: `1.6`, `1.7`, `1.9`.\n\n### Compatibility\n\n- Python 2.7 and 3.4+\n- Django 1.8+\n- Django-FSM 2+\n\n## Installation\n\nFirst, install the package with pip. This will automatically install any\ndependencies you may be missing\n\n```bash\npip install django-fsm-log\n```\n\nRegister django_fsm_log in your list of Django applications:\n\n```python\nINSTALLED_APPS = (\n    ...,\n    'django_fsm_log',\n    ...,\n)\n```\n\nThen migrate the app to create the database table\n\n```bash\npython manage.py migrate django_fsm_log\n```\n\n## Usage\n\nThe app listens for the `django_fsm.signals.post_transition` signal and\ncreates a new record for each transition.\n\nTo query the log:\n\n```python\nfrom django_fsm_log.models import StateLog\nStateLog.objects.all()\n# ...all recorded logs...\n```\n\n### Disabling logging for specific models\n\nBy default transitions get recorded for all models. Logging can be disabled for\nspecific models by adding their fully qualified name to `DJANGO_FSM_LOG_IGNORED_MODELS`.\n\n```python\nDJANGO_FSM_LOG_IGNORED_MODELS = ('poll.models.Vote',)\n```\n\n### `for_` Manager Method\n\nFor convenience there is a custom `for_` manager method to easily filter on the generic foreign key:\n\n```python\nfrom my_app.models import Article\nfrom django_fsm_log.models import StateLog\n\narticle = Article.objects.all()[0]\n\nStateLog.objects.for_(article)\n# ...logs for article...\n```\n\n### `by` Decorator\n\nWe found that our transitions are commonly called by a user, so we've added a\ndecorator to make logging this easy:\n\n```python\nfrom django.db import models\nfrom django_fsm import FSMField, transition\nfrom django_fsm_log.decorators import fsm_log_by\n\nclass Article(models.Model):\n\n    state = FSMField(default='draft', protected=True)\n\n    @fsm_log_by\n    @transition(field=state, source='draft', target='submitted')\n    def submit(self, by=None):\n        pass\n```\n\nWith this the transition gets logged when the `by` kwarg is present.\n\n```python\narticle = Article.objects.create()\narticle.submit(by=some_user) # StateLog.by will be some_user\n```\n\n### `description` Decorator\n\nDecorator that allows to set a custom description (saved on database) to a transitions.\n\n```python\nfrom django.db import models\nfrom django_fsm import FSMField, transition\nfrom django_fsm_log.decorators import fsm_log_description\n\nclass Article(models.Model):\n\n    state = FSMField(default='draft', protected=True)\n\n    @fsm_log_description(description='Article submitted')  # description param is NOT required\n    @transition(field=state, source='draft', target='submitted')\n    def submit(self, description=None):\n        pass\n\narticle = Article.objects.create()\narticle.submit()  # logged with \"Article submitted\" description\narticle.submit(description=\"Article reviewed and submitted\")  # logged with \"Article reviewed and submitted\" description\n```\n\n.. TIP::\nThe \"description\" argument passed when calling \".submit\" has precedence over the default description set in the decorator\n\nThe decorator also accepts a `allow_inline` boolean argument that allows to set the description inside the transition method.\n\n```python\nfrom django.db import models\nfrom django_fsm import FSMField, transition\nfrom django_fsm_log.decorators import fsm_log_description\n\nclass Article(models.Model):\n\n    state = FSMField(default='draft', protected=True)\n\n    @fsm_log_description(allow_inline=True)\n    @transition(field=state, source='draft', target='submitted')\n    def submit(self, description=None):\n        description.set(\"Article submitted\")\n\narticle = Article.objects.create()\narticle.submit()  # logged with \"Article submitted\" description\n```\n\n### Admin integration\n\nThere is an InlineForm available that can be used to display the history of changes.\n\nTo use it expand your own `AdminModel` by adding `StateLogInline` to its inlines:\n\n```python\nfrom django.contrib import admin\nfrom django_fsm_log.admin import StateLogInline\n\n\n@admin.register(FSMModel)\nclass FSMModelAdmin(admin.ModelAdmin):\n    inlines = [StateLogInline]\n```\n\n### Advanced Usage\n\nYou can change the behaviour of this app by turning on caching for StateLog records.\nSimply add `DJANGO_FSM_LOG_STORAGE_METHOD = 'django_fsm_log.backends.CachedBackend'` to your project's settings file.\nIt will use your project's default cache backend by default. If you wish to use a specific cache backend, you can add to\nyour project's settings:\n\n```python\nDJANGO_FSM_LOG_CACHE_BACKEND = 'some_other_cache_backend'\n```\n\nThe StateLog object is now available after the `django_fsm.signals.pre_transition`\nsignal is fired, but is deleted from the cache and persisted to the database after `django_fsm.signals.post_transition`\nis fired.\n\nThis is useful if:\n\n- you need immediate access to StateLog details, and cannot wait until `django_fsm.signals.post_transition`\n  has been fired\n- at any stage, you need to verify whether or not the StateLog has been written to the database\n\nAccess to the pending StateLog record is available via the `pending_objects` manager\n\n```python\nfrom django_fsm_log.models import StateLog\narticle = Article.objects.get(...)\npending_state_log = StateLog.pending_objects.get_for_object(article)\n```\n\n## Contributing\n\n### Running tests\n\n```bash\npip install tox\ntox\n```\n\n### Linting with pre-commit\n\nWe use ruff, black and more, all configured and check via [pre-commit](https://pre-commit.com/).\nBefore committing, run the following:\n\n```bash\npip install pre-commit\npre-commit install\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjazzband%2Fdjango-fsm-log","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjazzband%2Fdjango-fsm-log","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjazzband%2Fdjango-fsm-log/lists"}