在Haystack搜索中排除对象而无需update_index

时间:2013-03-12 22:15:15

标签: python django django-haystack

我需要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 个答案:

答案 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)

当然,您可以将最后两个查询组合在一起,我只是将它们拆分为显式。

这不是那么多代码,但是由于各种原因我花了很长时间才使它工作。希望它可以帮助你。

答案 1 :(得分:2)

自haystack 2.4.0起,您可以提升haystack.exceptions.SkipDocument以跳过使用index_queryset轻松排除的个人记录

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

答案 2 :(得分:1)

有一种方法可以在Haystack中按对象进行过滤。我遇到了与上述类似的问题,并在Haystack models API文档中遇到了SearchQuerySet方法。

来自Haystack(http://django-haystack.readthedocs.org/en/latest/searchqueryset_api.html#models

SearchQuerySet.models(self, *models)

接受要包含在搜索中的任意数量的Model类。这会将搜索结果缩小到仅包含指定模型的结果。

示例:

SearchQuerySet().filter(content='foo').models(BlogEntry, Comment)

因此,您可以根据需要按对象内容进行过滤。

答案 3 :(得分:0)

感谢@SI Eric,我能够找到答案,它也有点hacky但它​​确实有效。

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