如何在不公开数据库中字段名称的情况下使用 OrderingFilter

How can I use OrderingFilter without exposing the names of the fields in the database

我有一个使用 OrderingFilter 后端的模型。现在只允许按字段 id 排序。

我也想提供按其他字段排序的选项,但不必在我的数据库中公开字段名称。有办法吗?

是的,您可以通过在您的视图中使用 ordering_fields 属性来做到这一点,例如:

class YourViewSet(viewsets.ModelViewSet):
    serializer_class = yourSerializer
    filter_backends = (filters.OrderingFilter,)
    ordering_fields = ('field1', 'field2')

ordering_fields 中,您提到了允许排序的所有字段。

此处 field1field2 不需要出现在序列化程序 fields 属性中,因此它们不会出现在您的 API 响应中。

更新: 您的请求 url 应该是这样的:

http://example.com/api/users?ordering=field1

ordering 是查询参数。您需要将 ordering 设置为要用于订购查询集的字段名称。

你可以了解更多here

我创建了一个 AliasedOrderingFilter 应该能很好地满足这个需求。它扩展了 ordering_fields 属性以允许字段和字符串的元组。例如,您可以将视图 ordering_fields 设置为:

ordering_fields = (('alias1', 'field1'),('alias2', 'field2'), 'field3')

在带有 ordering=alias1,-alias2,field3 的请求中使用此 class 将导致:

qs.order_by('field1', '-field2', 'field3)

class:

class AliasedOrderingFilter(OrderingFilter):
    ''' this allows us to "alias" fields on our model to ensure consistency at the API level
        We do so by allowing the ordering_fields attribute to accept a list of tuples.
        You can mix and match, i.e.:
        ordering_fields = (('alias1', 'field1'), 'field2', ('alias2', 'field2')) '''

    def remove_invalid_fields(self, queryset, fields, view):      
        valid_fields = getattr(view, 'ordering_fields', self.ordering_fields)
        if valid_fields is None or valid_fields == '__all__':
            return super(AliasedOrderingFilter, self).remove_invalid_fields(queryset, fields, view)

        aliased_fields = {}
        for field in valid_fields:
            if isinstance(field, basestring):
                aliased_fields[field] = field
            else:
                aliased_fields[field[0]] = field[1]

        ordering = []
        for raw_field in fields:
            invert = raw_field[0] == '-'
            field = raw_field.lstrip('-')
            if field in aliased_fields:
                if invert:
                    ordering.append('-{}'.format(aliased_fields[field]))
                else:
                    ordering.append(aliased_fields[field])
        return ordering
pip install django-filter

在您看来:

from rest_framework import viewsets, filters
from django_filters.filters import OrderingFilter
from .models import MyList
from .serializers import MyListSerializer

class MyFilter(django_filters.FilterSet):
    surname = django_filters.CharFilter(name="model_field_name_2")

    order_by_field = 'ordering'
    ordering = OrderingFilter(
        # fields(('model field name', 'parameter name'),)
        fields=(
            ('model_field_name_1', 'name'),
            ('model_field_name_2', 'surname'),
            ('model_field_name_3', 'email'),
        )
    )

    class Meta:
        model = MyList
        fields = ['model_field_name_2',]

class MyListViewSet(viewsets.ModelViewSet):
    serializer_class = MyListSerializer
    filter_backends = (filters.DjangoFilterBackend,)
    filter_class = MyFilter
    
    def get_queryset(self):
        return MyList.objects.all()

你可以这样做:

/my-list?ordering=name,surname,email
/my-list?ordering=-email&surname=taylor

django-filter 文档: https://django-filter.readthedocs.io/en/latest/ref/filters.html#orderingfilter

drf 文档: http://www.django-rest-framework.org/api-guide/filtering/#djangofilterbackend