Skip to content

Setting AUDITLOG_LOGENTRY_MODEL leaves a dangling auditlog_logentry table, breaking flush #804

@Jackevansevo

Description

@Jackevansevo

Following the instructions in the docs to subclass AbstractLogEntry to provide my own model

from django.db import models

from auditlog.models import AbstractLogEntry

class CustomLogEntryModel(AbstractLogEntry):
    role = models.CharField(max_length=100, null=True, blank=True)
DATABASE_URL=postgresql:///example uv run manage.py makemigrations polls
Migrations for 'polls':
  polls/migrations/0001_initial.py
    + Create model CustomLogEntryModel

After migrating and looking at my DB schema, there's both auditlog_logentry and polls_customlogentrymodel

+--------+----------------------------+-------+-------+
| Schema | Name                       | Type  | Owner |
|--------+----------------------------+-------+-------|
| public | auditlog_logentry          | table | jack  |
.......................................................
| public | polls_customlogentrymodel  | table | jack  |
+--------+----------------------------+-------+-------+

This causes issues when trying to flush the database

$ DATABASE_URL=postgresql:///example uv run manage.py flush --no-input
CommandError: Database example couldn't be flushed. Possible reasons:
  * The database isn't running or isn't configured correctly.
  * At least one of the expected database tables doesn't exist.
  * The SQL was invalid.
Hint: Look at the output of 'django-admin sqlflush'. That's the SQL this command wasn't able to run.

If we look at the output of sqlfush

DATABASE_URL=postgresql:///example uv run manage.py sqlflush
BEGIN;
TRUNCATE "django_session", "auth_user_groups", "auth_permission", "auth_group_permissions", "auth_group", "polls_customlogentrymodel", "auth_user_user_permissions", "django_content_type", "auth_user", "django_admin_log" RESTART IDENTITY;
COMMIT;

Running this within psql

jack@(none):example> BEGIN;
 TRUNCATE "django_session", "auth_user_groups", "auth_permission", "auth_group_permissions", "auth_group", "polls_customlogentrymodel", "auth_user_user_permissions", "django_content_type", "a
 uth_user", "django_admin_log" RESTART IDENTITY;
 COMMIT;
You're about to run a destructive command.
Do you want to proceed? [y/N]: y
Your call!
BEGIN
cannot truncate a table referenced in a foreign key constraint
DETAIL:  Table "auditlog_logentry" references "django_content_type".
HINT:  Truncate table "auditlog_logentry" at the same time, or use TRUNCATE ... CASCADE.
Time: 0.004s
jack@(none):example>

Django rightly thinks our audit log model is polls_customlogentrymodel, but the fact auditlog_logentry exists means we can no longer flush our DB because it still has a FK constraint with django_content_type.

My best guess is that we need to make the log model swappable with AUDIT_LOGENTRY_MODEL

class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
("contenttypes", "0001_initial"),
]
operations = [
migrations.CreateModel(
name="LogEntry",
fields=[
(
"id",
models.AutoField(
verbose_name="ID",
serialize=False,
auto_created=True,
primary_key=True,
),
),
("object_pk", models.TextField(verbose_name="object pk")),
(
"object_id",
models.PositiveIntegerField(
db_index=True, null=True, verbose_name="object id", blank=True
),
),
("object_repr", models.TextField(verbose_name="object representation")),
(
"action",
models.PositiveSmallIntegerField(
verbose_name="action",
choices=[(0, "create"), (1, "update"), (2, "delete")],
),
),
(
"changes",
models.TextField(verbose_name="change message", blank=True),
),
(
"timestamp",
models.DateTimeField(auto_now_add=True, verbose_name="timestamp"),
),
(
"actor",
models.ForeignKey(
related_name="+",
on_delete=django.db.models.deletion.SET_NULL,
verbose_name="actor",
blank=True,
to=settings.AUTH_USER_MODEL,
null=True,
),
),
(
"content_type",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="+",
verbose_name="content type",
to="contenttypes.ContentType",
),
),
],
options={
"ordering": ["-timestamp"],
"get_latest_by": "timestamp",
"verbose_name": "log entry",
"verbose_name_plural": "log entries",
},
bases=(models.Model,),
),
]

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions