Skip to content

Commit 34969c4

Browse files
committed
make package_url field unique for PackageV2
Signed-off-by: Tushar Goel <tushar.goel.dav@gmail.com>
1 parent 80bf345 commit 34969c4

File tree

4 files changed

+120
-0
lines changed

4 files changed

+120
-0
lines changed

CHANGELOG.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
Release notes
22
=============
33

4+
Version v38.5.0
5+
---------------------
6+
7+
- fix: Make package_url field unique for PackageV2
8+
49
Version v38.4.0
510
---------------------
611

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
from django.db import migrations
2+
from django.db.models import F, Window
3+
from django.db.models.functions import RowNumber
4+
5+
6+
def remove_duplicate_package_urls(apps, schema_editor):
7+
PackageV2 = apps.get_model("vulnerabilities", "PackageV2")
8+
9+
duplicates = (
10+
PackageV2.objects
11+
.annotate(
12+
rn=Window(
13+
expression=RowNumber(),
14+
partition_by=[F("package_url")],
15+
order_by=F("id").desc(),
16+
)
17+
)
18+
.filter(rn__gt=1)
19+
)
20+
21+
BATCH_SIZE = 1000
22+
ids = list(duplicates.values_list("id", flat=True))
23+
24+
for i in range(0, len(ids), BATCH_SIZE):
25+
PackageV2.objects.filter(id__in=ids[i:i+BATCH_SIZE]).delete()
26+
27+
28+
class Migration(migrations.Migration):
29+
30+
dependencies = [
31+
("vulnerabilities", "0121_advisoryv2_is_latest_alter_advisoryv2_advisory_id_and_more"),
32+
]
33+
34+
operations = [
35+
migrations.RunPython(remove_duplicate_package_urls, migrations.RunPython.noop),
36+
]
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# Generated by Django 5.2.11 on 2026-04-15 11:59
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
("vulnerabilities", "0122_auto_20260415_1155"),
10+
]
11+
12+
operations = [
13+
migrations.AlterModelOptions(
14+
name="packagev2",
15+
options={
16+
"ordering": [
17+
"type",
18+
"namespace",
19+
"name",
20+
"version_rank",
21+
"version",
22+
"qualifiers",
23+
"subpath",
24+
]
25+
},
26+
),
27+
migrations.AlterField(
28+
model_name="packagev2",
29+
name="package_url",
30+
field=models.CharField(
31+
db_index=True,
32+
help_text="The Package URL for this package.",
33+
max_length=1000,
34+
unique=True,
35+
),
36+
),
37+
migrations.AlterUniqueTogether(
38+
name="packagev2",
39+
unique_together={("type", "namespace", "name", "version", "qualifiers", "subpath")},
40+
),
41+
migrations.AddIndex(
42+
model_name="packagev2",
43+
index=models.Index(
44+
fields=["type", "namespace", "name"], name="vulnerabili_type_ca0efc_idx"
45+
),
46+
),
47+
migrations.AddIndex(
48+
model_name="packagev2",
49+
index=models.Index(
50+
fields=["type", "namespace", "name", "qualifiers", "subpath"],
51+
name="vulnerabili_type_c98c98_idx",
52+
),
53+
),
54+
migrations.AddIndex(
55+
model_name="packagev2",
56+
index=models.Index(
57+
fields=["type", "namespace", "name", "version"], name="vulnerabili_type_1af1cc_idx"
58+
),
59+
),
60+
]

vulnerabilities/models.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3490,6 +3490,7 @@ class PackageV2(PackageURLMixin):
34903490
null=False,
34913491
help_text="The Package URL for this package.",
34923492
db_index=True,
3493+
unique=True
34933494
)
34943495

34953496
plain_package_url = models.CharField(
@@ -3520,6 +3521,24 @@ class PackageV2(PackageURLMixin):
35203521
db_index=True,
35213522
)
35223523

3524+
class Meta:
3525+
unique_together = ["type", "namespace", "name", "version", "qualifiers", "subpath"]
3526+
ordering = ["type", "namespace", "name", "version_rank", "version", "qualifiers", "subpath"]
3527+
indexes = [
3528+
# Index for getting al versions of a package
3529+
models.Index(fields=["type", "namespace", "name"]),
3530+
models.Index(fields=["type", "namespace", "name", "qualifiers", "subpath"]),
3531+
# Index for getting a specific version of a package
3532+
models.Index(
3533+
fields=[
3534+
"type",
3535+
"namespace",
3536+
"name",
3537+
"version",
3538+
]
3539+
),
3540+
]
3541+
35233542
def __str__(self):
35243543
return self.package_url
35253544

0 commit comments

Comments
 (0)