Skip to content

Commit c589e2f

Browse files
authored
Redirect downloads/latest/python3.x for given 3.x (#2816)
1 parent 568f643 commit c589e2f

File tree

7 files changed

+57
-28
lines changed

7 files changed

+57
-28
lines changed

downloads/managers.py

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,11 @@ def pymanager(self):
2929
def latest_python2(self):
3030
return self.python2().filter(is_latest=True)
3131

32-
def latest_python3(self):
33-
return self.python3().filter(is_latest=True)
32+
def latest_python3(self, minor_version: int | None = None):
33+
if minor_version is None:
34+
return self.python3().filter(is_latest=True)
35+
pattern = rf"^Python 3\.{minor_version}\."
36+
return self.python3().filter(name__regex=pattern).order_by("-release_date")
3437

3538
def latest_pymanager(self):
3639
return self.pymanager().filter(is_latest=True)
@@ -44,22 +47,10 @@ def released(self):
4447

4548
class ReleaseManager(Manager.from_queryset(ReleaseQuerySet)):
4649
def latest_python2(self):
47-
qs = self.get_queryset().latest_python2()
48-
if qs:
49-
return qs[0]
50-
else:
51-
return None
52-
53-
def latest_python3(self):
54-
qs = self.get_queryset().latest_python3()
55-
if qs:
56-
return qs[0]
57-
else:
58-
return None
50+
return self.get_queryset().latest_python2().first()
51+
52+
def latest_python3(self, minor_version: int | None = None):
53+
return self.get_queryset().latest_python3(minor_version).first()
5954

6055
def latest_pymanager(self):
61-
qs = self.get_queryset().latest_pymanager()
62-
if qs:
63-
return qs[0]
64-
else:
65-
return None
56+
return self.get_queryset().latest_pymanager().first()

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_python3(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)