Skip to content

Commit 68285eb

Browse files
committed
Redirect downloads/latest/python3.x for given 3.x
1 parent ea671db commit 68285eb

File tree

7 files changed

+58
-9
lines changed

7 files changed

+58
-9
lines changed

downloads/managers.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ def latest_python2(self):
3232
def latest_python3(self):
3333
return self.python3().filter(is_latest=True)
3434

35+
def latest_python3x(self, minor_version: int):
36+
pattern = rf"^Python 3\.{minor_version}\."
37+
return self.python3().filter(name__regex=pattern).order_by("-release_date")
38+
3539
def latest_pymanager(self):
3640
return self.pymanager().filter(is_latest=True)
3741

@@ -57,6 +61,13 @@ def latest_python3(self):
5761
else:
5862
return None
5963

64+
def latest_python3x(self, minor_version: int):
65+
qs = self.get_queryset().latest_python3x(minor_version)
66+
if qs:
67+
return qs[0]
68+
else:
69+
return None
70+
6071
def latest_pymanager(self):
6172
qs = self.get_queryset().latest_pymanager()
6273
if qs:

downloads/models.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,12 @@ def purge_fastly_download_pages(sender, instance, **kwargs):
292292
purge_url('/downloads/feed.rss')
293293
purge_url('/downloads/latest/python2/')
294294
purge_url('/downloads/latest/python3/')
295+
# Purge minor version specific URLs (like /downloads/latest/python3.14/)
296+
version = instance.get_version()
297+
if instance.version == Release.PYTHON3 and version:
298+
match = re.match(r'^3\.(\d+)', version)
299+
if match:
300+
purge_url(f'/downloads/latest/python3.{match.group(1)}/')
295301
purge_url('/downloads/latest/pymanager/')
296302
purge_url('/downloads/macos/')
297303
purge_url('/downloads/source/')

downloads/urls.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
urlpatterns = [
66
re_path(r'latest/python2/?$', views.DownloadLatestPython2.as_view(), name='download_latest_python2'),
77
re_path(r'latest/python3/?$', views.DownloadLatestPython3.as_view(), name='download_latest_python3'),
8+
re_path(r'latest/python3\.(?P<minor>\d+)/?$', views.DownloadLatestPython3x.as_view(), name='download_latest_python3x'),
89
re_path(r'latest/pymanager/?$', views.DownloadLatestPyManager.as_view(), name='download_latest_pymanager'),
910
re_path(r'latest/?$', views.DownloadLatestPython3.as_view(), name='download_latest_python3'),
1011
path('operating-systems/', views.DownloadFullOSList.as_view(), name='download_full_os_list'),

downloads/views.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,27 @@ def get_redirect_url(self, **kwargs):
4545
return reverse('download')
4646

4747

48+
class DownloadLatestPython3x(RedirectView):
49+
""" Redirect to latest Python 3.x release for a specific minor version """
50+
permanent = False
51+
52+
def get_redirect_url(self, **kwargs):
53+
minor_version = kwargs.get('minor')
54+
if not minor_version:
55+
return reverse('downloads:download')
56+
57+
try:
58+
minor_version_int = int(minor_version)
59+
latest_release = Release.objects.latest_python3x(minor_version_int)
60+
except (ValueError, Release.DoesNotExist):
61+
latest_release = None
62+
63+
if latest_release:
64+
return latest_release.get_absolute_url()
65+
else:
66+
return reverse('downloads:download')
67+
68+
4869
class DownloadLatestPyManager(RedirectView):
4970
""" Redirect to latest Python install manager release """
5071
permanent = False

static/sass/_layout.scss

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,7 @@
449449

450450
.release-version,
451451
.release-status,
452+
.release-dl,
452453
.release-start,
453454
.release-end,
454455
.release-pep {
@@ -458,10 +459,11 @@
458459
vertical-align: middle;
459460
}
460461

461-
.release-version { width: 15%; }
462+
.release-version { width: 10%; }
462463
.release-status { width: 20%; }
463-
.release-start { width: 25%; }
464-
.release-end { width: 25%; }
464+
.release-dl { width: 15%; }
465+
.release-start { width: 20%; }
466+
.release-end { width: 20%; }
465467
.release-pep { width: 15%; }
466468

467469
/* Previous Next pattern */

static/sass/mq.css

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1505,6 +1505,7 @@ html[xmlns] .slides { display: block; }
15051505

15061506
.release-version,
15071507
.release-status,
1508+
.release-dl,
15081509
.release-start,
15091510
.release-end,
15101511
.release-pep {
@@ -1514,16 +1515,19 @@ html[xmlns] .slides { display: block; }
15141515
vertical-align: middle; }
15151516

15161517
.release-version {
1517-
width: 15%; }
1518+
width: 10%; }
15181519

15191520
.release-status {
15201521
width: 20%; }
15211522

1523+
.release-dl {
1524+
width: 15%; }
1525+
15221526
.release-start {
1523-
width: 25%; }
1527+
width: 20%; }
15241528

15251529
.release-end {
1526-
width: 25%; }
1530+
width: 20%; }
15271531

15281532
.release-pep {
15291533
width: 15%; }

static/sass/no-mq.css

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1219,6 +1219,7 @@ a.button {
12191219

12201220
.release-version,
12211221
.release-status,
1222+
.release-dl,
12221223
.release-start,
12231224
.release-end,
12241225
.release-pep {
@@ -1228,16 +1229,19 @@ a.button {
12281229
vertical-align: middle; }
12291230

12301231
.release-version {
1231-
width: 15%; }
1232+
width: 10%; }
12321233

12331234
.release-status {
12341235
width: 20%; }
12351236

1237+
.release-dl {
1238+
width: 15%; }
1239+
12361240
.release-start {
1237-
width: 25%; }
1241+
width: 20%; }
12381242

12391243
.release-end {
1240-
width: 25%; }
1244+
width: 20%; }
12411245

12421246
.release-pep {
12431247
width: 15%; }

0 commit comments

Comments
 (0)