Django 有条件地过滤对象



我想使用一组过滤器从数据库中检索一堆行。

我想知道条件过滤器是否适用于 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我们将得到过滤后的结果

最新更新