めも: django-auditlog で手動で log entry をつくる

動機

django-auditlog には log_create method があるものの、 bulk_create には対応していないので...と思ったのだが、 delete() は QuerySet に発行しても signal があるのか LogEntry が作られていて、結果このコードはいらなかった。他で使うかもなのでいったんおいておく

調査方法

  • 実際に1件対象のモデルを削除してみる → LogEntry の各フィールドにどんな値が入ってるか確認
  • ライブラリソースコードを見る

方針

changes の作成とか remote_addr の取得とかは独自でロジックを組まずに、すでに実装されてるメソッドを使った。ドキュメントされてないメソッド使うのどうなんという気持ちと、あんまりリッチなドキュメントでもないからまあええか、のきもち。

https://github.com/jazzband/django-auditlog/blob/master/auditlog/diff.py#L117

sample code

from datetime import datetime

from auditlog.diff import model_instance_diff
from auditlog.middleware import AuditlogMiddleware
from auditlog.models import LogEntry
from django.contrib.contenttypes.models import ContentType

request = {} # TODO: pass django.HttpRequest object
JST = None # TODO: pass timezone object

log_entries = []
for item in items:
    log_entry = LogEntry(
        content_type=ContentType.objects.get_for_model(item),
        object_id=item.id,
        object_pk=f"{item.id}",
        object_repr=str(item),
        action=LogEntry.Action.DELETE,
        changes=model_instance_diff(item, None),
        actor=AuditlogMiddleware._get_actor(request),
        remote_addr=AuditlogMiddleware._get_remote_addr(request),
        timestamp=datetime.now(JST),
    )
    log_entries.append(log_entry)
LogEntry.objects.bulk_create(log_entries)

余談: delete() の signal について

ごりごり docs に書いてあって、

It does, however, emit the pre_delete and post_delete signals for all deleted objects (including cascaded deletions).

delete()update() bulk_update() bulk_create() と違って signal を発火してくれるとのこと。わら。