mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
Add PAGINATE_COUNT, MAX_PAGE_SIZE
This commit is contained in:
@ -25,9 +25,9 @@ class ConfigRevisionAdmin(admin.ModelAdmin):
|
||||
# ('Logging', {
|
||||
# 'fields': ('CHANGELOG_RETENTION',),
|
||||
# }),
|
||||
# ('Pagination', {
|
||||
# 'fields': ('MAX_PAGE_SIZE', 'PAGINATE_COUNT'),
|
||||
# }),
|
||||
('Pagination', {
|
||||
'fields': ('PAGINATE_COUNT', 'MAX_PAGE_SIZE'),
|
||||
}),
|
||||
('Miscellaneous', {
|
||||
'fields': ('MAINTENANCE_MODE', 'MAPS_URL'),
|
||||
}),
|
||||
|
@ -9,6 +9,7 @@ from rest_framework.decorators import action
|
||||
from rest_framework.response import Response
|
||||
|
||||
from ipam.models import *
|
||||
from netbox.config import Config
|
||||
from utilities.constants import ADVISORY_LOCK_KEYS
|
||||
from . import serializers
|
||||
|
||||
@ -160,12 +161,15 @@ class AvailableIPsMixin:
|
||||
|
||||
# Determine the maximum number of IPs to return
|
||||
else:
|
||||
config = Config()
|
||||
PAGINATE_COUNT = config.PAGINATE_COUNT
|
||||
MAX_PAGE_SIZE = config.MAX_PAGE_SIZE
|
||||
try:
|
||||
limit = int(request.query_params.get('limit', settings.PAGINATE_COUNT))
|
||||
limit = int(request.query_params.get('limit', PAGINATE_COUNT))
|
||||
except ValueError:
|
||||
limit = settings.PAGINATE_COUNT
|
||||
if settings.MAX_PAGE_SIZE:
|
||||
limit = min(limit, settings.MAX_PAGE_SIZE)
|
||||
limit = PAGINATE_COUNT
|
||||
if MAX_PAGE_SIZE:
|
||||
limit = min(limit, MAX_PAGE_SIZE)
|
||||
|
||||
# Calculate available IPs within the parent
|
||||
ip_list = []
|
||||
|
@ -2,6 +2,8 @@ from django.conf import settings
|
||||
from django.db.models import QuerySet
|
||||
from rest_framework.pagination import LimitOffsetPagination
|
||||
|
||||
from netbox.config import Config
|
||||
|
||||
|
||||
class OptionalLimitOffsetPagination(LimitOffsetPagination):
|
||||
"""
|
||||
@ -9,6 +11,8 @@ class OptionalLimitOffsetPagination(LimitOffsetPagination):
|
||||
matching a query, but retains the same format as a paginated request. The limit can only be disabled if
|
||||
MAX_PAGE_SIZE has been set to 0 or None.
|
||||
"""
|
||||
def __init__(self):
|
||||
self.default_limit = Config().PAGINATE_COUNT
|
||||
|
||||
def paginate_queryset(self, queryset, request, view=None):
|
||||
|
||||
@ -40,11 +44,9 @@ class OptionalLimitOffsetPagination(LimitOffsetPagination):
|
||||
if limit < 0:
|
||||
raise ValueError()
|
||||
# Enforce maximum page size, if defined
|
||||
if settings.MAX_PAGE_SIZE:
|
||||
if limit == 0:
|
||||
return settings.MAX_PAGE_SIZE
|
||||
else:
|
||||
return min(limit, settings.MAX_PAGE_SIZE)
|
||||
MAX_PAGE_SIZE = Config().MAX_PAGE_SIZE
|
||||
if MAX_PAGE_SIZE:
|
||||
return MAX_PAGE_SIZE if limit == 0 else min(limit, MAX_PAGE_SIZE)
|
||||
return limit
|
||||
except (KeyError, ValueError):
|
||||
pass
|
||||
|
@ -82,6 +82,20 @@ PARAMS = (
|
||||
field_kwargs={'base_field': forms.CharField()}
|
||||
),
|
||||
|
||||
# Pagination
|
||||
ConfigParam(
|
||||
name='PAGINATE_COUNT',
|
||||
label='Default page size',
|
||||
default=50,
|
||||
field=forms.IntegerField
|
||||
),
|
||||
ConfigParam(
|
||||
name='MAX_PAGE_SIZE',
|
||||
label='Maximum page size',
|
||||
default=1000,
|
||||
field=forms.IntegerField
|
||||
),
|
||||
|
||||
# Miscellaneous
|
||||
ConfigParam(
|
||||
name='MAINTENANCE_MODE',
|
||||
|
@ -158,11 +158,6 @@ LOGIN_REQUIRED = False
|
||||
# re-authenticate. (Default: 1209600 [14 days])
|
||||
LOGIN_TIMEOUT = None
|
||||
|
||||
# An API consumer can request an arbitrary number of objects =by appending the "limit" parameter to the URL (e.g.
|
||||
# "?limit=1000"). This setting defines the maximum limit. Setting it to 0 or None will allow an API consumer to request
|
||||
# all objects by specifying "?limit=0".
|
||||
MAX_PAGE_SIZE = 1000
|
||||
|
||||
# The file path where uploaded media such as image attachments are stored. A trailing slash is not needed. Note that
|
||||
# the default value of this setting is derived from the installed location.
|
||||
# MEDIA_ROOT = '/opt/netbox/netbox/media'
|
||||
@ -191,9 +186,6 @@ NAPALM_TIMEOUT = 30
|
||||
# be provided as a dictionary.
|
||||
NAPALM_ARGS = {}
|
||||
|
||||
# Determine how many objects to display per page within a list. (Default: 50)
|
||||
PAGINATE_COUNT = 50
|
||||
|
||||
# Enable installed plugins. Add the name of each plugin to the list.
|
||||
PLUGINS = []
|
||||
|
||||
|
@ -75,6 +75,7 @@ ADMINS = getattr(configuration, 'ADMINS', [])
|
||||
BASE_PATH = getattr(configuration, 'BASE_PATH', '')
|
||||
if BASE_PATH:
|
||||
BASE_PATH = BASE_PATH.strip('/') + '/' # Enforce trailing slash only
|
||||
CHANGELOG_RETENTION = getattr(configuration, 'CHANGELOG_RETENTION', 90)
|
||||
CORS_ORIGIN_ALLOW_ALL = getattr(configuration, 'CORS_ORIGIN_ALLOW_ALL', False)
|
||||
CORS_ORIGIN_REGEX_WHITELIST = getattr(configuration, 'CORS_ORIGIN_REGEX_WHITELIST', [])
|
||||
CORS_ORIGIN_WHITELIST = getattr(configuration, 'CORS_ORIGIN_WHITELIST', [])
|
||||
@ -85,12 +86,19 @@ DEBUG = getattr(configuration, 'DEBUG', False)
|
||||
DEVELOPER = getattr(configuration, 'DEVELOPER', False)
|
||||
DOCS_ROOT = getattr(configuration, 'DOCS_ROOT', os.path.join(os.path.dirname(BASE_DIR), 'docs'))
|
||||
EMAIL = getattr(configuration, 'EMAIL', {})
|
||||
EXEMPT_VIEW_PERMISSIONS = getattr(configuration, 'EXEMPT_VIEW_PERMISSIONS', [])
|
||||
GRAPHQL_ENABLED = getattr(configuration, 'GRAPHQL_ENABLED', True)
|
||||
HTTP_PROXIES = getattr(configuration, 'HTTP_PROXIES', None)
|
||||
INTERNAL_IPS = getattr(configuration, 'INTERNAL_IPS', ('127.0.0.1', '::1'))
|
||||
LOGGING = getattr(configuration, 'LOGGING', {})
|
||||
LOGIN_PERSISTENCE = getattr(configuration, 'LOGIN_PERSISTENCE', False)
|
||||
LOGIN_REQUIRED = getattr(configuration, 'LOGIN_REQUIRED', False)
|
||||
LOGIN_TIMEOUT = getattr(configuration, 'LOGIN_TIMEOUT', None)
|
||||
MEDIA_ROOT = getattr(configuration, 'MEDIA_ROOT', os.path.join(BASE_DIR, 'media')).rstrip('/')
|
||||
METRICS_ENABLED = getattr(configuration, 'METRICS_ENABLED', False)
|
||||
PLUGINS = getattr(configuration, 'PLUGINS', [])
|
||||
PLUGINS_CONFIG = getattr(configuration, 'PLUGINS_CONFIG', {})
|
||||
RELEASE_CHECK_URL = getattr(configuration, 'RELEASE_CHECK_URL', None)
|
||||
REMOTE_AUTH_AUTO_CREATE_USER = getattr(configuration, 'REMOTE_AUTH_AUTO_CREATE_USER', False)
|
||||
REMOTE_AUTH_BACKEND = getattr(configuration, 'REMOTE_AUTH_BACKEND', 'netbox.authentication.RemoteUserBackend')
|
||||
REMOTE_AUTH_DEFAULT_GROUPS = getattr(configuration, 'REMOTE_AUTH_DEFAULT_GROUPS', [])
|
||||
@ -122,20 +130,10 @@ for param in PARAMS:
|
||||
if hasattr(configuration, param.name):
|
||||
globals()[param.name] = getattr(configuration, param.name)
|
||||
|
||||
CHANGELOG_RETENTION = getattr(configuration, 'CHANGELOG_RETENTION', 90)
|
||||
EXEMPT_VIEW_PERMISSIONS = getattr(configuration, 'EXEMPT_VIEW_PERMISSIONS', [])
|
||||
GRAPHQL_ENABLED = getattr(configuration, 'GRAPHQL_ENABLED', True)
|
||||
LOGIN_PERSISTENCE = getattr(configuration, 'LOGIN_PERSISTENCE', False)
|
||||
LOGIN_REQUIRED = getattr(configuration, 'LOGIN_REQUIRED', False)
|
||||
LOGIN_TIMEOUT = getattr(configuration, 'LOGIN_TIMEOUT', None)
|
||||
MAX_PAGE_SIZE = getattr(configuration, 'MAX_PAGE_SIZE', 1000)
|
||||
METRICS_ENABLED = getattr(configuration, 'METRICS_ENABLED', False)
|
||||
NAPALM_ARGS = getattr(configuration, 'NAPALM_ARGS', {})
|
||||
NAPALM_PASSWORD = getattr(configuration, 'NAPALM_PASSWORD', '')
|
||||
NAPALM_TIMEOUT = getattr(configuration, 'NAPALM_TIMEOUT', 30)
|
||||
NAPALM_USERNAME = getattr(configuration, 'NAPALM_USERNAME', '')
|
||||
PAGINATE_COUNT = getattr(configuration, 'PAGINATE_COUNT', 50)
|
||||
RELEASE_CHECK_URL = getattr(configuration, 'RELEASE_CHECK_URL', None)
|
||||
|
||||
# Validate update repo URL and timeout
|
||||
if RELEASE_CHECK_URL:
|
||||
@ -462,7 +460,7 @@ REST_FRAMEWORK = {
|
||||
),
|
||||
'DEFAULT_VERSION': REST_FRAMEWORK_VERSION,
|
||||
'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.AcceptHeaderVersioning',
|
||||
'PAGE_SIZE': PAGINATE_COUNT,
|
||||
# 'PAGE_SIZE': PAGINATE_COUNT,
|
||||
'SCHEMA_COERCE_METHOD_NAMES': {
|
||||
# Default mappings
|
||||
'retrieve': 'read',
|
||||
@ -561,23 +559,6 @@ RQ_QUEUES = {
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# NetBox internal settings
|
||||
#
|
||||
|
||||
# Pagination
|
||||
if MAX_PAGE_SIZE and PAGINATE_COUNT > MAX_PAGE_SIZE:
|
||||
raise ImproperlyConfigured(
|
||||
f"PAGINATE_COUNT ({PAGINATE_COUNT}) must be less than or equal to MAX_PAGE_SIZE ({MAX_PAGE_SIZE}), if set."
|
||||
)
|
||||
PER_PAGE_DEFAULTS = [
|
||||
25, 50, 100, 250, 500, 1000
|
||||
]
|
||||
if PAGINATE_COUNT not in PER_PAGE_DEFAULTS:
|
||||
PER_PAGE_DEFAULTS.append(PAGINATE_COUNT)
|
||||
PER_PAGE_DEFAULTS = sorted(PER_PAGE_DEFAULTS)
|
||||
|
||||
|
||||
#
|
||||
# Plugins
|
||||
#
|
||||
|
@ -36,7 +36,7 @@
|
||||
{% endfor %}
|
||||
<div class="input-group input-group-sm">
|
||||
<select name="per_page" class="form-select per-page">
|
||||
{% for n in settings.PER_PAGE_DEFAULTS %}
|
||||
{% for n in page.paginator.get_page_lengths %}
|
||||
<option value="{{ n }}"{% if page.paginator.per_page == n %} selected="selected"{% endif %}>{{ n }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
|
@ -1,8 +1,12 @@
|
||||
from django.conf import settings
|
||||
from django.core.paginator import Paginator, Page
|
||||
|
||||
from netbox.config import Config
|
||||
|
||||
|
||||
class EnhancedPaginator(Paginator):
|
||||
default_page_lengths = (
|
||||
25, 50, 100, 250, 500, 1000
|
||||
)
|
||||
|
||||
def __init__(self, object_list, per_page, orphans=None, **kwargs):
|
||||
|
||||
@ -10,9 +14,9 @@ class EnhancedPaginator(Paginator):
|
||||
try:
|
||||
per_page = int(per_page)
|
||||
if per_page < 1:
|
||||
per_page = settings.PAGINATE_COUNT
|
||||
per_page = Config().PAGINATE_COUNT
|
||||
except ValueError:
|
||||
per_page = settings.PAGINATE_COUNT
|
||||
per_page = Config().PAGINATE_COUNT
|
||||
|
||||
# Set orphans count based on page size
|
||||
if orphans is None and per_page <= 50:
|
||||
@ -25,6 +29,11 @@ class EnhancedPaginator(Paginator):
|
||||
def _get_page(self, *args, **kwargs):
|
||||
return EnhancedPage(*args, **kwargs)
|
||||
|
||||
def get_page_lengths(self):
|
||||
if self.per_page not in self.default_page_lengths:
|
||||
return sorted([*self.default_page_lengths, self.per_page])
|
||||
return self.default_page_lengths
|
||||
|
||||
|
||||
class EnhancedPage(Page):
|
||||
|
||||
@ -57,17 +66,19 @@ def get_paginate_count(request):
|
||||
|
||||
Return the lesser of the calculated value and MAX_PAGE_SIZE.
|
||||
"""
|
||||
config = Config()
|
||||
|
||||
if 'per_page' in request.GET:
|
||||
try:
|
||||
per_page = int(request.GET.get('per_page'))
|
||||
if request.user.is_authenticated:
|
||||
request.user.config.set('pagination.per_page', per_page, commit=True)
|
||||
return min(per_page, settings.MAX_PAGE_SIZE)
|
||||
return min(per_page, config.MAX_PAGE_SIZE)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
if request.user.is_authenticated:
|
||||
per_page = request.user.config.get('pagination.per_page', settings.PAGINATE_COUNT)
|
||||
return min(per_page, settings.MAX_PAGE_SIZE)
|
||||
per_page = request.user.config.get('pagination.per_page', config.PAGINATE_COUNT)
|
||||
return min(per_page, config.MAX_PAGE_SIZE)
|
||||
|
||||
return min(settings.PAGINATE_COUNT, settings.MAX_PAGE_SIZE)
|
||||
return min(config.PAGINATE_COUNT, config.MAX_PAGE_SIZE)
|
||||
|
@ -1,6 +1,5 @@
|
||||
import urllib.parse
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.test import Client, TestCase, override_settings
|
||||
from django.urls import reverse
|
||||
@ -10,6 +9,7 @@ from dcim.models import Region, Site
|
||||
from extras.choices import CustomFieldTypeChoices
|
||||
from extras.models import CustomField
|
||||
from ipam.models import VLAN
|
||||
from netbox.config import Config
|
||||
from utilities.testing import APITestCase, disable_warnings
|
||||
|
||||
|
||||
@ -137,7 +137,7 @@ class APIPaginationTestCase(APITestCase):
|
||||
|
||||
def test_default_page_size(self):
|
||||
response = self.client.get(self.url, format='json', **self.header)
|
||||
page_size = settings.PAGINATE_COUNT
|
||||
page_size = Config().PAGINATE_COUNT
|
||||
self.assertLess(page_size, 100, "Default page size not sufficient for data set")
|
||||
|
||||
self.assertHttpStatus(response, status.HTTP_200_OK)
|
||||
|
Reference in New Issue
Block a user