在使用ORM的“额外”方法时,对“where”子句值进行OR运算

时间:2012-11-23 18:48:49

标签: django django-orm

TLDR 使用where parameter of the extra method of django's queryset api时,您可以插入对您的查询AND的自定义SQL。我有一种情况,我需要重置OR来重置查询。这有支持吗?


我有一个表与另一个表有M2M关系

class BookName:
    name = models.CharField(db_index=True)
    other_names = models.ManyToManyField(OtherName)

class OtherBookName:
    name = models.CharField(db_index=True)

我想查询列表中具有全名或替代名称的图书。

使用Q()会自然减慢速度。

我的解决方案是首先查询OtherBookName以查找列表中包含名称的行并返回这些pks(索引时速度很快)。然后我手动在两个模型之间包含M2M表,并添加一个where子句,该子句还应该拉出表中匹配的BookName实例。

test_names = ["Foo", "Bar",]
other_ids = OtherBookName.objects.filter(name__in=test_names).values_list("id", flat=True)
queryset = self\
            .filter(Q(name__in=test_names)) \
            .extra(
                where=[
                    "bookname_id = app_bookname.id",
                    "booknameotherbookname_id IN (%s)" 
                        % ",".join([str(id) for id in other_ids]),
                ],
                tables=["app_bookname_otherbookname",]) \
            .distinct()

这非常接近于工作,除了我想要AND时我的where claus是OR

1 个答案:

答案 0 :(得分:0)

试试这个:

names = ["Foo", "Bar",]
other_ids = OtherBookName.objects.filter(name__in=names).values_list("id", flat=True)
where_clause = "bookname_id = app_bookname.id AND (name IN (%s)" \
                % ",".join(names) + " OR booknameotherbookname_id IN (%s))" \
                % ",".join([str(id) for id in other_ids])
queryset = self\
            .extra(
                where=[where_clause],
                tables=["app_booknames_otherbookname",]) \
            .distinct()