Django1.1 + Django-Haystack2.8.1 + Elasticsearch2.3.0(重写搜索过滤)

本文详述了如何在Django Haystack中定制搜索视图和查询集,包括使用自定义SearchForm和SearchQuerySet进行高级搜索逻辑的实现,以及如何通过过滤和排序来优化搜索结果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、在 SearchForm 类的 search() 中:

    def search(self):
        if not self.is_valid():
            return self.no_query_found()

        if not self.cleaned_data.get('q'):
            return self.no_query_found()

        sqs = self.searchqueryset.auto_query(self.cleaned_data['q'])

        if self.load_all:
            sqs = sqs.load_all()

        return sqs

ps: 1、self.searchqueryset 拿到了所有做搜索的 model 结果
    2、self.cleaned_data['q'] 是搜索的内容
    3、sqs 是与 搜索内容 匹配的结果(全部表的数据)

2、在自定义的搜索结果视图类中

class OrderSearchView(SearchView):

    def __init__(self):
        super(OrderSearchView, self).__init__(template='searches/search_order.html',
                                                          load_all=True,
                                                          form_class=ModelSearchFormCustom,
                                                          searchqueryset=SearchQuerySetCustom(),
                                                          results_per_page=None)
        if not isinstance(self.searchqueryset, SearchQuerySetCustom):
            self.searchqueryset = SearchQuerySetCustom()

        self.searchqueryset._models = (Order,)

    def get_results(self):
        kwargs = {
            'username': self.request.user.username
        }
        return self.form.search(**kwargs).order_by('-create_time')

ps: 1、template 指定 结果页面
    2、form_class 指定 自定义 继承ModelSearchForm的类, ModelSearchForm继承自SearchForm
    3、searchqueryset 指定 自定义 继承SearchQuerySet(实现了诸如filter的函数、查询与搜索内容相符的结果)的类
    4、self.searchqueryset._models 指定希望搜索结果是 某一个model的结果
    5、(重要)kwargs 里的 username 必须是 OrderIndex 里定义了的, 也就是说对搜索结果排序、过滤(filtr)等操作的的字段不能用原Order表的字段

3、OrderSearchView 所对应的 Index 类

from haystack import indexes


class OrderIndex(indexes.SearchIndex, indexes.Indexable):
    text = indexes.CharField(document=True, use_template=True)
    data_id = indexes.IntegerField(model_attr='id', stored=False)
    username = indexes.CharField(model_attr='user__username')
    create_time = indexes.DateTimeField(model_attr='create_time')

    def get_model(self):
        return Order

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

ps: 1、username、create_time 是自己增加的过滤条件,username指定了与Order表关联的User表的username字段
    2、要用ID排序的话,必须加 stored=False,不保存到索引中去。因为haystack索引主键是ID,如果保存到索引中,排序的时候会报返回两个ID

4、以下是自定义的两个类

from haystack.forms import ModelSearchForm
from haystack.query import SearchQuerySet
from haystack.inputs import AutoQuery, Raw
from haystack.backends import SQ


class SearchQuerySetCustom(SearchQuerySet):

    def __init__(self, using=None, query=None):
        super(SearchQuerySetCustom, self).__init__(using, query)
        self._models = ()

    def auto_query(self, **kwargs):
        """
        Performs a best guess constructing the search query.

        This method is somewhat naive but works well enough for the simple,
        common cases.
        """
        return self.filter(**kwargs)

    def exclude(self, *args, **kwargs):
        """Narrows the search by ensuring certain attributes are not included."""
        clone = self.models(*self._models)
        clone.query.add_filter(~SQ(*args, **kwargs))
        return clone

    def filter_and(self, *args, **kwargs):
        """Narrows the search by looking for (and including) certain attributes."""
        clone = self.models(*self._models)
        clone.query.add_filter(SQ(*args, **kwargs))
        return clone

    def filter_or(self, *args, **kwargs):
        """Narrows the search by ensuring certain attributes are not included."""
        clone = self.models(*self._models)
        clone.query.add_filter(SQ(*args, **kwargs), use_or=True)
        return clone


class ModelSearchFormCustom(ModelSearchForm):

    def search(self, fieldname='content', **kwargs):

        if not self.is_valid():
            return self.no_query_found()

        if not self.cleaned_data.get('q'):
            return self.no_query_found()

        kwargs[fieldname] = AutoQuery(self.cleaned_data['q'])

        sqs = self.searchqueryset.auto_query(**kwargs)

        if self.load_all:
            sqs = sqs.load_all()

        return sqs.models(*self.get_models())
        # return sqs

ps: 1、OrderSearchView 类里 self.form是 ModelSearchFormCustom对象,所以self.form.search(**kwargs)调用的方法就是 ModelSearchFormCustom 里的search方法
    2、原 ModelSearchForm 的search方法:
        def search(self):
            sqs = super(ModelSearchForm, self).search()
            return sqs.models(*self.get_models())
    此方法里的search方法(SearchForm类):
        def search(self):
            if not self.is_valid():
                return self.no_query_found()

            if not self.cleaned_data.get('q'):
                return self.no_query_found()

            sqs = self.searchqueryset.auto_query(self.cleaned_data['q'])

            if self.load_all:
            sqs = sqs.load_all()

            return sqs
    3、默认使用的方法是 filter_and()

ps: 1、 没有大量测试,但是目前来看没什么问题

      2、不知道这个搜索框架底层到底是什么实现的,也就是说先筛选指定model,再做过滤会不会更快

附上本地测试结果:服务器、数据库(mysql)在新加坡:

    3、linux 命令重建索引 免输入 “y”:echo "y"|python3 /root/项目/manage.py rebuild_index

    4、linux 一行输入两个命令:Linux:  mkdir -p /root/abc && cp * -rf "$_"(命令大意是:强制复制 当前目录下的所有 到 mkdir创建的 “abc” 目录下)

二、升级优化:

1、假如有以下几张表

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值