【问题标题】:How can I use OrderingFilter without exposing the names of the fields in the database如何在不暴露数据库中字段名称的情况下使用 OrderingFilter
【发布时间】:2016-02-14 23:41:06
【问题描述】:

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

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

【问题讨论】:

    标签: django django-views django-rest-framework django-filter


    【解决方案1】:
    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 过滤器文档: https://django-filter.readthedocs.io/en/latest/ref/filters.html#orderingfilter

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

    【讨论】:

    • django-filter==2.0 中,filter_class 已重命名为filterset_class
    【解决方案2】:

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

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

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

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

    班级:

    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
    

    【讨论】:

    • 谢谢,这行得通。在函数定义中我不得不说filters.OrderingFilter。在ViewSet 中,在filter_backends 中添加AliasedOrderingFilter
    • 需要在remove_invalid_fields声明中添加request arg
    【解决方案3】:

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

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

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

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

    更新: 您的请求网址应如下所示:

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

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

    您可以了解更多here

    【讨论】:

    • 我不明白。在这种情况下,请求将使用什么参数要求按字段field1 进行排序?
    • 我已经知道了。我要问的是,有没有办法使用字段名称的别名而不是字段名称?也就是说,我可以有一个看起来像api/users?ordering=alias_for_field1 的请求吗?这样我就不必暴露字段的内部命名。
    • @PGryllos 在这种情况下,我建议您覆盖 get_queryset 方法并手动处理排序,而不是使用 OrderingFilter 后端。如果您坚持使用OrderingFilter 后端,那么您可能必须创建一个新的自定义过滤器类,该过滤器类继承OrderingFilter 类并根据您的要求覆盖OrderingFilter 方法。
    • 这不是问题的答案。问题是关于用模型名称替换参数名称。
    猜你喜欢
    • 1970-01-01
    • 2010-09-14
    • 2019-07-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-09
    相关资源
    最近更新 更多