|
42 | 42 | from django.db import transaction |
43 | 43 | from django.db.models import Count |
44 | 44 | from django.db.models import Exists |
| 45 | +from django.db.models import F |
45 | 46 | from django.db.models import OuterRef |
| 47 | +from django.db.models import Subquery |
46 | 48 | from django.db.models import Prefetch |
47 | 49 | from django.db.models import Q |
48 | 50 | from django.db.models.functions import Length |
@@ -1368,6 +1370,17 @@ def search(query): |
1368 | 1370 | | Q(references__url__icontains=query) |
1369 | 1371 | ).distinct() |
1370 | 1372 |
|
| 1373 | +class AdvisoryV2QuerySet(BaseQuerySet): |
| 1374 | + def latest_for_avid(self, avid: str): |
| 1375 | + return ( |
| 1376 | + self.filter(avid=avid) |
| 1377 | + .order_by( |
| 1378 | + F("date_collected").desc(nulls_last=True), |
| 1379 | + "-id", |
| 1380 | + ) |
| 1381 | + .first() |
| 1382 | + ) |
| 1383 | + |
1371 | 1384 |
|
1372 | 1385 | # FIXME: Remove when migration from Vulnerability to Advisory is completed |
1373 | 1386 | class Advisory(models.Model): |
@@ -2916,9 +2929,6 @@ class AdvisoryV2(models.Model): |
2916 | 2929 | blank=True, null=True, help_text="UTC Date of publication of the advisory" |
2917 | 2930 | ) |
2918 | 2931 | date_collected = models.DateTimeField(help_text="UTC Date on which the advisory was collected") |
2919 | | - date_imported = models.DateTimeField( |
2920 | | - blank=True, null=True, help_text="UTC Date on which the advisory was imported" |
2921 | | - ) |
2922 | 2932 |
|
2923 | 2933 | original_advisory_text = models.TextField( |
2924 | 2934 | blank=True, |
@@ -2959,11 +2969,15 @@ def risk_score(self): |
2959 | 2969 | risk_score = min(float(self.exploitability * self.weighted_severity), 10.0) |
2960 | 2970 | return round(risk_score, 1) |
2961 | 2971 |
|
2962 | | - objects = AdvisoryQuerySet.as_manager() |
| 2972 | + objects = AdvisoryV2QuerySet.as_manager() |
2963 | 2973 |
|
2964 | 2974 | class Meta: |
2965 | 2975 | unique_together = ["datasource_id", "advisory_id", "unique_content_id"] |
2966 | 2976 | ordering = ["datasource_id", "advisory_id", "date_published", "unique_content_id"] |
| 2977 | + # indexes = models.Index( |
| 2978 | + # fields=["avid", "-date_collected", "-id"], |
| 2979 | + # name="advisory_latest_by_avid_idx", |
| 2980 | + # ) |
2967 | 2981 |
|
2968 | 2982 | def save(self, *args, **kwargs): |
2969 | 2983 | self.full_clean() |
@@ -3004,6 +3018,29 @@ def get_aliases(self): |
3004 | 3018 | """ |
3005 | 3019 | return self.aliases.all() |
3006 | 3020 |
|
| 3021 | + def latest_for_avid(self, avid: str): |
| 3022 | + return ( |
| 3023 | + self.filter(avid=avid) |
| 3024 | + .order_by( |
| 3025 | + F("date_collected").desc(nulls_last=True), |
| 3026 | + "-id", |
| 3027 | + ) |
| 3028 | + .first() |
| 3029 | + ) |
| 3030 | + |
| 3031 | + def latest_per_avid(self): |
| 3032 | + latest_ids = ( |
| 3033 | + AdvisoryV2.objects |
| 3034 | + .filter(avid=OuterRef("avid")) |
| 3035 | + .order_by( |
| 3036 | + F("date_collected").desc(nulls_last=True), |
| 3037 | + "-id", |
| 3038 | + ) |
| 3039 | + .values("id")[:1] |
| 3040 | + ) |
| 3041 | + |
| 3042 | + return self.filter(id=Subquery(latest_ids)) |
| 3043 | + |
3007 | 3044 | alias = get_aliases |
3008 | 3045 |
|
3009 | 3046 |
|
|
0 commit comments