我想使用一组过滤器从数据库中检索一堆行。
我想知道条件过滤器是否适用于 django。也就是说,"如果变量不是 None,则过滤,否则不应用过滤"。
像这样:
user = User.objects.get(pk=1)
category = Category.objects.get(pk=1)
todays_items = Item.objects.filter(user=user, date=now()).conditional_filter(category=category))
我想做的是仅在类别不是 None 时才应用类别过滤器。
如果类别为 None(表示它未在请求对象中给出),则根本不会应用此过滤器。这将为我节省一堆"if-elif-else"的情况。
有没有办法做到这一点?
您可以链接查询:
user = User.objects.get(pk=1)
category = Category.objects.get(pk=1)
qs = Item.objects.filter(user=user, date=now())
if category:
qs = qs.filter(category=category)
由于查询集是延迟执行的,因此仅当您显示项目时才会发生数据库命中。
它们是解决您问题的几种方法。一种方法是使用 Q 对象进行复杂查找
from django.db.models import Q
user = User.objects.get(pk=1)
category = Category.objects.get(pk=1)
f1 = Q( user=user, date=now() )
f_cat_is_none = Q( category__isnull = True )
f_cat_is_not_none = Q( category=category )
todays_items = Item.objects.filter( f1 & ( f_cat_is_none | f_cat_is_not_none ) )
我不能正确理解您的答案是否是您正在寻找的查询,但是,通过此示例,您可以轻松编写自己的查询。
编辑了由于OP评论
category__isnull == True
表示,在数据库中,该项没有关联的类别。也许您正在寻找的查询是:
from django.db.models import Q
user_pk = 1
category_pk = 1 #some times None
f = Q( user__pk = user_pk, date=now() )
if category_pk is not None:
f &= Q( category__pk = category_pk )
todays_items = Item.objects.filter( f )
这只是一个代码示例,请根据您的要求进行调整。小心单_
和双__
。
嗯,这是一个相当古老的问题,但对于那些想在一行上进行条件过滤的人来说,这是我的方法(顺便说一句,下面的代码可能可以用更通用的方式编写):
from django.db.models import Q
def conditional_category_filter(category):
if category != None:
return Q(category=category)
else:
return Q() #Dummy filter
user = User.objects.get(pk=1)
category = Category.objects.get(pk=1)
todays_items = Item.objects.filter(conditional_category_filter(category), user=user, date=now())
您唯一需要注意的是,在关键字参数(如 user=user
)之前使用 conditional_category_filter(category)
调用。例如,以下代码将引发错误:
todays_items = Item.objects.filter(user=user, date=now(), conditional_category_filter(category))
继续@iuysal答案:
要使其通用,您还需要将键作为参数传递,为此您需要传递字典,这是我的做法:
像这样创建字典:
filters = {'filter1': 'value1', 'filter2__startswith': 'valu', ...}
然后将其传递给您的项目过滤器,如下所示:
Item.objects.filter(*[Q(**{k: v}) for k, v in filters.items() if v], filter3='value3')
我拥有的第一个版本不太神秘:
def _filter(filters):
filters = []
for k, v in n.items():
if v:
filters.append(Q(**{k: v}))
return filters
filters = _filter({'name': name})
return Item.objects.filter(*filters)
解包说明:我们希望Q (queries)
给objects.filter
args
参数,而我们想给kwargs
Q()
我现在在生产中有了这个(我只会修改过滤器名称,因为它很敏感):
def get_queryset(self):
filter1 = self.request.GET.get('filter1 ', '')
filter2__startswith = self.request.GET.get('filter2_prefix ', '')
def filters_to_Qs(filters):
return [Q(**{k: v}) for k, v in filters.items() if v]
filters = {'filter1': filter1 ,
'filter2__startswith': filter2__startswith }
return Order.objects.filter(*filters_to_Qs(filters))
from django.db.models import Q
qs = Users.objects.filter(
p_id=parent_id,
status=True
).all()
if user_id>0:
qs = qs.filter( ~Q(id=user_id) )
qs
我们将得到过滤后的结果