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