在Haystack搜索中排除对象,无需更新索引

5 投票
4 回答
2448 浏览
提问于 2025-04-17 18:52

我需要在Haystack搜索中排除一些值为 published=False 的对象。到目前为止,我的做法是添加一个 exclude(published=True),像这样:

class MymodelIndex(indexes.RealTimeSearchIndex, indexes.Indexable):
    def get_queryset(self):
        return Mymodel.objects.all().exclude(published=False)

这样做效果很好,但问题是每次数据库中添加新对象时,我都需要运行 ./manage.py rebuild_index,这让人觉得很麻烦。

我该如何做到不需要再运行其他命令呢?

备注:

Haystack的索引可以用于很多模型,所以像这样:

search = (
    SearchQuerySet().filter(content=term)
)

会返回多种类型的对象,而不仅仅是一个模型。

谢谢

4 个回答

2

从 haystack 2.4.0 版本开始,你可以使用 haystack.exceptions.SkipDocument 来跳过某些特定的记录,这样就能很方便地通过 index_queryset 来排除它们。

https://github.com/django-haystack/django-haystack/releases/tag/v2.4.0

3

我最近遇到过类似的事情,真是让人头疼。我找不到其他方法来解决这个问题。

首先,关于Haystack在多个模型上工作的这个问题,过滤器会返回所有匹配项:

Haystack在后台处理模型过滤,它使用一个叫做django_ct的属性来索引,这个属性的值是应用名称和模型名称。在我的情况下,它看起来像这样:django_ct='books.Title'

你可以尝试通过以下方式进行过滤:

SearchQuerySet.filter(content=term, django_ct='app.Model')

不过我不确定这样是否有效。在我的情况下,我还是需要进行原始搜索,所以我直接在那个搜索中添加了过滤:

sqs = SearchQuerySet()
sqs = sqs.raw_search(u'(title:(%s)^500 OR author:"%s"^400 OR "%s"~2 OR (%s)) AND (django_ct:books.Title)' % term)

无论你怎么获取,得到你想要的SearchQuerySet后,如果想要进一步过滤而不更新索引,你必须用自己的代码来实现。

# each item in a queryset has a pk property to the model instance it references
pks = [item.pk for item in list(sqs)] # have to wrap sqs in a list otherwise it causes problems

# use those pks to create a standard django queryset object
results = Model.objects.filter(pk__in=pks)

# Now you can do any additional filtering like normal
results = results.exclude(published=False)

当然,你可以把最后两个查询合并在一起,我只是分开写出来以便更清楚。

代码不算多,但因为各种原因,我花了很长时间才让它正常工作。希望这能对你有所帮助。

0

感谢@SI Eric,我找到了解决办法,虽然有点小技巧,但确实有效。

search = (
    SearchQuerySet().filter(content=term)
)

search_list = search[:]
unpublished_Mymodels = Mymodel.objects.filter(published=False)

for match in search_list:
    try:
        if match.model_name == 'Mymodel':
            if match._get_object() in unpublished_Mymodels:
                search_list.remove(match)
    except:
        pass

search = search_list

撰写回答