Repository: readthedocs/readthedocs.org

Issue:
Sort versions smartly everywhere
We currently have code that is smart about version sorting in Python:

https://github.com/rtfd/readthedocs.org/blob/master/readthedocs/projects/templatetags/projects_tags.py#L13

We should make sure that we're using this everywhere that we display versions to a user. 

Refs https://github.com/rtfd/readthedocs.org/pull/5037. 


Discussion:

Resolving patch:
diff --git a/readthedocs/projects/forms.py b/readthedocs/projects/forms.py
--- a/readthedocs/projects/forms.py
+++ b/readthedocs/projects/forms.py
@@ -22,6 +22,7 @@
 from readthedocs.oauth.models import RemoteRepository
 from readthedocs.projects import constants
 from readthedocs.projects.exceptions import ProjectSpamError
+from readthedocs.projects.templatetags.projects_tags import sort_version_aware
 from readthedocs.projects.models import (
     Domain,
     EmailHook,
@@ -235,9 +236,7 @@ def __init__(self, *args, **kwargs):
             choices=[default_choice] + list(all_versions),
         )
 
-        active_versions = self.instance.all_active_versions().values_list(
-            'slug', 'verbose_name'
-        )  # yapf: disabled
+        active_versions = self.get_all_active_versions()
         self.fields['default_version'].widget = forms.Select(
             choices=active_versions,
         )
@@ -253,6 +252,21 @@ def clean_conf_py_file(self):
             )  # yapf: disable
         return filename
 
+    def get_all_active_versions(self):
+        """
+        Returns all active versions.
+
+        Returns a smartly sorted list of tuples.
+        First item of each tuple is the version's slug,
+        and the second item is version's verbose_name.
+        """
+        version_qs = self.instance.all_active_versions()
+        if version_qs.exists():
+            version_qs = sort_version_aware(version_qs)
+            all_versions = [(version.slug, version.verbose_name) for version in version_qs]
+            return all_versions
+        return [()]
+
 
 class UpdateProjectForm(
         ProjectTriggerBuildMixin,
@@ -429,12 +443,14 @@ def build_versions_form(project):
     versions_qs = project.versions.all()  # Admin page, so show all versions
     active = versions_qs.filter(active=True)
     if active.exists():
+        active = sort_version_aware(active)
         choices = [(version.slug, version.verbose_name) for version in active]
         attrs['default-version'] = forms.ChoiceField(
             label=_('Default Version'),
             choices=choices,
             initial=project.get_default_version(),
         )
+    versions_qs = sort_version_aware(versions_qs)
     for version in versions_qs:
         field_name = 'version-{}'.format(version.slug)
         privacy_name = 'privacy-{}'.format(version.slug)
diff --git a/readthedocs/projects/views/public.py b/readthedocs/projects/views/public.py
--- a/readthedocs/projects/views/public.py
+++ b/readthedocs/projects/views/public.py
@@ -26,6 +26,7 @@
 from readthedocs.builds.views import BuildTriggerMixin
 from readthedocs.projects.models import Project
 from readthedocs.search.indexes import PageIndex
+from readthedocs.projects.templatetags.projects_tags import sort_version_aware
 from readthedocs.search.views import LOG_TEMPLATE
 
 from .base import ProjectOnboardMixin
@@ -171,6 +172,7 @@ def project_downloads(request, project_slug):
         slug=project_slug,
     )
     versions = Version.objects.public(user=request.user, project=project)
+    versions = sort_version_aware(versions)
     version_data = OrderedDict()
     for version in versions:
         data = version.get_downloads()


Test patch: