skip to Main Content

Want to sort data by names, but unfortunately there are many data with leading whitespaces, that is why rest_framework.filters.OrderingFilter doesn’t work properly. Mongo, DRF are used in my project.

My model:

from mongoengine import DynamicDocument, fields

class Book(DynamicDocument):
    name = fields.StringField(required=True)
    description = fields.StringField(blank=True, null=True)

    meta = {
        'collection': 'books',
        'strict': False,
    }

My view:

from rest_framework.filters import OrderingFilter
from rest_framework_mongoengine import viewsets

from core.serializers import BookSerializer
from core.models import Book

class BookViewSet(viewsets.ModelViewSet):
    serializer_class = BookSerializer
    queryset = Book.objects.all()
    filter_backends = [OrderingFilter]
    ordering_fields = ['name']
    ordering = ['name']

Someone has any idea, how to solve that?

3

Answers


  1. Chosen as BEST ANSWER

    If someone deals with mongoengine, you can solve this problem with queryset.aggregate():

    class BookViewSet(viewsets.ModelViewSet):
        serializer_class = BookSerializer
        queryset = Book.objects.all()
    
        def get_queryset(self):
            queryset = self.queryset
            pipeline = [
                {
                    '$project': {
                        'id': {'$toString': '$_id'},
                        'name': 1,
                        'ltrim_lower_name': {'$ltrim': {'input': {'$toLower': '$name'}}},
                        'description': 1,
                    }
                },
                {'$sort': {'ltrim_lower_name': 1}}
            ]
    
            return queryset.aggregate(pipeline)
    

    Used python 'trim_lower_name': {'$ltrim': {'input': {'$toLower': '$name'}}} because need case-insensitive sorting.


  2. There is aggregation operation called $trim in mongoDB that you can use to sanitize the string data , if you want to remove only the leading spaces then you can use the $ltrim

    Login or Signup to reply.
  3. Also find one more decision for this question

    utils.py:

    collation = dict(
        locale='en',
        caseLevel=False,
        caseFirst='off',
        strength=1,
        numericOrdering=True,
        alternate='shifted',
        maxVariable='space',
        backwards=False,
    )
    

    In views.py:

    class BookViewSet(viewsets.ModelViewSet):
        serializer_class = BookSerializer
        queryset = Book.objects.all()
    
        def get_queryset(self):
            queryset = self.queryset
            return queryset.collation(collation)
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search