如何在过滤器中添加if语句?

时间:2018-06-26 19:21:20

标签: python django

我有4个参数:城市,省份,strtype,方向,当该参数不为空时,我想在过滤器中使用它;当它为空时,请勿将其设置为过滤器关键字。

我使用的当前代码部分如下:

if (direction == '') & (strtype == '') & (city == '') & (province == ''):
    queryset = address.objects.filter(addline__startswith=keyword)[:10]
    if not queryset.exists():
        queryset = address.objects.filter(strname__startswith=keyword)[:10]
        return queryset
    else:
        return queryset

if (direction != '') & (strtype == '') & (city == '') & (province == ''):
    queryset = address.objects.filter(addline__startswith=keyword, 
                                      strdir=direction)[:10]
    if not queryset.exists():
        queryset = address.objects.filter(strname__startswith=keyword, 
                                          strdir=direction)[:10]
        return queryset
    else:
        return queryset

有16种可能性,这意味着我需要写16条if语句!这是太多的代码且不适合使用,有没有简洁的解决方案?

2 个答案:

答案 0 :(得分:7)

您可以构建字典,然后使用双星语法f(**kwargs)将其作为关键字参数传递:

conds = {}
if direction != '': conds["strdir"] = direction
if strtype != '': conds["strtype"] = strtype
if province != '': conds["province"] = province
if city != '': conds["city"] = city
queryset = address.objects.filter(addline__startswith=keyword, 
                                  **conds)[:10]
if not queryset.exists():
    queryset = address.objects.filter(strname__startswith=keyword, 
                                      **conds)[:10]

答案 1 :(得分:1)

  

有16种可能性,这意味着我需要写16条if语句!

否!,如果这些参数或多或少地独立发挥作用,则不会。例如,我们可以先提取抽象的通用逻辑:

def add_custom_filters(qs, direction, strtype, city, province):
    if direction:
        qs = qs.filter(strdir=direction)
    if strtype:
        qs = qs.filter(strype=strtype)
    if city:
        qs = qs.filter(strcity=city)
    if privince:
        qs = qs.filter(strprov=privince)
    return qs

(可能需要一些改动)

所以现在我们可以像这样使用这种逻辑:

queryset = address.objects.filter(addline__startswith=keyword)
queryset = add_custom_filters(queryset, direction, strtype, city, province)[:10]
if not queryset:
    queryset = address.objects.filter(strname__startswith=keyword)
    queryset = add_custom_filters(queryset, direction, strtype, city, province)[:10]
return queryset

因此,我们仅需要四个if案例,并且我们将此功能重复用于两次尝试方法。

由于过滤(如果不是真实性为True)是常见的模式,因此我们可以将其封装在辅助函数中:

def filter_if_truthfull(qs, **kwargs):
    retrurn qs.filter(**{k: v for k, v in kwargs.items() if v})

然后我们可以像这样使用它:

queryset = address.objects.filter(addline__startswith=keyword)
queryset = filter_if_truthfull(queryset, strdir=direction, strtype=strtype, strcity=city, strprov=province)[:10]
if not queryset:
    queryset = address.objects.filter(strname__startswith=keyword)
    queryset = filter_if_truthfull(queryset, strdir=direction, strtype=strtype, strcity=city, strprov=province)[:10]
return queryset

这允许我们添加任意数量的 named 过滤条件,这些条件仅在值具有真实性true的情况下才适用(对于字符串,如果字符串不为空,则为true,否则为true) None,它不是字符串,但也不会考虑使用这些过滤器。

如果仍然要使用QuerySet的结果,最好检查if queryset,因为这将执行查询,并将元素也加载到queryset中,而.exists()将使用EXISTS查询,如果您以后要处理这些元素,则需要执行额外的查询以将其提取到内存中。