Skip to content

Commit 1f871f5

Browse files
committed
refactor: Use new model instead of tags for Release Programming Languages
1 parent a3c294f commit 1f871f5

File tree

12 files changed

+403
-27
lines changed

12 files changed

+403
-27
lines changed

django/curator/models.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
from nltk.tokenize import word_tokenize
1616
from taggit.models import Tag
1717

18-
from library.models import ProgrammingLanguage, CodebaseReleasePlatformTag
18+
from library.models import CodebaseReleasePlatformTag
1919

2020
logger = logging.getLogger(__name__)
2121

@@ -43,11 +43,6 @@ class TagCuratorProxyQuerySet(models.QuerySet):
4343
def with_comma(self):
4444
return self.filter(name__icontains=",")
4545

46-
def programming_languages(self):
47-
return self.filter(
48-
id__in=ProgrammingLanguage.objects.values_list("tag_id", flat=True)
49-
)
50-
5146
def platforms(self):
5247
return self.filter(
5348
id__in=CodebaseReleasePlatformTag.objects.values_list("tag_id", flat=True)
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
# Generated by Django 4.2.22 on 2025-08-26 06:37
2+
3+
from django.db import migrations, models
4+
import django.db.models.deletion
5+
6+
def remove_old_tags(apps, schema_editor):
7+
ProgrammingLanguage = apps.get_model("library", "ProgrammingLanguage")
8+
ProgrammingLanguage.objects.all().delete()
9+
10+
11+
class Migration(migrations.Migration):
12+
13+
dependencies = [
14+
("library", "0032_license_text_codemeta_snapshot"),
15+
]
16+
17+
operations = [
18+
migrations.RunPython(remove_old_tags, reverse_code=migrations.RunPython.noop),
19+
migrations.RemoveField(
20+
model_name="programminglanguage",
21+
name="content_object",
22+
),
23+
migrations.RemoveField(
24+
model_name="programminglanguage",
25+
name="tag",
26+
),
27+
migrations.AddField(
28+
model_name="programminglanguage",
29+
name="is_pinned",
30+
field=models.BooleanField(default=False),
31+
),
32+
migrations.AddField(
33+
model_name="programminglanguage",
34+
name="is_user_defined",
35+
field=models.BooleanField(default=False),
36+
),
37+
migrations.AddField(
38+
model_name="programminglanguage",
39+
name="name",
40+
field=models.CharField(default="", max_length=100, unique=True),
41+
preserve_default=False,
42+
),
43+
migrations.AddField(
44+
model_name="programminglanguage",
45+
name="url",
46+
field=models.URLField(blank=True),
47+
),
48+
migrations.CreateModel(
49+
name="ReleaseLanguage",
50+
fields=[
51+
(
52+
"id",
53+
models.AutoField(
54+
auto_created=True,
55+
primary_key=True,
56+
serialize=False,
57+
verbose_name="ID",
58+
),
59+
),
60+
("version", models.CharField(max_length=20)),
61+
(
62+
"programming_language",
63+
models.ForeignKey(
64+
on_delete=django.db.models.deletion.CASCADE,
65+
related_name="release_languages",
66+
to="library.programminglanguage",
67+
),
68+
),
69+
(
70+
"release",
71+
models.ForeignKey(
72+
on_delete=django.db.models.deletion.CASCADE,
73+
related_name="release_languages",
74+
to="library.codebaserelease",
75+
),
76+
),
77+
],
78+
),
79+
migrations.AlterField(
80+
model_name="codebaserelease",
81+
name="programming_languages",
82+
field=models.ManyToManyField(
83+
through="library.ReleaseLanguage", to="library.programminglanguage"
84+
),
85+
),
86+
]

django/library/models.py

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -92,10 +92,22 @@ class CodebaseTag(TaggedItemBase):
9292
content_object = ParentalKey("library.Codebase", related_name="tagged_codebases")
9393

9494

95-
class ProgrammingLanguage(TaggedItemBase):
96-
content_object = ParentalKey(
97-
"library.CodebaseRelease", related_name="tagged_release_languages"
95+
@register_snippet
96+
class ProgrammingLanguage(models.Model):
97+
name = models.CharField(max_length=100, unique=True)
98+
url = models.URLField(blank=True)
99+
is_pinned = models.BooleanField(default=False)
100+
is_user_defined = models.BooleanField(default=False)
101+
102+
103+
class ReleaseLanguage(models.Model):
104+
programming_language = models.ForeignKey(
105+
"library.ProgrammingLanguage", related_name="release_languages", on_delete=models.CASCADE
106+
)
107+
release = models.ForeignKey(
108+
"library.CodebaseRelease", related_name="release_languages", on_delete=models.CASCADE
98109
)
110+
version = models.CharField(max_length=20)
99111

100112

101113
class CodebaseReleasePlatformTag(TaggedItemBase):
@@ -1146,7 +1158,7 @@ def with_platforms(self):
11461158
return self.prefetch_related("tagged_release_platforms__tag")
11471159

11481160
def with_programming_languages(self):
1149-
return self.prefetch_related("tagged_release_languages__tag")
1161+
return self
11501162

11511163
def with_codebase(self):
11521164
return self.prefetch_related(
@@ -1287,9 +1299,7 @@ class Status(models.TextChoices):
12871299
through=CodebaseReleasePlatformTag, related_name="platform_codebase_releases"
12881300
)
12891301
platforms = models.ManyToManyField(Platform)
1290-
programming_languages = ClusterTaggableManager(
1291-
through=ProgrammingLanguage, related_name="pl_codebase_releases"
1292-
)
1302+
programming_languages = models.ManyToManyField(ProgrammingLanguage, through="ReleaseLanguage")
12931303
codebase = models.ForeignKey(
12941304
Codebase, related_name="releases", on_delete=models.PROTECT
12951305
)

django/library/serializers.py

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737
CodebaseReleaseDownload,
3838
Contributor,
3939
License,
40+
ProgrammingLanguage,
41+
ReleaseLanguage,
4042
CodebaseImage,
4143
PeerReviewerFeedback,
4244
PeerReviewInvitation,
@@ -63,6 +65,28 @@ class Meta:
6365
)
6466

6567

68+
class ReleaseLanguageSerializer(serializers.ModelSerializer):
69+
class Meta:
70+
model = ReleaseLanguage
71+
fields = (
72+
"programming_language",
73+
"release",
74+
"version",
75+
)
76+
77+
78+
class ProgrammingLanguageSerializer(serializers.ModelSerializer):
79+
class Meta:
80+
model = ProgrammingLanguage
81+
fields = (
82+
"id",
83+
"name",
84+
"url",
85+
"is_pinned",
86+
"is_user_defined",
87+
)
88+
89+
6690
class ContributorSerializer(serializers.ModelSerializer):
6791
# Need an ID for Vue-Multiselect
6892
id = serializers.IntegerField(read_only=True)
@@ -563,7 +587,7 @@ class CodebaseReleaseSerializer(serializers.ModelSerializer):
563587
can_edit_originals = serializers.ReadOnlyField()
564588
os_display = serializers.ReadOnlyField(source="get_os_display")
565589
platforms = TagSerializer(many=True, source="platform_tags")
566-
programming_languages = TagSerializer(many=True)
590+
programming_languages = ReleaseLanguageSerializer(many=True)
567591
submitter = RelatedUserSerializer(read_only=True, label="Submitter")
568592
version_number = serializers.ReadOnlyField()
569593
release_notes = MarkdownField(max_length=2048)
@@ -635,14 +659,10 @@ def get_possible_licenses(self, instance):
635659
return serialized.data
636660

637661
def update(self, instance, validated_data):
638-
programming_languages = TagSerializer(
639-
many=True, data=validated_data.pop("programming_languages")
640-
)
641662
platform_tags = TagSerializer(
642663
many=True, data=validated_data.pop("platform_tags")
643664
)
644665

645-
set_tags(instance, programming_languages, "programming_languages")
646666
set_tags(instance, platform_tags, "platform_tags")
647667

648668
raw_license = validated_data.pop("license")

django/library/urls.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
r"codebases/(?P<identifier>[\w\-.]+)/releases", views.CodebaseReleaseViewSet
1616
)
1717
router.register(r"reviewers", views.PeerReviewerViewSet),
18+
router.register(r"programming-languages", views.ProgrammingLanguageViewSet),
1819
router.register(
1920
r"reviews/(?P<slug>[\da-f\-]+)/editor/invitations",
2021
views.PeerReviewInvitationViewSet,

django/library/views.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
Contributor,
6161
CodebaseImage,
6262
License,
63+
ProgrammingLanguage,
6364
PeerReview,
6465
PeerReviewer,
6566
PeerReviewerFeedback,
@@ -73,6 +74,7 @@
7374
ContributorSerializer,
7475
DownloadRequestSerializer,
7576
PeerReviewerSerializer,
77+
ProgrammingLanguageSerializer,
7678
ReleaseContributorSerializer,
7779
CodebaseReleaseEditSerializer,
7880
CodebaseImageSerializer,
@@ -1227,3 +1229,14 @@ def form_valid(self, form):
12271229

12281230
def get_success_url(self):
12291231
return reverse("core:profile-detail", kwargs={"pk": self.request.user.id})
1232+
1233+
1234+
class ProgrammingLanguageViewSet(CommonViewSetMixin, NoDeleteViewSet):
1235+
"""
1236+
ViewSet for ProgrammingLanguage model
1237+
"""
1238+
queryset = ProgrammingLanguage.objects.all()
1239+
serializer_class = ProgrammingLanguageSerializer
1240+
pagination_class = SmallResultSetPagination
1241+
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
1242+
ordering = ["is_pinned", "name"]

frontend/package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frontend/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
"sortablejs": "^1.15.2",
4343
"sortablejs-vue3": "^1.2.11",
4444
"vue": "^3.2.47",
45-
"vue-multiselect": "^3.0.0-beta.1",
45+
"vue-multiselect": "^3.3.1",
4646
"vue-router": "^4.3.0",
4747
"yup": "^1.3.3"
4848
},

0 commit comments

Comments
 (0)