diff --git a/patchwork/migrations/0049_patch_patch_covering_idx_default.py b/patchwork/migrations/0049_patch_patch_covering_idx_default.py new file mode 100644 index 000000000..272ca5efe --- /dev/null +++ b/patchwork/migrations/0049_patch_patch_covering_idx_default.py @@ -0,0 +1,28 @@ +# Generated by Django 6.0.6 on 2026-08-13 00:14 + +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ('patchwork', '0048_series_dependencies'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.AddIndex( + model_name='patch', + index=models.Index( + fields=[ + 'project', + 'archived', + 'state', + '-date', + 'delegate', + 'submitter', + ], + name='patch_covering_idx_default', + ), + ), + ] diff --git a/patchwork/models.py b/patchwork/models.py index d5cb31de9..77ca6aaa3 100644 --- a/patchwork/models.py +++ b/patchwork/models.py @@ -13,6 +13,7 @@ from django.contrib.auth.models import User from django.core.exceptions import ValidationError from django.core.validators import validate_unicode_slug +from django.core.validators import MaxValueValidator from django.db import models from django.urls import reverse from django.utils.functional import cached_property @@ -172,6 +173,7 @@ class UserProfile(models.Model): null=False, blank=False, help_text='Number of items to display per page', + validators=[MaxValueValidator(settings.MAX_ITEMS_PER_PAGE)], ) show_ids = models.BooleanField( default=False, @@ -208,6 +210,9 @@ def token(self): except Token.DoesNotExist: return + def get_items_per_page(self): + return min(self.items_per_page, settings.MAX_ITEMS_PER_PAGE) + def todo_patches(self, project=None): # filter on project, if necessary if project: @@ -735,6 +740,17 @@ class Meta: ], name='patch_covering_idx', ), + models.Index( + fields=[ + 'project', + 'archived', + 'state', + '-date', + 'delegate', + 'submitter', + ], + name='patch_covering_idx_default', + ), ] diff --git a/patchwork/paginator.py b/patchwork/paginator.py index 1b7bd9145..c79b493ae 100644 --- a/patchwork/paginator.py +++ b/patchwork/paginator.py @@ -25,7 +25,7 @@ def __init__(self, request, objects): items_per_page = settings.DEFAULT_ITEMS_PER_PAGE if request.user.is_authenticated: - items_per_page = request.user.profile.items_per_page + items_per_page = request.user.profile.get_items_per_page() super().__init__(objects, items_per_page) @@ -90,7 +90,3 @@ def __init__(self, request, objects): # prevent e.g. 1 2 ... 5 6 7 ... 8 9 if self.trailing_set[0] != self.adjacent_set[-1] + 1: self.show_trailing_ellipsis = True - - self.long_page = ( - len(self.current_page.object_list) >= LONG_PAGE_THRESHOLD - ) diff --git a/patchwork/settings/base.py b/patchwork/settings/base.py index 2b557fc1c..d5dd82c41 100644 --- a/patchwork/settings/base.py +++ b/patchwork/settings/base.py @@ -266,6 +266,8 @@ REST_RESULTS_PER_PAGE = 30 MAX_REST_RESULTS_PER_PAGE = 250 +MAX_ITEMS_PER_PAGE = 1000 + # Set to True to enable redirections or URLs from previous versions # of patchwork COMPAT_REDIR = True diff --git a/patchwork/templates/patchwork/partials/patch-list.html b/patchwork/templates/patchwork/partials/patch-list.html index 981ceee58..b9bb62d21 100644 --- a/patchwork/templates/patchwork/partials/patch-list.html +++ b/patchwork/templates/patchwork/partials/patch-list.html @@ -154,7 +154,7 @@ -{% for patch in page.object_list %} +{% for patch in patches %} {% if user.is_authenticated %} diff --git a/patchwork/views/__init__.py b/patchwork/views/__init__.py index 92adbbccd..e8621301d 100644 --- a/patchwork/views/__init__.py +++ b/patchwork/views/__init__.py @@ -280,13 +280,26 @@ def generic_list( else: context['filters'].set_status(filterclass, setting) + # Filtering + if patches is None: patches = Patch.objects.filter(project=project) - # annotate with tag counts - patches = patches.with_tag_counts(project) + patch_ids = patches + + patch_ids = patch_ids.only('id') + patch_ids = context['filters'].apply(patch_ids) + if not editable_order: + patch_ids = order.apply(patch_ids) - patches = context['filters'].apply(patches) + paginator = Paginator(request, patch_ids) + patch_ids = list( + paginator.current_page.object_list.values_list('id', flat=True) + ) + + # Aggregation + + patches = patches.filter(id__in=patch_ids) if not editable_order: patches = order.apply(patches) @@ -321,11 +334,13 @@ def generic_list( ) ) - paginator = Paginator(request, patches) + # annotate with tag counts + patches = patches.with_tag_counts(project) context.update( { 'page': paginator.current_page, + 'patches': patches, 'patch_form': properties_form, 'create_bundle_form': create_bundle_form, 'project': project,