Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add projects API ordering #1060

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 45 additions & 1 deletion docker-app/qfieldcloud/core/views/projects_views.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
from django.contrib.auth import get_user_model
from django.db import transaction
from django.db.models import CharField, QuerySet, TextField
from django.db.models.functions import Lower
from django.http import HttpRequest
from drf_spectacular.utils import (
OpenApiParameter,
OpenApiTypes,
Expand All @@ -11,7 +14,7 @@
from qfieldcloud.core.serializers import ProjectSerializer
from qfieldcloud.core.utils2 import storage
from qfieldcloud.subscription.exceptions import QuotaError
from rest_framework import generics, permissions, viewsets
from rest_framework import filters, generics, permissions, viewsets

User = get_user_model()

Expand Down Expand Up @@ -46,6 +49,43 @@ def has_permission(self, request, view):
return False


class ProjectOrderingFilter(filters.OrderingFilter):
def filter_queryset(
self, request: HttpRequest, queryset: QuerySet, view: viewsets.ModelViewSet
) -> QuerySet:
"""
Filters a query set to sort it by ordering values, if any
Returns the ordered QuerySet
"""
ordering = self.get_ordering(request, queryset, view)

if not ordering:
return queryset

new_ordering = []
for field in ordering:
descending = field.startswith("-")
clean_field = field.lstrip("-")

# owner's username is a FK
if field == "owner":
field = "owner__username"

# check if the ordering field is char/text
field_object = queryset.model._meta.get_field(clean_field)
if isinstance(field_object, (CharField, TextField)):
new_ordering.append(
Lower(clean_field).desc()
if descending
else Lower(clean_field).asc()
)
# if not, just use regular ordering
else:
new_ordering.append(field)

return queryset.order_by(*new_ordering)


@extend_schema_view(
retrieve=extend_schema(description="Retrieve a project"),
update=extend_schema(description="Update a project"),
Expand Down Expand Up @@ -77,6 +117,8 @@ class ProjectViewSet(viewsets.ModelViewSet):
lookup_url_kwarg = "projectid"
permission_classes = [permissions.IsAuthenticated, ProjectViewSetPermissions]
pagination_class = pagination.QfcLimitOffsetPagination()
filter_backends = [ProjectOrderingFilter]
ordering_fields = ["owner", "name", "created_at"]

def get_queryset(self):
projects = Project.objects.for_user(self.request.user)
Expand Down Expand Up @@ -133,6 +175,8 @@ class PublicProjectsListView(generics.ListAPIView):
permission_classes = [permissions.IsAuthenticated]
serializer_class = ProjectSerializer
pagination_class = pagination.QfcLimitOffsetPagination()
filter_backends = [ProjectOrderingFilter]
ordering_fields = ["owner", "name", "created_at"]

def get_queryset(self):
return Project.objects.for_user(self.request.user).filter(is_public=True)
Loading