diff --git a/netbox/core/signals.py b/netbox/core/signals.py index 46a0fe0fd7..1628bca06b 100644 --- a/netbox/core/signals.py +++ b/netbox/core/signals.py @@ -13,6 +13,7 @@ from django_prometheus.models import model_deletes, model_inserts, model_updates from core.choices import JobStatusChoices, ObjectChangeActionChoices from core.events import * from core.models import ObjectType +from utilities.object_types import objecttype_table_exists from extras.events import enqueue_event from extras.models import Tag from extras.utils import run_validators @@ -51,6 +52,10 @@ def update_object_types(sender, **kwargs): """ Create or update the corresponding ObjectType for each model within the migrated app. """ + # Skip ObjectType operations if the table doesn't exist yet (during migrations) + if not objecttype_table_exists(): + return + for model in sender.get_models(): app_label, model_name = model._meta.label_lower.split('.') diff --git a/netbox/netbox/models/features.py b/netbox/netbox/models/features.py index 09c2722adf..8494c0e7ad 100644 --- a/netbox/netbox/models/features.py +++ b/netbox/netbox/models/features.py @@ -24,6 +24,7 @@ from netbox.registry import registry from netbox.signals import post_clean from netbox.utils import register_model_feature from utilities.json import CustomFieldJSONEncoder +from utilities.object_types import objecttype_table_exists from utilities.serialization import serialize_object __all__ = ( @@ -670,6 +671,10 @@ def has_feature(model_or_ct, feature): """ Returns True if the model supports the specified feature. """ + # Check if ObjectType table exists before attempting queries + if not objecttype_table_exists(): + return False + # If an ObjectType was passed, we can use it directly if type(model_or_ct) is ObjectType: ot = model_or_ct diff --git a/netbox/netbox/search/backends.py b/netbox/netbox/search/backends.py index cb08ab4afb..1f4c38472c 100644 --- a/netbox/netbox/search/backends.py +++ b/netbox/netbox/search/backends.py @@ -15,6 +15,7 @@ from netaddr.core import AddrFormatError from core.models import ObjectType from extras.models import CachedValue, CustomField from netbox.registry import registry +from utilities.object_types import objecttype_table_exists from utilities.object_types import object_type_identifier from utilities.querysets import RestrictedPrefetch from utilities.string import title @@ -209,6 +210,10 @@ class CachedValueSearchBackend(SearchBackend): break # Prefetch any associated custom fields + # Skip if ObjectType table doesn't exist yet (during migrations) + if not objecttype_table_exists(): + return + object_type = ObjectType.objects.get_for_model(indexer.model) custom_fields = CustomField.objects.filter(object_types=object_type).exclude(search_weight=0) diff --git a/netbox/utilities/object_types.py b/netbox/utilities/object_types.py index 88cbbd3e88..8f5966b6d4 100644 --- a/netbox/utilities/object_types.py +++ b/netbox/utilities/object_types.py @@ -1,8 +1,11 @@ +from django.db import connection + from .string import title __all__ = ( 'object_type_identifier', 'object_type_name', + 'objecttype_table_exists', ) @@ -27,3 +30,13 @@ def object_type_name(object_type, include_app=True): except AttributeError: # Model does not exist return f'{object_type.app_label} > {object_type.model}' + + +def objecttype_table_exists(): + """ + Check if the core_objecttype table exists. + + Returns True if the table exists, False otherwise. + Used to prevent ObjectType queries during migrations when the table doesn't exist yet. + """ + return 'core_objecttype' in connection.introspection.table_names()