如何在Django中动态地向查询添加过滤器?

时间:2016-01-12 09:21:00

标签: python django django-orm

在我的viewSet中,我正在进行查询,

queryset= Books.objects.all();

现在从ajax调用我从UI获取我的过滤器值,即auther的年龄,性别等。总共将有5个过滤器。

现在我遇到的问题是如何向查询添加过滤器(只有那些具有任何值的过滤器)。

我尝试的是检查了单个过滤器值并进行了查询,但这样就失败了,就像用户删除过滤器值或添加多个过滤器一样。 有什么更好的建议如何实现这个目标?

6 个答案:

答案 0 :(得分:9)

您尚未显示任何代码,因此您尚未真正解释问题所在:

从查询集Book.objects.all()开始。对于每个过滤器,检查request.POST中是否存在过滤器的值,如果是,则过滤查询集。 Django查询集是惰性的,因此只会评估最终的查询集。

queryset = Book.objects.all()
if request.POST.get('age'):
    queryset = queryset.filter(author__age=request.POST['age'])
if request.POST.get('gender'):
    queryset = queryset.filter(author__gender=request.POST['gender'])
...

答案 1 :(得分:8)

这是一个更通用的。如果它们作为GET参数传递,它将对您的查询集应用过滤器。如果您正在进行POST调用,只需更改代码中的名称即可。

import operator

def your_view(self, request, *args, **kwargs):
    # Here you list all your filter names
    filter_names = ('filter_one', 'filter_two', 'another_one', )

    queryset = Books.objects.all(); 
    filter_clauses = [Q(filter=request.GET[filter])
                      for filter in filter_names
                      if request.GET.get(filter)]
    if filter_clauses:
        queryset = queryset.filter(reduce(operator.and_, filter_clauses))

    # rest of your view

请注意,您可以在过滤器的名称中使用查找表达式。例如,如果您要过滤价格低于或等于过滤器中指定价格的图书,则可以使用price__lte作为过滤器名称。

答案 2 :(得分:4)

你可以简单地获取request.GET内容作为dict(确保将值转换为字符串或所需类型,因为它们是默认列表,即:dict(request.GET)会给你类似{{{ 1}}。

一旦确定您拥有与模型字段匹配的密钥字典,您就可以执行以下操作:

{u'a': [u'val']}

答案 3 :(得分:2)

也许django-filter有助于简化其他人提供的解决方案?

类似的东西:

class BookFilter(django_filters.FilterSet):
    class Meta:
        model = Book
        fields = ['author__age', 'author__gender', ...]

然后视图如下:

def book_list(request):
    f = BookFilter(request.GET, queryset=Book.objects.all())
    return render_to_response('my_app/template.html', {'filter': f})

有关详细信息,请参阅documentation

答案 4 :(得分:1)

这对我有用,我将Alex Morozov的回答与Dima answer

合并了
import operator

def your_view(self, request, *args, **kwargs):
    # Here you list all your filter names
    filter_names = ('filter_one', 'filter_two', 'another_one', )

queryset = Books.objects.all(); 
filter_clauses = [Q(**{filter: request.GET[filter]})
                  for filter in filter_names
                  if request.GET.get(filter)]
if filter_clauses:
    queryset = queryset.filter(reduce(operator.and_, filter_clauses))

# rest of your view

答案 5 :(得分:0)

您可以做类似的事情

class BooksAPI(viewsets.ModelViewSet):
    queryset = Books.objects.none()


def get_queryset(self):
    argumentos = {}
    if self.request.query_params.get('age'):
        argumentos['age'] = self.request.query_params.get('age')
    if self.request.query_params.get('gender'):
        argumentos['gender'] = self.request.query_params.get('gender')
    if len(argumentos) > 0:
        books = Books.objects.filter(**argumentos)
    else:
        books = Books.objects.all()
    return books