From f70c48ae043d34238532a23f5ed932b699cd948d Mon Sep 17 00:00:00 2001 From: tdruez Date: Fri, 26 Jul 2024 14:52:15 +0400 Subject: [PATCH] Round of queryset optimizations #138 Signed-off-by: tdruez --- component_catalog/models.py | 13 +++++++ license_library/models.py | 7 +++- product_portfolio/models.py | 4 ++ .../tabs/tab_dependencies.html | 8 ++-- product_portfolio/views.py | 37 +++++++++++++++---- 5 files changed, 56 insertions(+), 13 deletions(-) diff --git a/component_catalog/models.py b/component_catalog/models.py index 01a8e89f..9950ed16 100644 --- a/component_catalog/models.py +++ b/component_catalog/models.py @@ -1633,6 +1633,19 @@ def annotate_sortable_identifier(self): sortable_identifier=Concat(*PACKAGE_URL_FIELDS, "filename", output_field=CharField()) ) + def only_rendering_fields(self): + """ + Minimum requirements to render a Package element in the UI. + """ + return self.only( + "uuid", + *PACKAGE_URL_FIELDS, + "filename", + "license_expression", + "dataspace__name", + "dataspace__show_usage_policy_in_user_views", + ) + class Package( ExternalReferenceMixin, diff --git a/license_library/models.py b/license_library/models.py index 1ba147f8..8bf0be4b 100644 --- a/license_library/models.py +++ b/license_library/models.py @@ -472,8 +472,11 @@ def for_expression(self, license_keys=None): "short_name", "spdx_license_key", "is_exception", - "usage_policy", - "dataspace", + "usage_policy__label", + "usage_policy__icon", + "usage_policy__color_code", + "dataspace__name", + "dataspace__show_usage_policy_in_user_views", ).select_related("dataspace", "usage_policy") if license_keys: diff --git a/product_portfolio/models.py b/product_portfolio/models.py index abb8409b..1a71ab9a 100644 --- a/product_portfolio/models.py +++ b/product_portfolio/models.py @@ -547,6 +547,10 @@ def product_secured(self, user=None, perms="view_product"): product_qs = Product.objects.get_queryset(user, perms) return self.filter(product__in=product_qs) + def product(self, product): + """Filter based on the provided ``product`` object.""" + return self.filter(product=product) + class ProductComponentQuerySet(ProductSecuredQuerySet): def catalogs(self): diff --git a/product_portfolio/templates/product_portfolio/tabs/tab_dependencies.html b/product_portfolio/templates/product_portfolio/tabs/tab_dependencies.html index e2c04ae2..5886586b 100644 --- a/product_portfolio/templates/product_portfolio/tabs/tab_dependencies.html +++ b/product_portfolio/templates/product_portfolio/tabs/tab_dependencies.html @@ -15,7 +15,7 @@
{% if page_obj.paginator.count != total_count %} {{ page_obj.paginator.count|intcomma }} of - + {{ total_count }} results {% else %} @@ -120,7 +120,7 @@ {% endif %} -
+
{{ dependency.resolved_to_package.license_expression_html|default_if_none:"" }}
{% else %} @@ -156,7 +156,9 @@ No results. {% if filter_dependency.is_active %} - Clear search and filters + + Clear search and filters + {% endif %} diff --git a/product_portfolio/views.py b/product_portfolio/views.py index f58efe5a..825bc6fd 100644 --- a/product_portfolio/views.py +++ b/product_portfolio/views.py @@ -391,8 +391,10 @@ def tab_notice(self): def tab_hierarchy(self): template = "product_portfolio/tabs/tab_hierarchy.html" + product = self.object + productcomponent_qs = ( - self.object.productcomponents.select_related( + product.productcomponents.select_related( "component", ) .prefetch_related( @@ -410,11 +412,12 @@ def tab_hierarchy(self): ) declared_dependencies_prefetch = models.Prefetch( - "package__declared_dependencies", ProductDependency.objects.all() + "package__declared_dependencies", + ProductDependency.objects.product(product) ) productpackage_qs = ( - self.object.productpackages.select_related( + product.productpackages.select_related( "package", ) .prefetch_related( @@ -648,7 +651,8 @@ def get_context_data(self, **kwargs): "licenses", License.objects.select_related("usage_policy") ) declared_dependencies_prefetch = models.Prefetch( - "package__declared_dependencies", ProductDependency.objects.all() + "package__declared_dependencies", + ProductDependency.objects.product(self.object) ) productpackage_qs = ( @@ -964,9 +968,16 @@ class ProductTabDependenciesView( def get_context_data(self, **kwargs): context_data = super().get_context_data(**kwargs) - dependency_qs = self.object.dependencies.select_related( - "for_package__dataspace", - "resolved_to_package__dataspace", + dependency_qs = ( + self.object.dependencies + .prefetch_related( + models.Prefetch( + "for_package", Package.objects.only_rendering_fields() + ), + models.Prefetch( + "resolved_to_package", Package.objects.only_rendering_fields() + ) + ) ) filter_dependency = DependencyFilterSet( @@ -977,7 +988,17 @@ def get_context_data(self, **kwargs): ) # Annotate the filtered queryset with the count of declared_dependencies - filtered_and_annotated_qs = filter_dependency.qs.with_resolved_to_dependencies_count() + filtered_and_annotated_qs = ( + filter_dependency.qs + # TODO: This is not scoped by product + .with_resolved_to_dependencies_count() + .order_by( + "for_package__type", + "for_package__namespace", + "for_package__name", + "for_package__version", + ) + ) paginator = Paginator(filtered_and_annotated_qs, self.paginate_by) page_number = self.request.GET.get(self.query_dict_page_param)