通过可迭代对象实现Django OR查询的最佳实践方法是什么?

3

我正在实现一个一次性数据导入程序,需要搜索已存在的slug。这些slug存储在一个数组中。转换数组为OR查询的最佳实践方式是什么?

我想到了以下解决方案,它能够正常工作,但感觉用了太多代码来完成这么简单的事情。

# slug might be an array or just a string
# ex:
slug = [ "snakes", "snake-s" ] # in the real world this is generated from directory structure on disk

# build the query
query = MyModel.objects
if hasattr(slug, "__iter__"):
    q = Q()
    for s in slug:
        q = q.__or__(Q(slug=s))
    query = query.filter(q)
else:
    query = query.filter(slug=slug)
4个回答

4
slug = ["snakes", "snake-s" ] # in the real world this is generated from directory structure on disk

# build the query
query = MyModel.objects
if hasattr(slug, "__iter__"):
    q_list = []
    for s in slug:
        q_list.append(Q(slug=s))
    query = query.filter(reduce(operator.or_, q_list))
else:
    query = query.filter(slug=slug)
  • q_list = [] 创建一个Q子句列表
  • reduce(operator.or_, q_list) 使用or运算符将列表合并

阅读此文:http://www.michelepasin.org/techblog/2010/07/20/the-power-of-djangos-q-objects/

@MostafaR - 如果我们愿意的话,我们可以将整个代码块压缩成一行(如下所示)。但是在那个层次上,它已经不太可读了。说代码不“Pythonic”只是因为它还没有被简化和模糊化是愚蠢的。我认为易读的代码是王道。同样重要的是要记住,我的答案的目的是展示通过运算符技术进行reduce操作。我回答中的其余部分只是为了将该技术与原始问题联系起来。

result = MyModel.objects.filter(reduce(operator.or_, [Q(slug=s) for s in slug])) if hasattr(slug, "__iter__") else MyModel.objects.filter(slug=slug)

1
你可以更Pythonic地编写这段代码,例如使用生成器语句代替三行代码来创建q_list。 - MostafaR
Pythonic的代码不是最少行数的代码,而你的一行代码也不够易读。但我确信q_list = [Q(slug=s) for s in slug]比你回答中的for语句更易读。 - MostafaR

1
result = MyModel.objects.filter(slug__in=slug).all() if isinstance(slug, list) else MyModel.objects.filter(slug=slug).all()

0

我认为在这种情况下,你应该使用Django的__in字段查询,像这样:

slugs = [ "snakes", "snake-s" ]
objects = MyModel.objects.filter(slug__in=slugs)

这个解决方案的问题与schacki的解决方案相同。 - MostafaR
我知道,不过 schacki 迟到了四分钟 :) - Pero
1
哦,这个我马上想到了,你只是比我打字速度快一些 :-) - schacki

-1
你发布的代码在很多方面都不会起作用(但我不确定它是否应该更像伪代码?),但从我的理解来看,这可能会有所帮助:
MyModel.objects.filter(slug__in=slug)

应该可以完成任务。


谢谢。不确定为什么,但我在文档页面上完全跳过了__in。 - Nate Pinchot
这个答案有bug,看看这个例子:'test' in 'xxtestxx' 返回 True。所以看起来这个解决方案是有效的,但实际上它会导致一些bug。in 运算符在 strlist 中的工作方式是不同的。 - MostafaR
@MostafaR 是的,我刚发现了。谢谢。 - Nate Pinchot
根据这个问题,slug是一个数组,而不是一个字符串,所以它确切地做了它应该做的事情,但同意,all()并不是必要的。 - schacki

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接