Django-Haystack:should_update在RealtimeSignalProcessor中似乎未触发?

3 投票
2 回答
1038 浏览
提问于 2025-04-17 22:27

我有一个模型,这个模型里有一个布尔字段,用来表示这个模型对象是否是活跃的。简单来说,我希望Haystack能忽略那些active=False的对象。对于完全重新索引,这个方法是有效的:

def index_queryset(self, using=None):
    return ExampleModel.objects.filter(active=True)

但是当一个对象被更新,并且索引是实时更新而不是完全重新索引的时候,比如说把一个对象改为不活跃状态,下面的代码就不起作用,而且似乎也没有被调用:

def should_update(self, instance):
    if instance.active:
        return True
    self.remove_object(instance)
    return False

我希望当对象被标记为不活跃时,它能从索引中移除。然而,当我把对象更新为不活跃状态时,它依然留在索引里,这样会影响到一些统计数据。我用manage.py update_index命令检查了一下,发现should_update的代码似乎没有运行?

顺便提一下,我使用的是haystack的开发版和最新稳定版的elasticsearch。

有什么想法吗?

2 个回答

1
  1. 在你的应用目录里创建一个叫做 signals.py 的文件。
  2. 编辑 signals.py 文件:

    from haystack import signals
    from .models import Product
    from haystack.exceptions import NotHandled
    
    class ProductUpdateSignalProcessor(signals.RealtimeSignalProcessor):
    
        def handle_save(self, sender, instance, **kwargs):
            if isinstance(instance, Product):
                using_backends = self.connection_router.for_write(instance=instance)
                for using in using_backends:
                    try:
                        index = self.connections[using].get_unified_index().get_index(sender)
                        if instance.active:
                            index.update_object(instance, using=using)
                        else:
                            index.remove_object(instance, using=using)
                    except NotHandled:
                        print(NotHandled.message)
            else:
                super(ProductUpdateSignalProcessor, self).handle_save(sender, instance, **kwargs)
    
  3. 编辑 settings.py 文件:

    HAYSTACK_SIGNAL_PROCESSOR = 'products.signals.ProductUpdateSignalProcessor'
    
1

从源代码来看,should_update() 默认返回 True,这意味着会重新建立索引。此外,remove_object() 是和类的删除后钩子关联的,这可能就是它没有被调用的原因,因为你并没有删除记录。

你可以通过稍微修改你的代码来触发索引的移除,像这样:

def should_update(self, instance, **kwargs):
    if instance.active:
        return True
    else:
        self.remove_object(instance, **kwargs)
        return False

或者反过来:

def should_update(self, instance, **kwargs):
    if not instance.active:
        self.remove_object(instance, **kwargs)
    return instance.active

另一种选择是创建一个 CRON 脚本来执行:

import haystack
from yourapp.models import ExampleModel

for obj in ExampleModel.objects.filter(active=False):
    haystack.site.remove_object(obj)

这个方法也可以通过 Django 的 post_save 信号来使用。

小字说明:我没有测试过任何这段代码。这些都是基于问题中提供的信息的理论

撰写回答