django有条件地过滤物体

时间:2012-09-29 08:34:18

标签: 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时应用类别过滤器。

如果category为None(表示未在请求对象中给出),则根本不会应用此过滤器。这样可以省去一堆'if-elif-else'的情况。

有办法做到这一点吗?

5 个答案:

答案 0 :(得分:22)

您可以链接查询:

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)

由于查询集是懒惰执行的,因此只有在显示项目时才会发生数据库命中。

答案 1 :(得分:8)

他们是解决您问题的几种方法。一种方法是使用Complex lookups with Q objects

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  )

这只是一个代码示例,符合您的要求。请注意单_和双__

答案 2 :(得分:5)

嗯,这是一个相当古老的问题但是对于那些想在一行上进行条件过滤的人来说,这是我的方法(顺便说一下,下面的代码可能用更通用的方式编写):

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

您唯一需要注意的是在conditional_category_filter(category)之类的关键字参数之前使用user=user调用。例如,以下代码将引发错误:

todays_items = Item.objects.filter(user=user, date=now(), conditional_category_filter(category))

答案 3 :(得分:2)

继续@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)赋予args作为参数,而我们想赋予objects.filter赋予kwargs

我现在正在生产中使用它(我将只修改过滤器名称,因为它很敏感):

Q()

答案 4 :(得分:0)

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中,我们将得到过滤后的结果