36

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

我想知道条件过滤器是否适用于 django。也就是说,“如果变量不是无则过滤,否则不应用过滤”。

像这样的东西:

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

我想做的是仅在类别不是无时应用类别过滤器。

如果 category 是 None (意味着它没有在请求对象中给出),那么这个过滤器根本不会被应用。这将为我节省一堆“if-elif-else”的情况。

有没有办法做到这一点?

4

5 回答 5

50

您可以链接查询:

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)

由于查询集是延迟执行的,因此只有在显示项目时才会发生 DB 命中。

于 2012-09-29T09:29:46.600 回答
16

它们是解决您问题的几种方法。一种方法是使用 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  )

这只是一个代码示例,适合您的要求。小心 single_和 double __

于 2012-09-29T08:42:00.830 回答
9

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

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))
于 2014-08-20T06:03:19.353 回答
4

要继续@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)as argsto objects.filteras args 而我们想给kwargstoQ()

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

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))
于 2019-02-11T14:11:35.877 回答
1
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我们将得到过滤后的结果

于 2019-11-01T13:04:05.283 回答