Skip to main content

Django Models Logging

This package logs every change to your Django models in the following format:

{
  "field_name": {
    "old": "old_value",
    "new": "new_value"
  }
}

For deleted objects, "new" is omitted and only "old" is stored.

Example:

{
  "price": {
    "old": "2425",
    "new": "645"
  },
  "name": {
    "old": "ProductName",
    "new": "NewProductName"
  }
}

Requirements

  • Python >= 3.10
  • Django >= 5.2

Installation

  1. Install via pip:
pip install django-models-logging
  1. Add to INSTALLED_APPS — must be at the end, after all apps whose models you want to log:
INSTALLED_APPS = [
    ...,
    'models_logging',
]
  1. Run migrations:
python manage.py migrate

Configuration

Select models to log

LOGGING_MODELS = (
    'app.ClassName',  # log only this model
    'another_app',    # log all models in this app
)

Exclude models from logging

LOGGING_EXCLUDE = (
    'app',                # exclude all models in this app
    'another_app.Model',  # exclude a specific model
)

Custom user model

If request.user is not your AUTH_USER_MODEL:

LOGGING_USER_MODEL = 'yourapp.Users'
# default: AUTH_USER_MODEL

Per-model field filtering

Set these as class attributes on the model:

class MyModel(models.Model):
    LOGGING_IGNORE_FIELDS = ('field1', 'field2')  # exclude specific fields
    # OR
    LOGGING_ONLY_FIELDS = ('field1', 'field2')    # include only these fields

Merging changes per request

By default, each .save() call creates a separate Change record. If .save() is called multiple times in one request, use the middleware to merge them:

MIDDLEWARE = [
    ...,
    'models_logging.middleware.LoggingStackMiddleware',
]

To control merging independently of the middleware:

LOGGING_MERGE_CHANGES = True  # default: True

For scripts or Celery tasks outside of a request cycle, use the context manager:

from models_logging.utils import create_merged_changes

def your_task():
    with create_merged_changes():
        ...

To temporarily suppress logging entirely:

from models_logging.utils import ignore_changes

with ignore_changes():          # ignore all models
    ...

with ignore_changes([MyModel]): # ignore specific models
    ...

Logging bulk updates

queryset.update() does not trigger Django signals and is not logged automatically. Use create_changes_for_update instead:

from models_logging.utils import create_changes_for_update

create_changes_for_update(MyModel.objects.filter(active=True), active=False)

This captures old and new values for each affected row.

Admin

To show an object's change history in the Django admin, use HistoryAdmin:

from models_logging.admin import HistoryAdmin

class YourModelAdmin(HistoryAdmin):
    history_latest_first = False        # show oldest first (default)
    inline_models_history = '__all__'   # '__all__' or list of inline model classes

Admin permissions

def can_revert(request, obj):
    return request.user.is_superuser

LOGGING_REVERT_IS_ALLOWED = can_revert   # callable or bool, default: True
LOGGING_CAN_DELETE_REVISION = False      # callable or bool, default: False
LOGGING_CAN_DELETE_CHANGES = False       # callable or bool, default: False
LOGGING_CAN_CHANGE_CHANGES = False       # callable or bool, default: False
LOGGING_CHANGES_REVISION_LIMIT = 100     # max changes shown inline in a revision

Custom JSON encoder

The default encoder handles FieldFile and GeoDjango Point types. To use your own:

LOGGING_JSON_ENCODER = 'path.to.your.JsonEncoder'

Custom change extras

To store extra data with each change (e.g. request IP, correlation ID), provide a custom function:

# yourapp/logging.py
def get_change_extras(obj, action):
    from models_logging import _local
    return {
        'ip': getattr(_local, 'request', None) and _local.request.META.get('REMOTE_ADDR'),
    }
LOGGING_GET_CHANGE_EXTRAS_FUNC = 'yourapp.logging.get_change_extras'

Management command

Delete old change records:

# delete all changes
python manage.py delete_changes

# delete changes for specific content types (by id)
python manage.py delete_changes --ctype 1,2,3

# exclude content types from deletion
python manage.py delete_changes --ctype-exclude 4,5

# delete changes older than a date
python manage.py delete_changes --date_lte 2024.01.01

Version compatibility

Package version Django Python
5.2.x 5.2 3.10 – 3.14
2.x 3.1 – 4.1 3.8+
0.9.7 <= 2.0

Note: This package is not a database backup solution. Reverting thousands of changes will be slow.

Release files for django-models-logging 5.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for django-models-logging 5.2.0
File Size Uploaded
django_models_logging-5.2.0.tar.gz 16.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for django-models-logging 5.2.0
File Interpreter ABI Platform
django_models_logging-5.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 44.4 kB

Release files / django_models_logging-5.2.0.tar.gz

Download URL django_models_logging-5.2.0.tar.gz
Size 16.9 kB
Tags Source
SHA-256 checksum
How to use checksums
92ca584336e6565323623996ab270983ea0261c837859ca506721801b4914885
BLAKE2b-256 checksum
How to use checksums
c8a3b353d4d64dbb50adae5fd988242d4b5c34c4af1bc16b9508bd1883ac93de
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.11.8 {"installer":{"name":"uv","version":"0.11.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / django_models_logging-5.2.0-py3-none-any.whl

Download URL django_models_logging-5.2.0-py3-none-any.whl
Size 27.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
80a5e52e8d7da03d8b2ee87fa8c35301eebe8b2c5fe05dbd1a465a8de5b52150
BLAKE2b-256 checksum
How to use checksums
81e03afd25144eca4c2576d5a527ef40881b12c72c0b2c335bf81492caaf9ad4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.11.8 {"installer":{"name":"uv","version":"0.11.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page