mirror of
https://github.com/jazzband/django-auditlog.git
synced 2026-03-16 22:20:26 +00:00
Configure actions in auditlog.register
This commit is contained in:
parent
b1ecc8f754
commit
910f1bf7b7
4 changed files with 60 additions and 34 deletions
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
- feat: Added `LogEntry.remote_port` field. ([#671](https://github.com/jazzband/django-auditlog/pull/671))
|
||||
- feat: Added `truncate` option to `auditlogflush` management command. ([#681](https://github.com/jazzband/django-auditlog/pull/681))
|
||||
- feat: Added `actions` param in `auditlog.register`. ([#682](https://github.com/jazzband/django-auditlog/pull/682))
|
||||
- Drop Python 3.8 support. ([#678](https://github.com/jazzband/django-auditlog/pull/678))
|
||||
- Confirm Django 5.1 support and drop Django 3.2 support. ([#677](https://github.com/jazzband/django-auditlog/pull/677))
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ from django.db.models.signals import (
|
|||
)
|
||||
|
||||
from auditlog.conf import settings
|
||||
from auditlog.receivers import log_access, log_create, log_delete, log_update
|
||||
from auditlog.signals import accessed
|
||||
|
||||
DispatchUID = tuple[int, int, int]
|
||||
|
|
@ -31,34 +32,11 @@ class AuditlogModelRegistry:
|
|||
|
||||
DEFAULT_EXCLUDE_MODELS = ("auditlog.LogEntry", "admin.LogEntry")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
create: bool = True,
|
||||
update: bool = True,
|
||||
delete: bool = True,
|
||||
access: bool = True,
|
||||
m2m: bool = True,
|
||||
custom: Optional[dict[ModelSignal, Callable]] = None,
|
||||
):
|
||||
from auditlog.receivers import log_access, log_create, log_delete, log_update
|
||||
|
||||
def __init__(self):
|
||||
self._registry = {}
|
||||
self._signals = {}
|
||||
self._m2m_signals = defaultdict(dict)
|
||||
|
||||
if create:
|
||||
self._signals[post_save] = log_create
|
||||
if update:
|
||||
self._signals[pre_save] = log_update
|
||||
if delete:
|
||||
self._signals[post_delete] = log_delete
|
||||
if access:
|
||||
self._signals[accessed] = log_access
|
||||
self._m2m = m2m
|
||||
|
||||
if custom is not None:
|
||||
self._signals.update(custom)
|
||||
|
||||
def register(
|
||||
self,
|
||||
model: ModelBase = None,
|
||||
|
|
@ -70,6 +48,8 @@ class AuditlogModelRegistry:
|
|||
serialize_data: bool = False,
|
||||
serialize_kwargs: Optional[dict[str, Any]] = None,
|
||||
serialize_auditlog_fields_only: bool = False,
|
||||
actions: Optional[dict[str, bool]] = None,
|
||||
custom: Optional[dict[ModelSignal, Callable]] = None,
|
||||
):
|
||||
"""
|
||||
Register a model with auditlog. Auditlog will then track mutations on this model's instances.
|
||||
|
|
@ -81,10 +61,31 @@ class AuditlogModelRegistry:
|
|||
:param mask_fields: The fields to mask for sensitive info.
|
||||
:param m2m_fields: The fields to handle as many to many.
|
||||
:param serialize_data: Option to include a dictionary of the objects state in the auditlog.
|
||||
:param serialize_kwargs: Optional kwargs to pass to Django serializer
|
||||
:param serialize_kwargs: Optional kwargs to pass to Django serializer.
|
||||
:param serialize_auditlog_fields_only: Only fields being considered in changes will be serialized.
|
||||
:param actions: Enble log entry on create, update, delete, access and m2m fields.
|
||||
:param custom: Configure a custom signal when register.
|
||||
"""
|
||||
|
||||
actions = actions or {}
|
||||
create = actions.get("create", True)
|
||||
update = actions.get("update", True)
|
||||
delete = actions.get("delete", True)
|
||||
access = actions.get("access", True)
|
||||
m2m = actions.get("m2m", True)
|
||||
|
||||
if create:
|
||||
self._signals[post_save] = log_create
|
||||
if update:
|
||||
self._signals[pre_save] = log_update
|
||||
if delete:
|
||||
self._signals[post_delete] = log_delete
|
||||
if access:
|
||||
self._signals[accessed] = log_access
|
||||
|
||||
if custom is not None:
|
||||
self._signals.update(custom)
|
||||
|
||||
if include_fields is None:
|
||||
include_fields = []
|
||||
if exclude_fields is None:
|
||||
|
|
@ -122,7 +123,7 @@ class AuditlogModelRegistry:
|
|||
"serialize_kwargs": serialize_kwargs,
|
||||
"serialize_auditlog_fields_only": serialize_auditlog_fields_only,
|
||||
}
|
||||
self._connect_signals(cls)
|
||||
self._connect_signals(cls, m2m=m2m)
|
||||
|
||||
# We need to return the class, as the decorator is basically
|
||||
# syntactic sugar for:
|
||||
|
|
@ -180,7 +181,7 @@ class AuditlogModelRegistry:
|
|||
),
|
||||
}
|
||||
|
||||
def _connect_signals(self, model):
|
||||
def _connect_signals(self, model, m2m: bool = False):
|
||||
"""
|
||||
Connect signals for the model.
|
||||
"""
|
||||
|
|
@ -192,7 +193,7 @@ class AuditlogModelRegistry:
|
|||
sender=model,
|
||||
dispatch_uid=self._dispatch_uid(signal, receiver),
|
||||
)
|
||||
if self._m2m:
|
||||
if m2m:
|
||||
for field_name in self._registry[model]["m2m_fields"]:
|
||||
receiver = make_log_m2m_changes(field_name)
|
||||
self._m2m_signals[model][field_name] = receiver
|
||||
|
|
|
|||
|
|
@ -5,9 +5,7 @@ from django.core.serializers.json import DjangoJSONEncoder
|
|||
from django.db import models
|
||||
|
||||
from auditlog.models import AuditlogHistoryField
|
||||
from auditlog.registry import AuditlogModelRegistry, auditlog
|
||||
|
||||
m2m_only_auditlog = AuditlogModelRegistry(create=False, update=False, delete=False)
|
||||
from auditlog.registry import auditlog
|
||||
|
||||
|
||||
@auditlog.register()
|
||||
|
|
@ -363,7 +361,15 @@ auditlog.register(ProxyModel)
|
|||
auditlog.register(RelatedModel)
|
||||
auditlog.register(ManyRelatedModel)
|
||||
auditlog.register(ManyRelatedModel.recursive.through)
|
||||
m2m_only_auditlog.register(ManyRelatedModel, m2m_fields={"related"})
|
||||
auditlog.register(
|
||||
ManyRelatedModel,
|
||||
m2m_fields=["related"],
|
||||
actions={
|
||||
"create": False,
|
||||
"update": False,
|
||||
"delete": False,
|
||||
},
|
||||
)
|
||||
auditlog.register(SimpleExcludeModel, exclude_fields=["text"])
|
||||
auditlog.register(SimpleMappingModel, mapping_fields={"sku": "Product No."})
|
||||
auditlog.register(AdditionalDataIncludedModel)
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ from django.core import management
|
|||
from django.db import models
|
||||
from django.db.models import JSONField, Value
|
||||
from django.db.models.functions import Now
|
||||
from django.db.models.signals import pre_save
|
||||
from django.db.models.signals import post_delete, post_save, pre_save
|
||||
from django.test import RequestFactory, TestCase, TransactionTestCase, override_settings
|
||||
from django.urls import resolve, reverse
|
||||
from django.utils import dateformat, formats
|
||||
|
|
@ -34,7 +34,7 @@ from auditlog.diff import model_instance_diff
|
|||
from auditlog.middleware import AuditlogMiddleware
|
||||
from auditlog.models import DEFAULT_OBJECT_REPR, LogEntry
|
||||
from auditlog.registry import AuditlogModelRegistry, AuditLogRegistrationError, auditlog
|
||||
from auditlog.signals import post_log, pre_log
|
||||
from auditlog.signals import accessed, post_log, pre_log
|
||||
from auditlog_tests.fixtures.custom_get_cid import get_cid as custom_get_cid
|
||||
from auditlog_tests.models import (
|
||||
AdditionalDataIncludedModel,
|
||||
|
|
@ -1438,6 +1438,24 @@ class RegisterModelSettingsTest(TestCase):
|
|||
self.assertEqual(fields["include_fields"], ["label"])
|
||||
self.assertEqual(fields["exclude_fields"], ["text"])
|
||||
|
||||
@override_settings(
|
||||
AUDITLOG_INCLUDE_TRACKING_MODELS=(
|
||||
{
|
||||
"model": "auditlog_tests.SimpleModel",
|
||||
"actions": {
|
||||
"delete": False,
|
||||
},
|
||||
},
|
||||
)
|
||||
)
|
||||
def test_register_actions_from_settings_models(self):
|
||||
self.test_auditlog.register_from_settings()
|
||||
|
||||
self.assertTrue(self.test_auditlog.contains(SimpleModel))
|
||||
self.assertTrue(post_save in self.test_auditlog._signals)
|
||||
self.assertTrue(accessed in self.test_auditlog._signals)
|
||||
self.assertFalse(post_delete in self.test_auditlog._signals)
|
||||
|
||||
def test_registration_error_if_bad_serialize_params(self):
|
||||
with self.assertRaisesMessage(
|
||||
AuditLogRegistrationError,
|
||||
|
|
|
|||
Loading…
Reference in a new issue