Skip to content

Commit ef2f408

Browse files
fix finding reviewers model registration
1 parent 1a4e7a8 commit ef2f408

1 file changed

Lines changed: 40 additions & 19 deletions

File tree

dojo/auditlog.py

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@
1818

1919
logger = logging.getLogger(__name__)
2020

21+
# FindingReviewers proxy model will be created lazily in register_django_pghistory_models()
22+
# Cannot be defined at module level because Finding.reviewers.through requires
23+
# Django's app registry to be ready (AppRegistryNotReady error)
24+
# The function is called from DojoAppConfig.ready() which guarantees the registry is ready
25+
2126

2227
def _flush_models_in_batches(models_to_flush, timestamp_field: str, retention_period: int, batch_size: int, max_batches: int, *, dry_run: bool = False) -> tuple[int, int, bool]:
2328
"""
@@ -339,25 +344,41 @@ def register_django_pghistory_models():
339344
# https://django-pghistory.readthedocs.io/en/2.4.2/tutorial.html#tracking-many-to-many-events
340345
# Note: For auto-generated through models, we don't specify obj_fk/obj_field
341346
# as Django doesn't allow foreign keys to auto-generated through models
342-
reviewers_through = Finding._meta.get_field("reviewers").remote_field.through
343-
344-
class FindingReviewers(reviewers_through):
345-
class Meta:
346-
proxy = True
347-
348-
pghistory.track(
349-
pghistory.InsertEvent(),
350-
pghistory.DeleteEvent(),
351-
pghistory.ManualEvent(label="initial_import"),
352-
meta={
353-
"db_table": "dojo_finding_reviewersevent",
354-
"indexes": [
355-
models.Index(fields=["pgh_created_at"]),
356-
models.Index(fields=["pgh_label"]),
357-
models.Index(fields=["pgh_context_id"]),
358-
],
359-
},
360-
)(FindingReviewers)
347+
#
348+
# We must create the proxy model here (not at module level) because:
349+
# 1. Finding.reviewers.through requires Django's app registry to be ready
350+
# 2. This function is called from DojoAppConfig.ready() which guarantees registry is ready
351+
# 3. We check if it already exists to avoid re-registration warnings
352+
#
353+
# Note: This pattern is not explicitly documented in Django's official documentation.
354+
# Django docs mention AppRegistryNotReady and AppConfig.ready() in general terms, but
355+
# don't specifically cover proxy models for auto-generated ManyToMany through tables.
356+
# This is a common pattern used by libraries like django-pghistory and is necessary
357+
# because accessing Model.field.through at module import time triggers AppRegistryNotReady.
358+
try:
359+
FindingReviewers = apps.get_model("dojo", "FindingReviewers")
360+
except LookupError:
361+
# Model doesn't exist yet, create it
362+
# Note: Finding is imported above, and apps registry is ready when this runs
363+
reviewers_through = Finding._meta.get_field("reviewers").remote_field.through
364+
365+
class FindingReviewers(reviewers_through):
366+
class Meta:
367+
proxy = True
368+
369+
pghistory.track(
370+
pghistory.InsertEvent(),
371+
pghistory.DeleteEvent(),
372+
pghistory.ManualEvent(label="initial_import"),
373+
meta={
374+
"db_table": "dojo_finding_reviewersevent",
375+
"indexes": [
376+
models.Index(fields=["pgh_created_at"]),
377+
models.Index(fields=["pgh_label"]),
378+
models.Index(fields=["pgh_context_id"]),
379+
],
380+
},
381+
)(FindingReviewers)
361382

362383
# Only log during actual application startup, not during shell commands
363384
if "shell" not in sys.argv:

0 commit comments

Comments
 (0)