Skip to content

Commit

Permalink
feat: order by metainfo fields
Browse files Browse the repository at this point in the history
  • Loading branch information
czosel committed Jul 1, 2022
1 parent c4391ac commit 0a93026
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 5 deletions.
33 changes: 29 additions & 4 deletions emeis/core/filters.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from django.conf import settings
from django.db.models.functions import Lower
from django.db.models import TextField
from django.db.models.functions import Cast, Lower
from django_filters import FilterSet
from django_filters.filters import CharFilter
from rest_framework import filters
Expand Down Expand Up @@ -53,13 +54,28 @@ class Meta:
}


class CaseInsensitiveOrderingFilter(filters.OrderingFilter):
class EmeisOrderingFilter(filters.OrderingFilter):
"""Custom ordering filter for Emeis.
This adds two things:
- case insensitive ordering via "case_insensitive_ordering_fields"
- ordering by metainfo fields
"""

def get_valid_fields(self, queryset, view, context=None):
ordering_fields = super().get_valid_fields(queryset, view, context or {})
return ordering_fields + [
(f"metainfo__{field}", f"{field} in metainfo")
for field in self._meta_settings(view)
]

def _make_ordering_field(self, field, view):
desc = field.startswith("-")
field_name = field[1:] if desc else field

if field_name in getattr(view, "case_insensitive_ordering_fields", []):
return Lower(field_name).desc() if desc else Lower(field_name)
if field_name in self._get_case_insensitive_fields(view):
field_expr = Lower(Cast(field_name, output_field=TextField()))
return field_expr.desc() if desc else field_expr
return field

def get_ordering(self, request, queryset, view):
Expand All @@ -68,6 +84,15 @@ def get_ordering(self, request, queryset, view):
return ordering
return [self._make_ordering_field(field, view) for field in ordering]

def _meta_settings(self, view):
model_name = view.get_queryset().model.__name__.lower()
return settings.EMEIS_META_FIELDS.get(model_name, [])

def _get_case_insensitive_fields(self, view):
return getattr(view, "case_insensitive_ordering_fields", []) + [
f"metainfo__{field}" for field in self._meta_settings(view)
]


class ScopeFilterset(FilterSet):
class Meta:
Expand Down
19 changes: 19 additions & 0 deletions emeis/core/tests/test_filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,25 @@ def test_user_ordering_case_insensitive(admin_client, admin_user, user_factory,
assert expect_emails == [d["attributes"]["email"] for d in resp.json()["data"]]


@pytest.mark.parametrize("sort", ["metainfo__position", "-metainfo__position"])
def test_ordering_metainfo(admin_client, admin_user, user_factory, sort):
admin_user.user.metainfo = {"position": "d"}
admin_user.user.save()
positions = ["B", "a", "C"]
for position in positions:
user_factory.create(metainfo={"position": position})

resp = admin_client.get(reverse("user-list"), {"sort": sort})

expect = sorted(
positions + ["d"], key=lambda e: e.lower(), reverse=sort.startswith("-")
)

assert expect == [
d["attributes"]["metainfo"].get("position") for d in resp.json()["data"]
]


@pytest.mark.parametrize("sort", ["username", "-username"])
def test_user_ordering_case_sensitive(admin_client, admin_user, user_factory, sort):
user_factory.create_batch(5)
Expand Down
4 changes: 3 additions & 1 deletion emeis/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ def parse_languages(languages):
"DEFAULT_METADATA_CLASS": "rest_framework_json_api.metadata.JSONAPIMetadata",
"DEFAULT_FILTER_BACKENDS": (
"rest_framework_json_api.filters.QueryParameterValidationFilter",
"emeis.core.filters.CaseInsensitiveOrderingFilter",
"emeis.core.filters.EmeisOrderingFilter",
"rest_framework_json_api.django_filters.DjangoFilterBackend",
"emeis.core.filters.MonolingualSearchFilter",
),
Expand Down Expand Up @@ -278,3 +278,5 @@ def parse_admins(admins):
"": {"handlers": ["console"], "level": env.str("LOG_LEVEL", default="INFO")}
},
}

EMEIS_META_FIELDS = {"user": ["position"]}

0 comments on commit 0a93026

Please sign in to comment.