Как обрезать/вырезать ведущие пробелы из StringField для представления списка в Django/Mongodb?

Хочу отсортировать данные по именам, но к сожалению есть много данных с пробелами, поэтому rest_framework.filters.OrderingFilter не работает должным образом. В моем проекте используются Mongo, DRF.

Моя модель:

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,
    }

Мое мнение:

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']

У кого-нибудь есть идеи, как это решить?

Попытка аннотирования кверисета:

from django.db.models import F, Func
...
class BookViewSet(viewsets.ModelViewSet):
    ...
    def get_queryset(self):
        queryset = self.queryset.annotate(name_lower=Func(F('name'), function='LOWER'))

В mongoDB существует операция агрегации $trim, которую можно использовать для санации строковых данных, если вы хотите удалить только ведущие пробелы, вы можете использовать $ltrim ...

Если кто-то имеет дело с mongoengine, вы можете решить эту проблему с помощью 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)

Используется python 'trim_lower_name': {'$ltrim': {'input': {'$toLower': '$name'}}} потому что нужна сортировка без учета регистра

Найдите еще одно решение для этого вопроса

utils.py:

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

В views.py:

class BookViewSet(viewsets.ModelViewSet):
    serializer_class = BookSerializer
    queryset = Book.objects.all()

    def get_queryset(self):
        queryset = self.queryset
        return queryset.collation(collation)
Вернуться на верх