Django Haystack索引在模型中不适用于多个领域

nik*_*nik 1 django search whoosh django-haystack

我在我们的django应用程序中使用haystack进行搜索和搜索工作非常好.但是我遇到了reamtime搜索的问题.对于实时搜索,我使用haystack的默认RealTimeSignalProcessor(haystack.signals.RealtimeSignalProcessor).我的模型中包含一个多对多的字段.当仅针对此多对多字段更改数据时,似乎realtimesignal处理器未正确更新索引数据.更新了多个到多个数据后,我的搜索结果出错了.

它在手动运行rebuild_index命令后工作.我认为rebuild_index正在工作,因为它首先进行清理,然后再次构建索引数据.

有人可以提出一些问题的解决方案吗?

顺便说一下,围绕它的代码.

模型:

class Message_forum(models.Model):
      message = models.ForeignKey(Message)
      tags = models.ManyToManyField(Tag, blank=True, null=True) #this is many to many field
Run Code Online (Sandbox Code Playgroud)

search_index.py:

class Message_forumIndex(indexes.SearchIndex, indexes.Indexable):
    text = indexes.EdgeNgramField(document=True, use_template=True)
    message = indexes.CharField(model_attr='message', null=True)
    tags = indexes.CharField(model_attr='tags', null=True)

    def get_model(self):
        return Message_forum

    def index_queryset(self, using=None):
        return self.get_model().objects.all()

    def prepare_tags(self, obj):
        return [tag.tag for tag in obj.tags.all()]
Run Code Online (Sandbox Code Playgroud)

索引模板:

{{ object.tags.tag }}
Run Code Online (Sandbox Code Playgroud)

settings.py:

HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'
Run Code Online (Sandbox Code Playgroud)

我有干草堆的最新版本,并且作为后端嗖的一声.

nik*_*nik 9

我在挖掘干草堆的代码后想出来了.

在haystack默认的RealTimeSignalProcessor中,它连接每个应用程序模型的post_save和post_delete信号.现在在handle_save方法中调用post_save和post_delete信号.在这种方法中,haystack正在验证发送者,在我的情况下验证标签(多对多)字段,Message_forum_tag模型作为发送者传递.现在我的search_index中没有这个模型的索引,因为它不是我的应用程序模型,而是django生成的模型.因此在handle_save方法中,它绕过了此模型的任何更改,因此它没有更新已更改对象的索引数据.

所以我已经找到了两个不同的解决方案来解决这个问题.

  1. 我可以创建特定于我的模型Message_forum的自定义实时信号处理器,在这个设置方法中,我可以使用handle_save在Message_forum中的每个多对多字段上连接m2mchanged信号.同时我可以将Message_forum作为发送方传递,以便haystack将通过验证(不完全验证,但试图获取其索引obj)并将更新已更改对象的索引数据.

  2. 另一种方法是确保每当更改任何多对多字段时,都会调用其父节点(此处为Message_forum.save())的保存方法.因此它将始终调用post_save信号,之后haystack将更新索引对象数据.

花了大约3个小时来搞清楚.希望这会帮助有同样问题的人.


Dan*_*n D 6

我有一个类似的问题,但我选择了Nikhil的1号和2号混合选项.

对于名为ContentItem的模型,其中m2m字段称为类别,我创建了一个自定义信号处理器,扩展了基本信号处理器.

所以我实现了从源复制的setup(),但添加了以下行:

models.signals.m2m_changed.connect(self.handle_save, sender=ContentItem.categories.through)
Run Code Online (Sandbox Code Playgroud)

和teardown()做了同样的事,但是有一个类似的断开线.我还扩展了handle_save并更改了行:

index = self.connections[using].get_unified_index().get_index(sender)
Run Code Online (Sandbox Code Playgroud)

index = self.connections[using].get_unified_index().get_index(instance.__class__)
Run Code Online (Sandbox Code Playgroud)

这意味着此信号处理器正在监视ContentItem到Category的管理表中的m2m更改,但是当进行m2m更改时,将传递正确类的名称,即ContentItem而不是ContentItem.categories.through.

这似乎在很大程度上起作用,但是如果我删除了一个类别,尽管删除了关系,m2m_changed也不会触发.看起来这可能是django本身的一个错误.

所以我还在设置中添加了以下行(以及断开连接):

models.signals.pre_delete.connect(self.handle_m2m_delete, sender=Category)
Run Code Online (Sandbox Code Playgroud)

并创建了handle_save(handle_m2m_delete)的方法副本,该方法从through表中手动删除了关系并保存了受影响的ContentItems(导致原始handle_save被触发).这至少意味着我不必记得保存父代以在代码中的任何其他位置更新索引.