Skip to content

Commit d0b7182

Browse files
authored
Merge pull request #343 from netboxlabs/342-migration
342 update init to use migration graph instead of filename
2 parents 392e830 + b490a71 commit d0b7182

File tree

1 file changed

+49
-15
lines changed

1 file changed

+49
-15
lines changed

netbox_custom_objects/__init__.py

Lines changed: 49 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,19 @@
33
import warnings
44

55
from django.db import connection, transaction
6+
from django.db.migrations.loader import MigrationLoader
67
from django.db.migrations.recorder import MigrationRecorder
78
from django.db.models.signals import pre_migrate, post_migrate
8-
from django.db.utils import DatabaseError, OperationalError, ProgrammingError
99
from netbox.plugins import PluginConfig
1010

1111
from .constants import APP_LABEL as APP_LABEL
1212

1313
# Context variable to track if we're currently running migrations
1414
_is_migrating = contextvars.ContextVar('is_migrating', default=False)
1515

16-
# Minimum migration required for the plugin to function properly
17-
# Update this when adding migrations that add fields to the plugin's models
18-
REQUIRED_MIGRATION = '0003_ensure_fk_constraints'
16+
# Cache for migration check to avoid repeated expensive filesystem/database operations
17+
_migrations_checked = None
18+
_checking_migrations = False
1919

2020

2121
def _migration_started(sender, **kwargs):
@@ -24,8 +24,10 @@ def _migration_started(sender, **kwargs):
2424

2525

2626
def _migration_finished(sender, **kwargs):
27-
"""Signal handler for post_migrate - clears the migration flag."""
27+
"""Signal handler for post_migrate - clears the migration flag and cache."""
28+
global _migrations_checked
2829
_is_migrating.set(False)
30+
_migrations_checked = None
2931

3032

3133
# Plugin Configuration
@@ -54,10 +56,12 @@ def _should_skip_dynamic_model_creation():
5456
Returns True if dynamic models should not be created/loaded due to:
5557
- Currently running migrations
5658
- Running tests
57-
- Required migration not yet applied
59+
- All migrations not yet applied
5860
5961
Returns False if it's safe to proceed with dynamic model creation.
6062
"""
63+
global _migrations_checked, _checking_migrations
64+
6165
# Skip if currently running migrations
6266
if _is_migrating.get():
6367
return True
@@ -66,17 +70,47 @@ def _should_skip_dynamic_model_creation():
6670
if "test" in sys.argv:
6771
return True
6872

69-
# Skip if required migration hasn't been applied yet
70-
try:
71-
recorder = MigrationRecorder(connection)
72-
applied_migrations = recorder.applied_migrations()
73-
if ('netbox_custom_objects', REQUIRED_MIGRATION) not in applied_migrations:
74-
return True
75-
except (DatabaseError, OperationalError, ProgrammingError):
76-
# If we can't check, assume migrations haven't been run
73+
# Below code is to check if the last migration is applied using the migration graph
74+
# However, migrations can can call into get_models() which can call into this function again
75+
# so we have checks to prevent recursion
76+
if _checking_migrations:
7777
return True
7878

79-
return False
79+
# Return cached result if available
80+
if _migrations_checked is not None:
81+
return _migrations_checked
82+
83+
_checking_migrations = True
84+
85+
try:
86+
loader = MigrationLoader(connection)
87+
88+
# Get all migrations for our app from the migration graph
89+
app_migrations = [
90+
key[1] for key in loader.graph.nodes
91+
if key[0] == APP_LABEL
92+
]
93+
94+
if not app_migrations:
95+
result = True
96+
else:
97+
# Get and check if the last migration is applied
98+
last_migration = sorted(app_migrations)[-1]
99+
recorder = MigrationRecorder(connection)
100+
applied_migrations = recorder.applied_migrations()
101+
102+
if (APP_LABEL, last_migration) not in applied_migrations:
103+
result = True
104+
else:
105+
result = False
106+
107+
# Cache the result
108+
_migrations_checked = result
109+
return result
110+
111+
finally:
112+
# Always clear the recursion flag
113+
_checking_migrations = False
80114

81115
def ready(self):
82116
from .models import CustomObjectType

0 commit comments

Comments
 (0)