Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/332.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何在Django中向查询动态添加过滤器?_Python_Django_Django Orm - Fatal编程技术网

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

Python 如何在Django中向查询动态添加过滤器?,python,django,django-orm,Python,Django,Django Orm,在我的视图集中,我正在执行查询 queryset= Books.objects.all(); 现在,通过一个ajax调用,我从UI获得了我的过滤器值,即auther的年龄、性别等。总共有5个过滤器 现在我遇到的问题是如何向查询中添加过滤器(仅那些具有任何值的过滤器) 我尝试的是检查单个筛选器值并执行查询,但这样做会失败,就像用户删除筛选器值或添加多个筛选器一样。 有什么更好的建议可以实现这一点吗?您没有显示任何代码,因此您没有真正解释问题所在: 从querysetBook.objects.al

在我的视图集中,我正在执行查询

queryset= Books.objects.all();
现在,通过一个ajax调用,我从UI获得了我的过滤器值,即auther的年龄、性别等。总共有5个过滤器

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

我尝试的是检查单个筛选器值并执行查询,但这样做会失败,就像用户删除筛选器值或添加多个筛选器一样。
有什么更好的建议可以实现这一点吗?

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

从queryset
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'])
...

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

import operator
from django.db.models import Q


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\uu lte
作为筛选名称。

可能有助于简化其他人给出的解决方案

比如:

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})

有关更多信息,请参见。

您只需获取请求即可。以dict的形式获取内容(确保将值转换为字符串或所需类型,因为默认情况下它们是列表,即:
dict(request.get)
将为您提供类似于
{u'a':[u'val']}

一旦确定有与模型字段匹配的键字典,您只需执行以下操作:


filtered=queryset.filter(**dict_container)

这对我很有效,我将Alex Morozov的答案与


你可以这样做

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

值得一提的是,只有在需要结果时才会对其进行评估:)+1任何人这比我的答案更枯燥。我认为首先理解我的答案更容易,所以这两个答案很好地结合在一起:)注意,您可能需要
request.GET.GET(filter)
而不是
request.GET中的filter.GET
,如果提交空字符串,它们会给出不同的结果。@Alasdair,很好的捕获,谢谢!用你的建议更新了答案。你完全正确,我个人不喜欢我答案中的
reduce
部分,希望我们能更通俗地表达它。@AmanGupta,是的,Django允许你查询链接模型的字段:
过滤器=('a_book_field','author_an_author_field',)
等等。混合它们是完全可以的。我正是这样做的,但它总是说,
无法将关键字“filter”解析为字段
。有什么想法吗?我想在age中使用范围过滤器,那么如果self.request.query\u-params.get('age'):argumentos['age\u-gte']=self.request.query\u-params.get('age')argumentos['age\u-lte']=self.request.query\u-params.get('age'),我该怎么办呢@迪帕克·查拉
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