Always True Q 对象

Always True Q object

我想动态创建 Django ORM 过滤器查询的某些部分,现在我可以这样做:

if some:
   Obj.filter(
       some_f1=some_v1,
       f1=v1,
       f2=v2,
       f3=v3,
       f4=v4,
       ...
   )
else:
   Obj.filter(
       f1=v1,
       f2=v2,
       f3=v3,
       f4=v4,
       ...
   )

我想要像这样没有重复代码的东西:

Obj.filter(
    Q(some_f1=some_v1) if some else True,  # what to use instead of True?
    f1=v1,
    f2=v2,
    f3=v3,
    f4=v4,
    ...
)

试试这个;

conditions = {'f1':f1,'f2':f2, 'f3':f3}
if some:
    conditions['some_f1'] = some_v1

Obj.objects.filter(**conditions)

根据this答案我们可以使条件参数传递

Obj.filter(
    *( (Q(some_f1=some_v1),) if some  else ()),    
    f1=v1,
    f2=v2,
    f3=v3,
    f4=v4,
    ...
)

所以,如果 someTrue 我们将元组 (Q(some_f1=some_v1),) 添加到参数列表,在其他情况下我们添加空元组 (),我们还需要将它包装起来在 *() 中,当我们传递非关键字参数

的元组时,一如既往

正如 Alasdair 在评论中的回答:

Obj.filter(
    Q(some_f1=some_v1) if some else Q(), 
    f1=v1,
    f2=v2,
    f3=v3,
    f4=v4,
    ...
)

QuerySets are lazy 起,您可以创建默认过滤器,然后根据您的条件添加其他过滤器。 Django 不会 运行 查询,直到 QuerySet 被评估(例如,在 for 循环中迭代它)

filtered_objects = Obj.filter(
    some_f1=some_v1,
    f1=v1,
    f2=v2,
    f3=v3,
    f4=v4,
    ...
)
if some:
    filtered_objects.filter(some_f1=some_v1)

这里有一个获取始终为真的 Q 对象的 hacky 方法:

always_true = ~Q(pk=None)

这取决于主键不能为空。

"always true" Q 对象在使用 AND(基本过滤器语法;即 x and True == x)时等同于 No Q 对象,因此您的用例的 DRYer 替代方案如下:

filters = dict(f1=v1,
               f2=v2,
               f3=v3,
               f4=v4,
               ...)
if some:
    filters['some_f1'] = some_v1

qs = obj.filter(**filters)

根据您的需要进行修改。