【问题标题】:Conditionally Filter Within Django Queryset在 Django 查询集中有条件地过滤
【发布时间】:2019-01-08 08:33:09
【问题描述】:

我想知道是否有一种方法可以根据过滤的值是否为None 有条件地过滤 Django 中的查询集。我知道你可以这样做:

some_name = 'Bob'
qs = MyModel.objects.filter(gender='boy')
if some_name:
    qs = qs.filter(name=some_name)

我们有条件地过滤变量some_name 仅当它存在时。我很好奇是否可以使用单个查询语句复制此逻辑,而不是在过滤器上“链接”到查询集的末尾。所以这看起来像:

qs = MyModel.objects.filter(gender='boy').filter(name=some_name if some_name else None)

显然,该示例无效,因为它会过滤 name=None 而不是不过滤,但是有没有人找到一种方法来做我想做的事情?对于更长的嵌套查询,将所有内容放在一个语句中会非常有帮助。

【问题讨论】:

    标签: python django


    【解决方案1】:

    我不相信在 Django 中有专门的内置方法可以做到这一点,但您可以使用字典解包运算符 ** 和字典推导来实现所需的结果。

    例如:

    some_name = 'Bob'
    field_value_pairs = [('gender', 'boy'), ('name', some_name)]
    filter_options = {k:v for k,v in field_value_pairs if v}
    qs = MyModel.objects.filter(**filter_options)
    

    所以如果some_nameNone,那么'name' 字段将从filter_options 中排除,因此不会包含在过滤器查询中。


    更新:

    您还可以使用Q object 构建一个查询,该查询可以传递给filter 方法的单个调用。这允许更大的灵活性并允许类似于 SQL WHERE 子句的更复杂的过滤。

    例如:

    from django.db.models import Q
    
    some_name = 'Bob'
    query = Q(gender='boy')
    if some_name:
        query = query & Q(name=some_name)
    qs = MyModel.objects.filter(query)
    

    或者,如果您想要一个更紧凑的视图来处理像这样的简单情况:

    query = Q(gender='boy') & (Q(name=some_name) if some_name else Q())
    

    或(更接近您想要的外观):

    qs = MyModel.objects.filter(Q(gender='boy') & (Q(name=some_name) if some_name else Q()))
    

    请注意,使用单独的filter 调用并不是很糟糕,因为只会进行一次数据库查询(假设您在最后一次filter 调用之前不尝试引用查询集中的对象)。您可以通过looking at the database queries Django is making 进行检查。但就风格而言,我可以看到只调用一次filter 的偏好。

    【讨论】:

      猜你喜欢
      • 2011-06-09
      • 2020-08-22
      • 2019-04-15
      • 2011-09-29
      • 2011-02-04
      • 2011-06-11
      相关资源
      最近更新 更多