2017-11-18 142 views
0

下面我有一個簡單的模型不同orderingfilter:Django的休息框架:對於不同的領域

class Ingredient(models.Model): 
    name = models.CharField(max_length=30) 

我使用Django的休息框架API端點。

class IngredientListAPIView(ListAPIView): 
    queryset = Ingredient.objects.all() 
    serializer_class = IngredientListSerializer 
    filter_backends = [OrderingFilter] 

我希望我的兩個端點,以輸出爲:

?ordering=name -- i want the ordering to be case-insensitive 
?ordering=-name -- i want the ordering to be case-insensitive 

只有這樣,才能實現這一目標是創建

class CaseInsensitiveOrderingFilter(OrderingFilter): 

    def filter_queryset(self, request, queryset, view): 
     ordering = self.get_ordering(request, queryset, view) 

     if ordering: 
      new_ordering = [] 
      for field in ordering: 
       if field.startswith('-'): 
        new_ordering.append(Lower(field[1:]).desc()) 
       else: 
        new_ordering.append(Lower(field).asc()) 
      return queryset.order_by(*new_ordering) 

     return queryset 

然後

class IngredientListAPIView(ListAPIView): 
    queryset = Ingredient.objects.all().order_by(Lower('name')) 
    serializer_class = IngredientListSerializer 
    filter_backends = [CaseInsensitiveOrderingFilter] 

但現在當我訪問以下端點

?ordering=id -- it shows 1,10,11,12 
?ordering=-id -- it shows 99,98 ..100.. 

如果我使用filter_backends = [OrderingFilter]代替filter_backends = [CaseInsensitiveOrderingFilter]

?ordering=id -- it shows 1,2,3,4, 
?ordering=-id -- it shows 220,221,220 

所以如何告訴Django使用

filter_backends = [CaseInsensitiveOrderingFilter] for name field and 
filter_backends = [OrderingFilter] for id field 

回答

0

我建議有不區分大小寫領域特定的類屬性

class IngredientListAPIView(ListAPIView): 
    queryset = Ingredient.objects.all().order_by(Lower('name')) 
    serializer_class = IngredientListSerializer 
    filter_backends = [CaseInsensitiveOrderingFilter] 
    ordering_fields =() # include both normal and case insensitive fields 
    ordering_case_insensitive_fields =() # put here only case insensitive fields 

然後自定義排序類將是:

class CaseInsensitiveOrderingFilter(OrderingFilter): 

    def filter_queryset(self, request, queryset, view): 
     ordering = self.get_ordering(request, queryset, view) 
     insensitive_ordering = getattr(view, 'ordering_case_insensitive_fields',()) 

     if ordering: 
      new_ordering = [] 
      for field in ordering: 
       if field in insensitive_ordering: 
        new_ordering.append(Lower(field[1:]).desc() if field.startswith('-') else Lower(field).asc()) 
       else: 
        new_ordering.append(field) 
      return queryset.order_by(*new_ordering) 

     return queryset 
+0

使用filter_backends看起來更加靈活。我有一個查詢。爲什麼我們不能提到orders_fields =('name')作爲CaseInsensitiveOrderingFilter中的一個屬性,而不是在IngredientListAPIView中提及 –

+0

你可以看看https://github.com/encode/django-rest-framework/issues/5606#event- 1348371639。並在那裏回答。 –

+0

我得到errro:如果我使用ordering_fields =('__all'__),'Query'對象沒有屬性'aggregates'。如果我使用ordered_fields =('id','name'),它可以很好地工作 –

0

views.py

class IngredientListAPIView(ListAPIView): 
    queryset = Ingredient.objects.all() 
    serializer_class = IngredientListSerializer 

    def filter_queryset(self, queryset): 
     if "name" in self.request.query_params.get("ordering"): 
      return CaseInsensitiveOrderingFilter().filter_queryset(self.request, queryset, self) 
     else: 
      queryset = OrderingFilter().filter_queryset(self.request, queryset, self) 
      return SearchFilter().filter_queryset(self.request, queryset, self) 
+0

但是如果我想與訂購過濾器一起添加SearchFilter什麼。我們可以通過'filter_backends = [SearchFilter,CaseInsensitiveOrderingFilter]'來完成。如何將它添加到filter_queryset方法 –

+0

我添加到帖子。你能看到我編輯的答案嗎?這是你想要的嗎 ? – origamic

+0

它的返回html而不是JSON –