From 6ccd53ec0a3b8258617944c26467edf3aab7622f Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Wed, 6 May 2026 20:44:16 -0400 Subject: [PATCH 001/183] Remove backward compatibility shim for ExpandableIPAddressField Removes the deprecated ExpandableIPAddressField alias (renamed to ExpandableIPNetworkField in a prior release) per the v4.7.0 removal schedule. Closes #22053 Co-Authored-By: Claude Sonnet 4.6 --- netbox/utilities/forms/fields/expandable.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/netbox/utilities/forms/fields/expandable.py b/netbox/utilities/forms/fields/expandable.py index ea222268e..2bc59c7ad 100644 --- a/netbox/utilities/forms/fields/expandable.py +++ b/netbox/utilities/forms/fields/expandable.py @@ -1,5 +1,4 @@ import re -import warnings import netaddr from django import forms @@ -71,15 +70,3 @@ class ExpandableIPNetworkField(forms.CharField): if family == 6 and re.search(IP6_EXPANSION_PATTERN, value): return list(expand_ipnetwork_pattern(value.lower(), 6)) return [value] - - -# TODO: Remove in NetBox v4.7.0 -def __getattr__(name): - if name == 'ExpandableIPAddressField': - warnings.warn( - "ExpandableIPAddressField has been renamed to ExpandableIPNetworkField. " - "ExpandableIPAddressField will be removed in NetBox v4.7.0.", - DeprecationWarning, - ) - return ExpandableIPNetworkField - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") From caed3812fea3d501c7df45e262751347edb3d9c5 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Wed, 6 May 2026 20:43:06 -0400 Subject: [PATCH 002/183] Remove backward compatibility shim for OptionalLimitOffsetPagination Removes the deprecated OptionalLimitOffsetPagination alias (renamed to NetBoxPagination in a prior release) per the v4.7.0 removal schedule. Closes #22052 Co-Authored-By: Claude Sonnet 4.6 --- netbox/netbox/api/pagination.py | 14 -------------- netbox/netbox/tests/test_api.py | 2 +- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/netbox/netbox/api/pagination.py b/netbox/netbox/api/pagination.py index bbdc83256..eb0295662 100644 --- a/netbox/netbox/api/pagination.py +++ b/netbox/netbox/api/pagination.py @@ -1,5 +1,3 @@ -import warnings - from django.db.models import QuerySet from django.utils.translation import gettext_lazy as _ from rest_framework.exceptions import ValidationError @@ -222,15 +220,3 @@ class LimitOffsetListPagination(LimitOffsetPagination): self.display_page_controls = True return data[self.offset:self.offset + self.limit] - - -# TODO: Remove in NetBox v4.7.0 -def __getattr__(name): - if name == 'OptionalLimitOffsetPagination': - warnings.warn( - "OptionalLimitOffsetPagination has been renamed to NetBoxPagination. " - "OptionalLimitOffsetPagination will be removed in NetBox v4.7.0.", - DeprecationWarning, - ) - return NetBoxPagination - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/netbox/netbox/tests/test_api.py b/netbox/netbox/tests/test_api.py index 0cff906a4..2529e56cf 100644 --- a/netbox/netbox/tests/test_api.py +++ b/netbox/netbox/tests/test_api.py @@ -46,7 +46,7 @@ class AppTest(APITestCase): self.assertEqual(response.data['id'], self.user.pk) -class OptionalLimitOffsetPaginationTest(TestCase): +class NetBoxPaginationTest(TestCase): def setUp(self): self.paginator = NetBoxPagination() From 416def1dbc886155cbccf308662d92fade3a6534 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Wed, 6 May 2026 20:37:56 -0400 Subject: [PATCH 003/183] Closes #22054: Remove backward compatibility shim for expand_ipaddress_pattern() Removes the deprecated `expand_ipaddress_pattern()` alias and the associated `__getattr__` compatibility hook that redirected callers to `expand_ipnetwork_pattern()`. Co-Authored-By: Claude Sonnet 4.6 --- netbox/utilities/forms/utils.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/netbox/utilities/forms/utils.py b/netbox/utilities/forms/utils.py index b40ffa77c..73814c9e4 100644 --- a/netbox/utilities/forms/utils.py +++ b/netbox/utilities/forms/utils.py @@ -1,5 +1,4 @@ import re -import warnings from django import forms from django.forms.models import fields_for_model @@ -295,15 +294,3 @@ def validate_csv(headers, fields, required_fields): for f in required_fields: if f not in headers: raise forms.ValidationError(_('Required column header "{header}" not found.').format(header=f)) - - -# TODO: Remove in NetBox v4.7.0 -def __getattr__(name): - if name == 'expand_ipaddress_pattern': - warnings.warn( - "expand_ipaddress_pattern() has been renamed to expand_ipnetwork_pattern(). " - "expand_ipaddress_pattern() will be removed in NetBox v4.7.0.", - DeprecationWarning, - ) - return expand_ipnetwork_pattern - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") From a59ab6f216260ae41edbfea7ff10b1add517dd6a Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 7 May 2026 08:29:40 -0400 Subject: [PATCH 004/183] Removes the `housekeeping` management command (closes #21565) The command was deprecated in v4.6.0; all housekeeping tasks are now handled automatically by NetBox's built-in job scheduler. Co-Authored-By: Claude Sonnet 4.6 --- docs/release-notes/version-4.7.md | 13 ++ .../management/commands/housekeeping.py | 180 ------------------ 2 files changed, 13 insertions(+), 180 deletions(-) create mode 100644 docs/release-notes/version-4.7.md delete mode 100644 netbox/extras/management/commands/housekeeping.py diff --git a/docs/release-notes/version-4.7.md b/docs/release-notes/version-4.7.md new file mode 100644 index 000000000..51ff3d78a --- /dev/null +++ b/docs/release-notes/version-4.7.md @@ -0,0 +1,13 @@ +# NetBox v4.7 + +## v4.7.0 (FUTURE) + +### Breaking Changes + +### Enhancements + +### Other Changes + +* [#21565](https://github.com/netbox-community/netbox/issues/21565) - Remove the obsolete `housekeeping` management command + +### REST API Changes diff --git a/netbox/extras/management/commands/housekeeping.py b/netbox/extras/management/commands/housekeeping.py deleted file mode 100644 index e68142ac3..000000000 --- a/netbox/extras/management/commands/housekeeping.py +++ /dev/null @@ -1,180 +0,0 @@ -import warnings -from datetime import timedelta -from importlib import import_module - -import requests -from django.conf import settings -from django.core.cache import cache -from django.core.management.base import BaseCommand -from django.db.models import Exists, OuterRef, Subquery -from django.utils import timezone -from packaging import version - -from core.choices import ObjectChangeActionChoices -from core.models import Job, ObjectChange -from netbox.config import Config -from utilities.proxy import resolve_proxies - - -class Command(BaseCommand): - help = "Perform nightly housekeeping tasks [DEPRECATED]" - - def handle(self, *args, **options): - warnings.warn( - "\n\nDEPRECATION WARNING\n" - "Running this command is no longer necessary: All housekeeping tasks\n" - "are addressed automatically via NetBox's built-in job scheduler. It\n" - "will be removed in a future release.\n", - category=FutureWarning, - ) - - config = Config() - - # Clear expired authentication sessions (essentially replicating the `clearsessions` command) - if options['verbosity']: - self.stdout.write("[*] Clearing expired authentication sessions") - if options['verbosity'] >= 2: - self.stdout.write(f"\tConfigured session engine: {settings.SESSION_ENGINE}") - engine = import_module(settings.SESSION_ENGINE) - try: - engine.SessionStore.clear_expired() - if options['verbosity']: - self.stdout.write("\tSessions cleared.", self.style.SUCCESS) - except NotImplementedError: - if options['verbosity']: - self.stdout.write( - f"\tThe configured session engine ({settings.SESSION_ENGINE}) does not support " - f"clearing sessions; skipping." - ) - - # Delete expired ObjectChanges - if options['verbosity']: - self.stdout.write('[*] Checking for expired changelog records') - if config.CHANGELOG_RETENTION: - cutoff = timezone.now() - timedelta(days=config.CHANGELOG_RETENTION) - if options['verbosity'] >= 2: - self.stdout.write(f'\tRetention period: {config.CHANGELOG_RETENTION} days') - self.stdout.write(f'\tCut-off time: {cutoff}') - - expired_qs = ObjectChange.objects.filter(time__lt=cutoff) - - # When enabled, retain each object's original create and most recent update record while pruning expired - # changelog entries. This applies only to objects without a delete record. - if config.CHANGELOG_RETAIN_CREATE_LAST_UPDATE: - if options['verbosity'] >= 2: - self.stdout.write('\tRetaining create & last update records for non-deleted objects') - - deleted_exists = ObjectChange.objects.filter( - action=ObjectChangeActionChoices.ACTION_DELETE, - changed_object_type_id=OuterRef('changed_object_type_id'), - changed_object_id=OuterRef('changed_object_id'), - ) - - # Keep create records only where no delete exists for that object - create_pks_to_keep = ( - ObjectChange.objects.filter(action=ObjectChangeActionChoices.ACTION_CREATE) - .annotate(has_delete=Exists(deleted_exists)) - .filter(has_delete=False) - .values('pk') - ) - - # Keep the most recent update per object only where no delete exists for the object - latest_update_pks_to_keep = ( - ObjectChange.objects.filter(action=ObjectChangeActionChoices.ACTION_UPDATE) - .annotate(has_delete=Exists(deleted_exists)) - .filter(has_delete=False) - .order_by('changed_object_type_id', 'changed_object_id', '-time', '-pk') - .distinct('changed_object_type_id', 'changed_object_id') - .values('pk') - ) - - expired_qs = expired_qs.exclude(pk__in=Subquery(create_pks_to_keep)) - expired_qs = expired_qs.exclude(pk__in=Subquery(latest_update_pks_to_keep)) - - expired_records = expired_qs.count() - if expired_records: - if options['verbosity']: - self.stdout.write( - f'\tDeleting {expired_records} expired records... ', self.style.WARNING, ending='' - ) - self.stdout.flush() - expired_qs.delete() - if options['verbosity']: - self.stdout.write('Done.', self.style.SUCCESS) - elif options['verbosity']: - self.stdout.write('\tNo expired records found.', self.style.SUCCESS) - elif options['verbosity']: - self.stdout.write( - f'\tSkipping: No retention period specified (CHANGELOG_RETENTION = {config.CHANGELOG_RETENTION})' - ) - - # Delete expired Jobs - if options['verbosity']: - self.stdout.write("[*] Checking for expired jobs") - if config.JOB_RETENTION: - cutoff = timezone.now() - timedelta(days=config.JOB_RETENTION) - if options['verbosity'] >= 2: - self.stdout.write(f"\tRetention period: {config.JOB_RETENTION} days") - self.stdout.write(f"\tCut-off time: {cutoff}") - expired_records = Job.objects.filter(created__lt=cutoff).count() - if expired_records: - if options['verbosity']: - self.stdout.write( - f"\tDeleting {expired_records} expired records... ", - self.style.WARNING, - ending="" - ) - self.stdout.flush() - Job.objects.filter(created__lt=cutoff).delete() - if options['verbosity']: - self.stdout.write("Done.", self.style.SUCCESS) - elif options['verbosity']: - self.stdout.write("\tNo expired records found.", self.style.SUCCESS) - elif options['verbosity']: - self.stdout.write( - f"\tSkipping: No retention period specified (JOB_RETENTION = {config.JOB_RETENTION})" - ) - - # Check for new releases (if enabled) - if options['verbosity']: - self.stdout.write("[*] Checking for latest release") - if settings.ISOLATED_DEPLOYMENT: - if options['verbosity']: - self.stdout.write("\tSkipping: ISOLATED_DEPLOYMENT is enabled") - elif settings.RELEASE_CHECK_URL: - headers = { - 'Accept': 'application/vnd.github.v3+json', - } - - try: - if options['verbosity'] >= 2: - self.stdout.write(f"\tFetching {settings.RELEASE_CHECK_URL}") - response = requests.get( - url=settings.RELEASE_CHECK_URL, - headers=headers, - proxies=resolve_proxies(url=settings.RELEASE_CHECK_URL) - ) - response.raise_for_status() - - releases = [] - for release in response.json(): - if 'tag_name' not in release or release.get('devrelease') or release.get('prerelease'): - continue - releases.append((version.parse(release['tag_name']), release.get('html_url'))) - latest_release = max(releases) - if options['verbosity'] >= 2: - self.stdout.write(f"\tFound {len(response.json())} releases; {len(releases)} usable") - if options['verbosity']: - self.stdout.write(f"\tLatest release: {latest_release[0]}", self.style.SUCCESS) - - # Cache the most recent release - cache.set('latest_release', latest_release, None) - - except requests.exceptions.RequestException as exc: - self.stdout.write(f"\tRequest error: {exc}", self.style.ERROR) - else: - if options['verbosity']: - self.stdout.write("\tSkipping: RELEASE_CHECK_URL not set") - - if options['verbosity']: - self.stdout.write("Finished.", self.style.SUCCESS) From 2562216006977961bfae1f0a5d58381aee872de8 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 7 May 2026 08:43:45 -0400 Subject: [PATCH 005/183] Remove v4.7 release notes from branch Co-Authored-By: Claude Sonnet 4.6 --- docs/release-notes/version-4.7.md | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 docs/release-notes/version-4.7.md diff --git a/docs/release-notes/version-4.7.md b/docs/release-notes/version-4.7.md deleted file mode 100644 index 51ff3d78a..000000000 --- a/docs/release-notes/version-4.7.md +++ /dev/null @@ -1,13 +0,0 @@ -# NetBox v4.7 - -## v4.7.0 (FUTURE) - -### Breaking Changes - -### Enhancements - -### Other Changes - -* [#21565](https://github.com/netbox-community/netbox/issues/21565) - Remove the obsolete `housekeeping` management command - -### REST API Changes From 9275db607e71c11321583ff43457c451c10e5024 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 7 May 2026 08:30:25 -0400 Subject: [PATCH 006/183] Remove the DEFAULT_ACTION_PERMISSIONS constant (closes #21886) Removes the deprecated _DEFAULT_ACTION_PERMISSIONS dict and its __getattr__ compatibility shim from netbox/constants.py. Action permissions should be defined via ObjectAction subclasses. Co-Authored-By: Claude Sonnet 4.6 --- docs/release-notes/version-4.7.md | 13 +++++++++++++ netbox/netbox/constants.py | 24 ------------------------ 2 files changed, 13 insertions(+), 24 deletions(-) create mode 100644 docs/release-notes/version-4.7.md diff --git a/docs/release-notes/version-4.7.md b/docs/release-notes/version-4.7.md new file mode 100644 index 000000000..eb22e8ef5 --- /dev/null +++ b/docs/release-notes/version-4.7.md @@ -0,0 +1,13 @@ +# NetBox v4.7 + +## v4.7.0 (FUTURE) + +### Breaking Changes + +### Enhancements + +### Other Changes + +* [#21886](https://github.com/netbox-community/netbox/issues/21886) - Remove the obsolete `DEFAULT_ACTION_PERMISSIONS` constant + +### REST API Changes diff --git a/netbox/netbox/constants.py b/netbox/netbox/constants.py index efe42c383..b226c606c 100644 --- a/netbox/netbox/constants.py +++ b/netbox/netbox/constants.py @@ -44,30 +44,6 @@ ADVISORY_LOCK_KEYS = { 'job-schedules': 110100, } -# TODO: Remove in NetBox v4.7 -# Legacy default view action permission mapping -_DEFAULT_ACTION_PERMISSIONS = { - 'add': {'add'}, - 'export': {'view'}, - 'bulk_import': {'add'}, - 'bulk_edit': {'change'}, - 'bulk_delete': {'delete'}, -} - - -def __getattr__(name): - if name == 'DEFAULT_ACTION_PERMISSIONS': - import warnings - warnings.warn( - f"{name} is deprecated and will be removed in NetBox v4.7. " - "Define action permissions via ObjectAction subclasses instead.", - DeprecationWarning, - stacklevel=2, - ) - return _DEFAULT_ACTION_PERMISSIONS - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") - - # General-purpose tokens CENSOR_TOKEN = '********' CENSOR_TOKEN_CHANGED = '***CHANGED***' From 9e70e297a512c2d31d8d49688c7b72cab93c4754 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 7 May 2026 08:43:46 -0400 Subject: [PATCH 007/183] Remove v4.7 release notes from branch Co-Authored-By: Claude Sonnet 4.6 --- docs/release-notes/version-4.7.md | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 docs/release-notes/version-4.7.md diff --git a/docs/release-notes/version-4.7.md b/docs/release-notes/version-4.7.md deleted file mode 100644 index eb22e8ef5..000000000 --- a/docs/release-notes/version-4.7.md +++ /dev/null @@ -1,13 +0,0 @@ -# NetBox v4.7 - -## v4.7.0 (FUTURE) - -### Breaking Changes - -### Enhancements - -### Other Changes - -* [#21886](https://github.com/netbox-community/netbox/issues/21886) - Remove the obsolete `DEFAULT_ACTION_PERMISSIONS` constant - -### REST API Changes From 5b20197e971274c561a7c8e10479825918505b03 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 7 May 2026 08:32:38 -0400 Subject: [PATCH 008/183] Drop support for deprecated Sentry config parameters (closes #21883) Removes SENTRY_DSN, SENTRY_SAMPLE_RATE, SENTRY_SEND_DEFAULT_PII, and SENTRY_TRACES_SAMPLE_RATE. These were superseded by SENTRY_CONFIG in v4.4.2. Documentation updated to use SENTRY_CONFIG exclusively. Co-Authored-By: Claude Sonnet 4.6 --- docs/administration/error-reporting.md | 6 ++- docs/configuration/error-reporting.md | 75 -------------------------- docs/release-notes/version-4.7.md | 15 ++++++ netbox/netbox/settings.py | 26 ++------- 4 files changed, 23 insertions(+), 99 deletions(-) create mode 100644 docs/release-notes/version-4.7.md diff --git a/docs/administration/error-reporting.md b/docs/administration/error-reporting.md index 8b4312273..10dc71f31 100644 --- a/docs/administration/error-reporting.md +++ b/docs/administration/error-reporting.md @@ -4,11 +4,13 @@ ### Enabling Error Reporting -NetBox supports native integration with [Sentry](https://sentry.io/) for automatic error reporting. To enable this functionality, set `SENTRY_ENABLED` to `True` and define your unique [data source name (DSN)](https://docs.sentry.io/product/sentry-basics/concepts/dsn-explainer/) in `configuration.py`. +NetBox supports native integration with [Sentry](https://sentry.io/) for automatic error reporting. To enable this functionality, set `SENTRY_ENABLED` to `True` and define your unique [data source name (DSN)](https://docs.sentry.io/product/sentry-basics/concepts/dsn-explainer/) in `configuration.py` via `SENTRY_CONFIG`. ```python SENTRY_ENABLED = True -SENTRY_DSN = "https://examplePublicKey@o0.ingest.sentry.io/0" +SENTRY_CONFIG = { + "dsn": "https://examplePublicKey@o0.ingest.sentry.io/0", +} ``` Setting `SENTRY_ENABLED` to False will disable the Sentry integration. diff --git a/docs/configuration/error-reporting.md b/docs/configuration/error-reporting.md index 2d287ef06..a3bc87355 100644 --- a/docs/configuration/error-reporting.md +++ b/docs/configuration/error-reporting.md @@ -16,27 +16,6 @@ The default configuration is shown below: Additionally, `http_proxy` and `https_proxy` are set to the HTTP and HTTPS proxies, respectively, configured for NetBox (if any). -## SENTRY_DSN - -!!! warning "This parameter will be removed in NetBox v4.5." - Set this using `SENTRY_CONFIG` instead: - - ``` - SENTRY_CONFIG = { - "dsn": "https://examplePublicKey@o0.ingest.sentry.io/0", - } - ``` - -Default: `None` - -Defines a Sentry data source name (DSN) for automated error reporting. `SENTRY_ENABLED` must be `True` for this parameter to take effect. For example: - -``` -SENTRY_DSN = "https://examplePublicKey@o0.ingest.sentry.io/0" -``` - ---- - ## SENTRY_ENABLED Default: `False` @@ -48,43 +27,6 @@ Set to `True` to enable automatic error reporting via [Sentry](https://sentry.io --- -## SENTRY_SAMPLE_RATE - -!!! warning "This parameter will be removed in NetBox v4.5." - Set this using `SENTRY_CONFIG` instead: - - ``` - SENTRY_CONFIG = { - "sample_rate": 0.2, - } - ``` - -Default: `1.0` (all) - -The sampling rate for errors. Must be a value between 0 (disabled) and 1.0 (report on all errors). - ---- - -## SENTRY_SEND_DEFAULT_PII - -!!! warning "This parameter will be removed in NetBox v4.5." - Set this using `SENTRY_CONFIG` instead: - - ``` - SENTRY_CONFIG = { - "send_default_pii": True, - } - ``` - -Default: `False` - -Maps to the Sentry SDK's [`send_default_pii`](https://docs.sentry.io/platforms/python/configuration/options/#send-default-pii) parameter. If enabled, certain personally identifiable information (PII) is added. - -!!! warning "Sensitive data" - If you enable this option, be aware that sensitive data such as cookies and authentication tokens will be logged. - ---- - ## SENTRY_TAGS An optional dictionary of tag names and values to apply to Sentry error reports.For example: @@ -101,20 +43,3 @@ SENTRY_TAGS = { --- -## SENTRY_TRACES_SAMPLE_RATE - -!!! warning "This parameter will be removed in NetBox v4.5." - Set this using `SENTRY_CONFIG` instead: - - ``` - SENTRY_CONFIG = { - "traces_sample_rate": 0.2, - } - ``` - -Default: `0` (disabled) - -The sampling rate for transactions. Must be a value between 0 (disabled) and 1.0 (report on all transactions). - -!!! warning "Consider performance implications" - A high sampling rate for transactions can induce significant performance penalties. If transaction reporting is desired, it is recommended to use a relatively low sample rate of 10% to 20% (0.1 to 0.2). diff --git a/docs/release-notes/version-4.7.md b/docs/release-notes/version-4.7.md new file mode 100644 index 000000000..5172727ac --- /dev/null +++ b/docs/release-notes/version-4.7.md @@ -0,0 +1,15 @@ +# NetBox v4.7 + +## v4.7.0 (FUTURE) + +### Breaking Changes + +* The following deprecated Sentry configuration parameters have been removed: `SENTRY_DSN`, `SENTRY_SAMPLE_RATE`, `SENTRY_SEND_DEFAULT_PII`, and `SENTRY_TRACES_SAMPLE_RATE`. Use the `SENTRY_CONFIG` parameter instead. + +### Enhancements + +### Other Changes + +* [#21883](https://github.com/netbox-community/netbox/issues/21883) - Drop support for deprecated Sentry configuration parameters + +### REST API Changes diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index 33631f943..75e34a635 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -181,16 +181,8 @@ SECURE_HSTS_PRELOAD = getattr(configuration, 'SECURE_HSTS_PRELOAD', False) SECURE_HSTS_SECONDS = getattr(configuration, 'SECURE_HSTS_SECONDS', 0) SECURE_SSL_REDIRECT = getattr(configuration, 'SECURE_SSL_REDIRECT', False) SENTRY_CONFIG = getattr(configuration, 'SENTRY_CONFIG', {}) -# TODO: Remove in NetBox v4.7 -SENTRY_DSN = getattr(configuration, 'SENTRY_DSN', None) SENTRY_ENABLED = getattr(configuration, 'SENTRY_ENABLED', False) -# TODO: Remove in NetBox v4.7 -SENTRY_SAMPLE_RATE = getattr(configuration, 'SENTRY_SAMPLE_RATE', 1.0) -# TODO: Remove in NetBox v4.7 -SENTRY_SEND_DEFAULT_PII = getattr(configuration, 'SENTRY_SEND_DEFAULT_PII', False) SENTRY_TAGS = getattr(configuration, 'SENTRY_TAGS', {}) -# TODO: Remove in NetBox v4.7 -SENTRY_TRACES_SAMPLE_RATE = getattr(configuration, 'SENTRY_TRACES_SAMPLE_RATE', 0) SESSION_COOKIE_NAME = getattr(configuration, 'SESSION_COOKIE_NAME', 'sessionid') SESSION_COOKIE_PATH = CSRF_COOKIE_PATH SESSION_COOKIE_SECURE = getattr(configuration, 'SESSION_COOKIE_SECURE', False) @@ -637,31 +629,21 @@ MAINTENANCE_EXEMPT_PATHS = ( # Sentry # -# Warn on the presence of deprecated Sentry config parameters -for config_param in ('SENTRY_DSN', 'SENTRY_SAMPLE_RATE', 'SENTRY_SEND_DEFAULT_PII', 'SENTRY_TRACES_SAMPLE_RATE'): - if hasattr(configuration, config_param): - warnings.warn( - f"{config_param} is deprecated and will be removed in NetBox v4.7. Use SENTRY_CONFIG instead.", - DeprecationWarning, - ) - if SENTRY_ENABLED: try: import sentry_sdk except ModuleNotFoundError: raise ImproperlyConfigured("SENTRY_ENABLED is True but the sentry-sdk package is not installed.") - # Construct default Sentry initialization parameters from legacy SENTRY_* config parameters + # Build the Sentry initialization parameters sentry_config = { - 'dsn': SENTRY_DSN, - 'sample_rate': SENTRY_SAMPLE_RATE, - 'send_default_pii': SENTRY_SEND_DEFAULT_PII, - 'traces_sample_rate': SENTRY_TRACES_SAMPLE_RATE, + 'sample_rate': 1.0, + 'send_default_pii': False, + 'traces_sample_rate': 0, # TODO: Support proxy routing 'http_proxy': HTTP_PROXIES.get('http') if HTTP_PROXIES else None, 'https_proxy': HTTP_PROXIES.get('https') if HTTP_PROXIES else None, } - # Override/extend the default parameters with any provided via SENTRY_CONFIG sentry_config.update(SENTRY_CONFIG) # Check for a DSN if not sentry_config.get('dsn'): From ce1691663d0b204a549168af7bee1dd869ff80e6 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 7 May 2026 08:43:47 -0400 Subject: [PATCH 009/183] Remove v4.7 release notes from branch Co-Authored-By: Claude Sonnet 4.6 --- docs/release-notes/version-4.7.md | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 docs/release-notes/version-4.7.md diff --git a/docs/release-notes/version-4.7.md b/docs/release-notes/version-4.7.md deleted file mode 100644 index 5172727ac..000000000 --- a/docs/release-notes/version-4.7.md +++ /dev/null @@ -1,15 +0,0 @@ -# NetBox v4.7 - -## v4.7.0 (FUTURE) - -### Breaking Changes - -* The following deprecated Sentry configuration parameters have been removed: `SENTRY_DSN`, `SENTRY_SAMPLE_RATE`, `SENTRY_SEND_DEFAULT_PII`, and `SENTRY_TRACES_SAMPLE_RATE`. Use the `SENTRY_CONFIG` parameter instead. - -### Enhancements - -### Other Changes - -* [#21883](https://github.com/netbox-community/netbox/issues/21883) - Drop support for deprecated Sentry configuration parameters - -### REST API Changes From 4418beeb07741e7c920b4f54bf97cdb0b60356f9 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 7 May 2026 08:33:59 -0400 Subject: [PATCH 010/183] Remove support for legacy action views (closes #21888) Drops the LEGACY_ACTIONS constant and ActionsMixin._convert_legacy_actions() method. Action views must now define the actions attribute as a list of ObjectAction subclasses rather than as a legacy permission dict. Co-Authored-By: Claude Sonnet 4.6 --- docs/release-notes/version-4.7.md | 13 +++++++++ netbox/netbox/views/generic/mixins.py | 42 --------------------------- 2 files changed, 13 insertions(+), 42 deletions(-) create mode 100644 docs/release-notes/version-4.7.md diff --git a/docs/release-notes/version-4.7.md b/docs/release-notes/version-4.7.md new file mode 100644 index 000000000..7dce85ed8 --- /dev/null +++ b/docs/release-notes/version-4.7.md @@ -0,0 +1,13 @@ +# NetBox v4.7 + +## v4.7.0 (FUTURE) + +### Breaking Changes + +### Enhancements + +### Other Changes + +* [#21888](https://github.com/netbox-community/netbox/issues/21888) - Remove support for legacy view action mappings from `ActionsMixin`; drop the `LEGACY_ACTIONS` constant + +### REST API Changes diff --git a/netbox/netbox/views/generic/mixins.py b/netbox/netbox/views/generic/mixins.py index 2945e0e33..e47188a77 100644 --- a/netbox/netbox/views/generic/mixins.py +++ b/netbox/netbox/views/generic/mixins.py @@ -1,7 +1,6 @@ from django.shortcuts import get_object_or_404 from extras.models import TableConfig -from netbox import object_actions from utilities.permissions import get_permission_for_model __all__ = ( @@ -9,18 +8,6 @@ __all__ = ( 'TableMixin', ) -# TODO: Remove in NetBox v4.7 -LEGACY_ACTIONS = { - 'add': object_actions.AddObject, - 'edit': object_actions.EditObject, - 'delete': object_actions.DeleteObject, - 'export': object_actions.BulkExport, - 'bulk_import': object_actions.BulkImport, - 'bulk_edit': object_actions.BulkEdit, - 'bulk_rename': object_actions.BulkRename, - 'bulk_delete': object_actions.BulkDelete, -} - class ActionsMixin: """ @@ -33,41 +20,12 @@ class ActionsMixin: """ actions = tuple() - # TODO: Remove in NetBox v4.7 - def _convert_legacy_actions(self): - """ - Convert a legacy dictionary mapping action name to required permissions to a list of ObjectAction subclasses. - """ - if type(self.actions) is not dict: - return - - import warnings - warnings.warn( - f"{self.__class__.__name__}.actions is defined as a dictionary, which is deprecated and will be removed " - "in NetBox v4.7. Define actions as a list of ObjectAction subclasses instead.", - DeprecationWarning, - stacklevel=2, - ) - - actions = [] - for name in self.actions.keys(): - try: - actions.append(LEGACY_ACTIONS[name]) - except KeyError: - raise ValueError(f"Unsupported legacy action: {name}") - - self.actions = actions - def get_permitted_actions(self, user, model=None): """ Return a tuple of actions for which the given user is permitted to do. """ model = model or self.queryset.model - # TODO: Remove in NetBox v4.7 - # Handle legacy action sets - self._convert_legacy_actions() - # Resolve required permissions for each action permitted_actions = [] for action in self.actions: From 4d9e4838d41eb723f654ceada3a6fddbc90aad08 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 7 May 2026 08:43:48 -0400 Subject: [PATCH 011/183] Remove v4.7 release notes from branch Co-Authored-By: Claude Sonnet 4.6 --- docs/release-notes/version-4.7.md | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 docs/release-notes/version-4.7.md diff --git a/docs/release-notes/version-4.7.md b/docs/release-notes/version-4.7.md deleted file mode 100644 index 7dce85ed8..000000000 --- a/docs/release-notes/version-4.7.md +++ /dev/null @@ -1,13 +0,0 @@ -# NetBox v4.7 - -## v4.7.0 (FUTURE) - -### Breaking Changes - -### Enhancements - -### Other Changes - -* [#21888](https://github.com/netbox-community/netbox/issues/21888) - Remove support for legacy view action mappings from `ActionsMixin`; drop the `LEGACY_ACTIONS` constant - -### REST API Changes From 3b145a9c3dfdc1c4af3d296f61de43f7680f58c8 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 7 May 2026 08:35:42 -0400 Subject: [PATCH 012/183] Remove the `models` key from the application registry (closes #21891) Drops the deprecated registry['models'] key, the __getitem__ deprecation warning, and the population code in register_model(). Registered models should be retrieved via ObjectType.objects.public() instead. Co-Authored-By: Claude Sonnet 4.6 --- docs/release-notes/version-4.7.md | 13 +++++++++++++ netbox/netbox/context_processors.py | 2 +- netbox/netbox/models/features.py | 5 ----- netbox/netbox/registry.py | 11 ----------- 4 files changed, 14 insertions(+), 17 deletions(-) create mode 100644 docs/release-notes/version-4.7.md diff --git a/docs/release-notes/version-4.7.md b/docs/release-notes/version-4.7.md new file mode 100644 index 000000000..07b905f60 --- /dev/null +++ b/docs/release-notes/version-4.7.md @@ -0,0 +1,13 @@ +# NetBox v4.7 + +## v4.7.0 (FUTURE) + +### Breaking Changes + +### Enhancements + +### Other Changes + +* [#21891](https://github.com/netbox-community/netbox/issues/21891) - Remove the `models` key from the application registry (use `ObjectType.objects.public()` instead) + +### REST API Changes diff --git a/netbox/netbox/context_processors.py b/netbox/netbox/context_processors.py index eeeb442b4..1ff919a0c 100644 --- a/netbox/netbox/context_processors.py +++ b/netbox/netbox/context_processors.py @@ -38,7 +38,7 @@ def preferences(request): def registry(request): """ - Adds NetBox registry items to the template context. Example: {{ registry.models.core }} + Adds NetBox registry items to the template context. """ return { 'registry': registry_, diff --git a/netbox/netbox/models/features.py b/netbox/netbox/models/features.py index 993828c1b..4f59936df 100644 --- a/netbox/netbox/models/features.py +++ b/netbox/netbox/models/features.py @@ -723,11 +723,6 @@ def register_models(*models): for model in models: app_label, model_name = model._meta.label_lower.split('.') - # TODO: Remove in NetBox v4.7 - # Register public models (access the underlying dict directly to avoid triggering the deprecation warning) - if not getattr(model, '_netbox_private', False): - dict.__getitem__(registry, 'models')[app_label].add(model_name) - # Register applicable feature views for the model if issubclass(model, ContactsMixin): register_model_view(model, 'contacts', kwargs={'model': model})( diff --git a/netbox/netbox/registry.py b/netbox/netbox/registry.py index f894a11b0..351f3cd2a 100644 --- a/netbox/netbox/registry.py +++ b/netbox/netbox/registry.py @@ -9,15 +9,6 @@ class Registry(dict): removed (though the value of each key is mutable). """ def __getitem__(self, key): - # TODO: Remove in NetBox v4.7 - if key == 'models': - import warnings - warnings.warn( - 'The "models" registry key is deprecated and will be removed in NetBox v4.7. Registered models can be ' - 'obtained by calling ObjectType.objects.public().', - DeprecationWarning, - stacklevel=2, - ) try: return super().__getitem__(key) except KeyError: @@ -39,8 +30,6 @@ registry = Registry({ 'filtersets': dict(), 'model_actions': collections.defaultdict(set), 'model_features': dict(), - # TODO: Remove in NetBox v4.7 - 'models': collections.defaultdict(set), 'plugins': dict(), 'request_processors': list(), 'search': dict(), From 5cfcdf9b7ae7ad21b8bf528f8f9b493cfb2c1df0 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 7 May 2026 08:43:49 -0400 Subject: [PATCH 013/183] Remove v4.7 release notes from branch Co-Authored-By: Claude Sonnet 4.6 --- docs/release-notes/version-4.7.md | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 docs/release-notes/version-4.7.md diff --git a/docs/release-notes/version-4.7.md b/docs/release-notes/version-4.7.md deleted file mode 100644 index 07b905f60..000000000 --- a/docs/release-notes/version-4.7.md +++ /dev/null @@ -1,13 +0,0 @@ -# NetBox v4.7 - -## v4.7.0 (FUTURE) - -### Breaking Changes - -### Enhancements - -### Other Changes - -* [#21891](https://github.com/netbox-community/netbox/issues/21891) - Remove the `models` key from the application registry (use `ObjectType.objects.public()` instead) - -### REST API Changes From 0ac9f5c1742aad1822be899e72ed5bddb876771d Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 7 May 2026 08:38:26 -0400 Subject: [PATCH 014/183] Raise minimum required PostgreSQL version from 14 to 15 (closes #20546) PostgreSQL 14 reaches end-of-life in November 2026 and Django 6.1 will require PostgreSQL 15+. Updates all documentation references from 14 to 15, and removes the "needed on PostgreSQL 15 and later" conditional comment from the database creation instructions (since 15 is now the minimum). Co-Authored-By: Claude Sonnet 4.6 --- docs/configuration/required-parameters.md | 2 +- docs/installation/1-postgresql.md | 7 +++---- docs/installation/index.md | 2 +- docs/installation/upgrading.md | 2 +- docs/introduction.md | 2 +- docs/release-notes/version-4.7.md | 15 +++++++++++++++ 6 files changed, 22 insertions(+), 8 deletions(-) create mode 100644 docs/release-notes/version-4.7.md diff --git a/docs/configuration/required-parameters.md b/docs/configuration/required-parameters.md index 72573afad..2255ff462 100644 --- a/docs/configuration/required-parameters.md +++ b/docs/configuration/required-parameters.md @@ -59,7 +59,7 @@ See the [`DATABASES`](#databases) configuration below for usage. ## DATABASES -NetBox requires access to a PostgreSQL 14 or later database service to store data. This service can run locally on the NetBox server or on a remote system. Databases are defined as named dictionaries: +NetBox requires access to a PostgreSQL 15 or later database service to store data. This service can run locally on the NetBox server or on a remote system. Databases are defined as named dictionaries: ```python DATABASES = { diff --git a/docs/installation/1-postgresql.md b/docs/installation/1-postgresql.md index 41751fc10..7dac7cf46 100644 --- a/docs/installation/1-postgresql.md +++ b/docs/installation/1-postgresql.md @@ -2,8 +2,8 @@ This section entails the installation and configuration of a local PostgreSQL database. If you already have a PostgreSQL database service in place, skip to [the next section](2-redis.md). -!!! warning "PostgreSQL 14 or later required" - NetBox requires PostgreSQL 14 or later. Please note that MySQL and other relational databases are **not** supported. +!!! warning "PostgreSQL 15 or later required" + NetBox requires PostgreSQL 15 or later. Please note that MySQL and other relational databases are **not** supported. ## Installation @@ -12,7 +12,7 @@ sudo apt update sudo apt install -y postgresql ``` -Before continuing, verify that you have installed PostgreSQL 14 or later: +Before continuing, verify that you have installed PostgreSQL 15 or later: ```no-highlight psql -V @@ -32,7 +32,6 @@ Within the shell, enter the following commands to create the database and user ( CREATE DATABASE netbox; CREATE USER netbox WITH PASSWORD 'J5brHrAXFLQSif0K'; ALTER DATABASE netbox OWNER TO netbox; --- the next two commands are needed on PostgreSQL 15 and later \connect netbox; GRANT CREATE ON SCHEMA public TO netbox; ``` diff --git a/docs/installation/index.md b/docs/installation/index.md index 7ef8dd0d4..b514df448 100644 --- a/docs/installation/index.md +++ b/docs/installation/index.md @@ -28,7 +28,7 @@ The following sections detail how to set up a new instance of NetBox: | Dependency | Supported Versions | |------------|--------------------| | Python | 3.12, 3.13, 3.14 | -| PostgreSQL | 14+ | +| PostgreSQL | 15+ | | Redis | 4.0+ | Below is a simplified overview of the NetBox application stack for reference: diff --git a/docs/installation/upgrading.md b/docs/installation/upgrading.md index 5110def57..e6c60c80c 100644 --- a/docs/installation/upgrading.md +++ b/docs/installation/upgrading.md @@ -20,7 +20,7 @@ NetBox requires the following dependencies: | Dependency | Supported Versions | |------------|--------------------| | Python | 3.12, 3.13, 3.14 | -| PostgreSQL | 14+ | +| PostgreSQL | 15+ | | Redis | 4.0+ | ### Version History diff --git a/docs/introduction.md b/docs/introduction.md index c8e5ee8ac..1b7cf5316 100644 --- a/docs/introduction.md +++ b/docs/introduction.md @@ -79,5 +79,5 @@ NetBox is built on the [Django](https://djangoproject.com/) Python framework and | HTTP service | nginx or Apache | | WSGI service | gunicorn or uWSGI | | Application | Django/Python | -| Database | PostgreSQL 14+ | +| Database | PostgreSQL 15+ | | Task queuing | Redis/django-rq | diff --git a/docs/release-notes/version-4.7.md b/docs/release-notes/version-4.7.md new file mode 100644 index 000000000..76931f7a1 --- /dev/null +++ b/docs/release-notes/version-4.7.md @@ -0,0 +1,15 @@ +# NetBox v4.7 + +## v4.7.0 (FUTURE) + +### Breaking Changes + +* The minimum required PostgreSQL version has been raised from 14 to 15. + +### Enhancements + +### Other Changes + +* [#20546](https://github.com/netbox-community/netbox/issues/20546) - Raise the minimum required PostgreSQL version from 14 to 15 + +### REST API Changes From 14f3d9c791d70234157e4b0e9f843fcf1a60cf3a Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 7 May 2026 08:43:51 -0400 Subject: [PATCH 015/183] Remove v4.7 release notes from branch Co-Authored-By: Claude Sonnet 4.6 --- docs/release-notes/version-4.7.md | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 docs/release-notes/version-4.7.md diff --git a/docs/release-notes/version-4.7.md b/docs/release-notes/version-4.7.md deleted file mode 100644 index 76931f7a1..000000000 --- a/docs/release-notes/version-4.7.md +++ /dev/null @@ -1,15 +0,0 @@ -# NetBox v4.7 - -## v4.7.0 (FUTURE) - -### Breaking Changes - -* The minimum required PostgreSQL version has been raised from 14 to 15. - -### Enhancements - -### Other Changes - -* [#20546](https://github.com/netbox-community/netbox/issues/20546) - Raise the minimum required PostgreSQL version from 14 to 15 - -### REST API Changes From b277d9265466608e3108de9f6675b52e718c4ef8 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 7 May 2026 08:41:01 -0400 Subject: [PATCH 016/183] Remove the custom querystring template tag (closes #19091) Removes the deprecated querystring template tag from utilities/templatetags/ helpers.py and updates all 30 call sites across templates to use Django's built-in querystring tag (available since Django 5.1). The request argument is dropped since the built-in tag reads from the template context automatically. Co-Authored-By: Claude Sonnet 4.6 --- docs/release-notes/version-4.7.md | 13 ++++++++++ .../templates/dcim/rack_elevation_list.html | 8 +++---- netbox/templates/dcim/rack_list.html | 2 +- netbox/templates/generic/bulk_add.html | 2 +- netbox/templates/inc/paginator.html | 16 ++++++------- .../ipam/inc/ipaddress_edit_header.html | 6 ++--- netbox/templates/ipam/inc/max_depth.html | 4 ++-- netbox/templates/ipam/inc/max_length.html | 4 ++-- .../ipam/inc/prefix_edit_header.html | 4 ++-- .../templates/ipam/inc/toggle_available.html | 6 ++--- netbox/templates/ipam/ipaddress_assign.html | 2 +- netbox/utilities/templatetags/helpers.py | 24 ------------------- 12 files changed, 40 insertions(+), 51 deletions(-) create mode 100644 docs/release-notes/version-4.7.md diff --git a/docs/release-notes/version-4.7.md b/docs/release-notes/version-4.7.md new file mode 100644 index 000000000..f46cd5076 --- /dev/null +++ b/docs/release-notes/version-4.7.md @@ -0,0 +1,13 @@ +# NetBox v4.7 + +## v4.7.0 (FUTURE) + +### Breaking Changes + +### Enhancements + +### Other Changes + +* [#19091](https://github.com/netbox-community/netbox/issues/19091) - Remove the custom `querystring` template tag (use Django's built-in tag instead) + +### REST API Changes diff --git a/netbox/templates/dcim/rack_elevation_list.html b/netbox/templates/dcim/rack_elevation_list.html index 828e862eb..dcab72eeb 100644 --- a/netbox/templates/dcim/rack_elevation_list.html +++ b/netbox/templates/dcim/rack_elevation_list.html @@ -8,7 +8,7 @@ {% block controls %}
- + {% trans "View List" %} diff --git a/netbox/templates/dcim/rack_list.html b/netbox/templates/dcim/rack_list.html index ca72d2f25..1772ea7df 100644 --- a/netbox/templates/dcim/rack_list.html +++ b/netbox/templates/dcim/rack_list.html @@ -4,7 +4,7 @@ {% load i18n %} {% block extra_controls %} - + {% trans "View Elevations" %} {% endblock %} diff --git a/netbox/templates/generic/bulk_add.html b/netbox/templates/generic/bulk_add.html index 99b60b3a1..33bc0d769 100644 --- a/netbox/templates/generic/bulk_add.html +++ b/netbox/templates/generic/bulk_add.html @@ -8,7 +8,7 @@ {% block tabs %}