diff --git a/app/experimenter/experiments/constants.py b/app/experimenter/experiments/constants.py index 68f03f9a9..c39aa5123 100644 --- a/app/experimenter/experiments/constants.py +++ b/app/experimenter/experiments/constants.py @@ -85,6 +85,12 @@ class ExperimentConstants(object): (CHANNEL_RELEASE, CHANNEL_RELEASE), ) + # Ordering given in https://github.com/mozilla/experimenter/issues/1042 + CHANNEL_NIGHTLY_ORDER = 1 + CHANNEL_BETA_ORDER = 2 + CHANNEL_RELEASE_ORDER = 3 + CHANNEL_UNSET_ORDER = 0 + # Pref stuff PREF_TYPE_BOOL = "boolean" PREF_TYPE_INT = "integer" diff --git a/app/experimenter/experiments/models.py b/app/experimenter/experiments/models.py index c80b95fff..891034583 100644 --- a/app/experimenter/experiments/models.py +++ b/app/experimenter/experiments/models.py @@ -7,7 +7,7 @@ from django.contrib.postgres.fields import JSONField from django.core.validators import MaxValueValidator from django.db import models -from django.db.models import Max +from django.db.models import Case, Max, Value, When from django.urls import reverse from django.utils import timezone from django.utils.functional import cached_property @@ -511,6 +511,26 @@ def population(self): channel=self.firefox_channel, ) + @staticmethod + def firefox_channel_sort(): + """A Case that can be added to an Experiment QuerySet to sort.""" + return Case( + When( + firefox_channel=ExperimentConstants.CHANNEL_RELEASE, + then=Value(ExperimentConstants.CHANNEL_RELEASE_ORDER), + ), + When( + firefox_channel=ExperimentConstants.CHANNEL_BETA, + then=Value(ExperimentConstants.CHANNEL_BETA_ORDER), + ), + When( + firefox_channel=ExperimentConstants.CHANNEL_NIGHTLY, + then=Value(ExperimentConstants.CHANNEL_NIGHTLY_ORDER), + ), + default=Value(ExperimentConstants.CHANNEL_UNSET_ORDER), + output_field=models.IntegerField(), + ) + class ExperimentVariant(models.Model): experiment = models.ForeignKey( diff --git a/app/experimenter/experiments/tests/test_models.py b/app/experimenter/experiments/tests/test_models.py index 89c3b21af..244528339 100644 --- a/app/experimenter/experiments/tests/test_models.py +++ b/app/experimenter/experiments/tests/test_models.py @@ -838,6 +838,28 @@ def test_experiment_population_returns_correct_string(self): ) self.assertEqual(experiment.population, "0.5% of Nightly Firefox 57.0") + def test_experiment_firefox_channel_sort_does_sorting(self): + ExperimentFactory.create(firefox_channel=Experiment.CHANNEL_NIGHTLY) + ExperimentFactory.create(firefox_channel=Experiment.CHANNEL_RELEASE) + ExperimentFactory.create(firefox_channel=Experiment.CHANNEL_BETA) + ExperimentFactory.create(firefox_channel="") + sorted_experiments = ( + Experiment.objects.annotate( + firefox_channel_sort=Experiment.firefox_channel_sort() + ) + .order_by("firefox_channel_sort") + .values("firefox_channel_sort") + ) + self.assertEqual( + [r["firefox_channel_sort"] for r in sorted_experiments], + [ + Experiment.CHANNEL_UNSET_ORDER, + Experiment.CHANNEL_NIGHTLY_ORDER, + Experiment.CHANNEL_BETA_ORDER, + Experiment.CHANNEL_RELEASE_ORDER, + ], + ) + class TestExperimentChangeLog(TestCase): diff --git a/app/experimenter/experiments/views.py b/app/experimenter/experiments/views.py index 99d7b7b84..1ad42d56b 100644 --- a/app/experimenter/experiments/views.py +++ b/app/experimenter/experiments/views.py @@ -111,8 +111,8 @@ class ExperimentOrderingForm(forms.Form): ("latest_change", "Least Recently Updated"), ("firefox_version", "Firefox Version Ascending"), ("-firefox_version", "Firefox Version Descending"), - ("firefox_channel", "Firefox Channel Ascending"), - ("-firefox_channel", "Firefox Channel Descending"), + ("firefox_channel_sort", "Firefox Channel Ascending"), + ("-firefox_channel_sort", "Firefox Channel Descending"), ) ordering = forms.ChoiceField( @@ -141,6 +141,13 @@ def get_filterset_kwargs(self, *args, **kwargs): kwargs["data"] = self.request.GET return kwargs + def get_queryset(self): + qs = super().get_queryset() + qs = qs.annotate( + firefox_channel_sort=Experiment.firefox_channel_sort() + ) + return qs + def get_ordering(self): self.ordering_form = ExperimentOrderingForm(self.request.GET)