2323from urllib .parse import urlencode
2424
2525from django .core .paginator import Paginator
26+ from django .db .models import Count
2627from django .http import HttpResponse
2728from django .shortcuts import render , redirect
2829from django .urls import reverse
@@ -46,7 +47,7 @@ def get(self, request):
4647
4748 if request .GET :
4849 packages = self .request_to_queryset (request )
49- result_size = packages . count ( )
50+ result_size = len ( packages )
5051 page_no = int (request .GET .get ("page" , 1 ))
5152 packages = Paginator (packages , 50 ).get_page (page_no )
5253 context ["packages" ] = packages
@@ -68,9 +69,14 @@ def request_to_queryset(request):
6869 if len (request .GET ["name" ]):
6970 package_name = request .GET ["name" ]
7071
71- return models .Package .objects .all ().filter (
72- name__icontains = package_name ,
73- type__icontains = package_type ,
72+ return list (
73+ models .Package .objects .all ()
74+ .filter (name__icontains = package_name , type__icontains = package_type )
75+ .annotate (
76+ vulnerability_count = Count ("vulnerabilities" ),
77+ patched_vulnerability_count = Count ("resolved_vulnerabilities" ),
78+ )
79+ .prefetch_related ()
7480 )
7581
7682
@@ -81,8 +87,8 @@ class VulnerabilitySearchView(View):
8187 def get (self , request ):
8288 context = {"form" : forms .CVEForm (request .GET or None )}
8389 if request .GET :
84- vulnerabilities = self .request_to_queryset (request )
85- result_size = vulnerabilities . count ( )
90+ vulnerabilities = self .request_to_vulnerabilities (request )
91+ result_size = len ( vulnerabilities )
8692 pages = Paginator (vulnerabilities , 50 )
8793 vulnerabilities = pages .get_page (int (self .request .GET .get ("page" , 1 )))
8894 context ["vulnerabilities" ] = vulnerabilities
@@ -91,9 +97,14 @@ def get(self, request):
9197 return render (request , self .template_name , context )
9298
9399 @staticmethod
94- def request_to_queryset (request ):
100+ def request_to_vulnerabilities (request ):
95101 vuln_id = request .GET ["vuln_id" ]
96- return models .Vulnerability .objects .filter (vulnerability_id__icontains = vuln_id )
102+ return list (
103+ models .Vulnerability .objects .filter (vulnerability_id__icontains = vuln_id ).annotate (
104+ vulnerable_package_count = Count ("vulnerable_packages" ),
105+ patched_package_count = Count ("patched_packages" ),
106+ )
107+ )
97108
98109
99110class PackageUpdate (UpdateView ):
@@ -112,9 +123,11 @@ def get_context_data(self, **kwargs):
112123 return context
113124
114125 def _package_vulnerabilities (self , package_pk ):
115-
116- resolved_vuln = [i for i in self .get_object ().resolved_to ]
117- unresolved_vuln = [i for i in self .get_object ().vulnerable_to ]
126+ # This can be further optimised by caching get_object result first time it
127+ # is called
128+ package = self .get_object ()
129+ resolved_vuln = [i for i in package .resolved_to .values ("vulnerability_id" , "pk" )]
130+ unresolved_vuln = [i for i in package .vulnerable_to .values ("vulnerability_id" , "pk" )]
118131
119132 return resolved_vuln , unresolved_vuln
120133
@@ -214,9 +227,10 @@ def relationship_already_exists(relationship):
214227 @staticmethod
215228 def create_relationship_instance (vulnerability_id , package_id , is_vulnerable ):
216229 package = models .Package .objects .get (id = package_id )
230+ # FIXME: Handle the case when vuln_created=True
217231 vulnerability , vuln_created = models .Vulnerability .objects .get_or_create (
218232 vulnerability_id = vulnerability_id
219- ) # nopep8
233+ )
220234 return models .PackageRelatedVulnerability (
221235 vulnerability = vulnerability , package = package , is_vulnerable = is_vulnerable
222236 )
0 commit comments