DRF - 是否可以将URL中的多个过滤器参数与某种OR逻辑符号组合在一起

时间:2016-01-06 05:11:59

标签: python django url django-rest-framework

我使用Django REST Framework构建了一个REST端点。

[HttpPost]
[AllowAnonymous]
public ActionResult Login(LoginModel usr)
{      
        if (usr.UserName=="random"&&usr.Password=="randPassword")
        {

            Session["Username"] = usr.UserName.ToString();
            FormsAuthentication.SetAuthCookie(user.UserName, false);
           return RedirectToAction("Success","Account",new {new {Name=usr.UserName}});
        }
        else
        {
            ModelState.AddModelError("", "UserName or Password is Wrong");
            return View();
        }

}

现在,如果我提出这样的请求:

class PersonFilter(django_filters.FilterSet):
    id = django_filters.NumberFilter(name="id", lookup_type="gt")
    first_name = django_filters.CharFilter(name="first_name", lookup_type="icontains")
    last_name = django_filters.CharFilter(name="last_name", lookup_type="icontains")

class Meta:
    model = Person
    fields = ('id', 'first_name', 'last_name', 'last_mod')

class PersonModelViewSet(viewsets.ReadOnlyModelViewSet):
    queryset = Person.objects.none()
    filter_backends = (filters.DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter)
    pagination_class = StandardResultsSetPagination
    ordering_fields = ('id', 'first_name', 'last_name', 'last_mod')
    ordering = ('last_mod', 'id')
    filter_class = PersonFilter

这只返回名字和姓氏都包含" foo"的那些对象。我想返回名字包含" foo"或姓氏包含" foo"。

我想知道URL参数中是否有可用的符号,这意味着过滤器之间的逻辑或关系。

一种解决方法是向端点发出两个单独的AJAX查询,但这需要额外的工作来统一结果。

3 个答案:

答案 0 :(得分:3)

不幸的是,目前的django_filter实施无法实现。每个过滤器都会就地修改查询集,而不是返回Q对象,这可以根据您的喜好加入。您可以尝试重写FilterSet.qs()方法并在self._qs.query.where上执行一些黑魔法,以使用OR重新组合子句。另请参阅editing the queryset filters上的问题。

更新:只要Django处理SQ​​L注入尝试真的很好,你就可以使用类似的东西:

qs.filter(map(operators.or_, [Q(k=v) for k, v in request.GET.items()]))

,但在投入生产之前肯定需要进行一些验证。

答案 1 :(得分:2)

我还想做类似的事情,最终使用django-filter创建了一个自定义过滤器,希望这会有所帮助:

class NameFilter(django_filters.CharFilter):
  def filter(self, qs, value):
    if value:
      return qs.filter(Q(**{first_name+'__'+self.lookup_expr: value}) |
                       Q(**{last_name+'__'+self.lookup_expr: value}))
    return qs


class PersonFilter(django_filters.rest_framework.FilterSet):
  name = NameFilter(lookup_expr='icontains')
  

/ api / rest / v1 / Person?name = foo&page_size = 10

这不是一个非常通用的解决方案,而是一个如何创建自己的过滤器的示例,它的通用性取决于您的代码实现。

答案 2 :(得分:1)

您可以使用复杂的单词并使用不同的前缀(不仅是'q')

query_reg = self.request.GET.get("r")
        if query_reg:
            queryset = queryset.filter(
                Q(region=query_reg)
            )
query_reg_air = self.request.GET.get("ra")
    if query_reg_air:
        queryset = queryset.filter(
            Q(region=query_reg_air.split('_')[0]) &
            Q(min_air_flow__lte=query_reg_air.split('_')[1]) &
            Q(max_air_flow__gte=query_reg_air.split('_')[1]) |
            Q(region=query_reg_air.split('_')[0]) &
            Q(min_air_flow__lte=str(float(query_reg_air.split('_')[1]) * 1.2)) &
            Q(max_air_flow__gte=str(float(query_reg_air.split('_')[1])))
            # Q(query__range=(min_air_flow, max_air_flow))
        ).order_by('-KPC')

Screenshot