• 拓展django-haystack全文检索的样式和搜索频率限制


    一、样式:

    django-haystack在utils模块中封装了HighHighlighter用于配置搜索结果的样式展示。想要更改结果的样式,可以写个子类重写相应的方法达到效果

    1.关键字高亮:

    HighHighlighter为模版文件提供了搜索关键字相关的配置信息,只需在模版文件search.html中使用即可

     1 # 关键字高亮分为三步:
     2 # 1.模版引用
     3 {% load highlight %}
     4 
     5 # 2.改变模版变量的填充方式
     6 # 改变写法后,higtlight会为原结果中的关键字部分添一个span标签,并设置class为highlighted
     7 # 改变前
     8 {{ item.object.title }}
     9 # 改变后
    10 {% highlight item.object.title with query %}
    11 
    12 # 3.给关键字设置样式
    13 <style>
    14     span.highlighted {
    15         color: red;
    16     }
    17 </style>

    效果如下:

    注:我这里改了关键字显示位置,原生的django-haystack的搜索结果是会以 ... 开头,然后拼接关键字以及后面部分的。

    2.关键字显示位置:

    通过改变HighHighlighter类的find_window方法可改变关键字显示位置,具体实现如下:

     1 # 1.定义子类继承,并重写find_window方法
     2 class MyHighlighter(Highlighter):
     3     """自定义Highlighter,改变高亮部分前面文本长度"""
     4     def find_window(self, highlight_locations):
     5         best_start = 0
     6         best_end = self.max_length
     7 
     8         # First, make sure we have words.
     9         if not len(highlight_locations):
    10             return (best_start, best_end)
    11 
    12         words_found = []
    13 
    14         # Next, make sure we found any words at all.
    15         for word, offset_list in highlight_locations.items():
    16             if len(offset_list):
    17                 # Add all of the locations to the list.
    18                 words_found.extend(offset_list)
    19 
    20         if not len(words_found):
    21             return (best_start, best_end)
    22 
    23         if len(words_found) == 1:
    24             # 查找内容中只找到一个query
    25             best_start = words_found[0]
    26             best_end = words_found[0] + self.max_length
    27 
    28             if best_end > len(self.text_block):
    29                 move_forward_steps = best_end - len(self.text_block)
    30                 best_start -= move_forward_steps
    31 
    32             if best_start < 0:
    33                 best_start = 0
    34 
    35         return (best_start, best_end)
    36 
    37 # 2.django的settings文件中自定义Highlighter类
    38 HAYSTACK_CUSTOM_HIGHLIGHTER = 'utils.haystack_custom.MyHighlighter'

    效果如上图

    二、搜索频率限制:

    跟踪haystack.urls可以知道,Django-haystack的视图定义在SearchView这个类中

    1 # haystack.urls.py
    2 
    3 urlpatterns = [
    4     url(r'^$', SearchView(), name='haystack_search'),
    5 ]

    urls.py中将SearchView的类对象直接作为视图函数,当搜索请求来的时候,将会执行SearchView类的__call__方法,__call__方法源码如下:

     1     def __call__(self, request):
     2         """
     3         Generates the actual response to the search.
     4 
     5         Relies on internal, overridable methods to construct the response.
     6         """
     7         # 获取request对象
     8         self.request = request
     9     
    10         # 获取form中的参数
    11         self.form = self.build_form()
    12         # 校验form参数
    13         self.query = self.get_query()
    14         # 生成搜索结果
    15         self.results = self.get_results()
    16     
    17         # 返回视图
    18         return self.create_response()

    那么,可以写个子类继承SearchView类,在SearchView类的__call__方法执行之前,从request对象中获取到用户ip,然后对ip做频率限制即可实现我们的需求,实现如下:

     1 # 1.写个子类继承SearchView类,重写__call__方法
     2 
     3 # 导入这里就不说了
     4 class MySearchView(SearchView):
     5     """自定义search视图函数,添加IP搜索频率限制"""
     6     def __call__(self, request):
     7         # 获取用户IP
     8         ip = request.META.get("REMOTE_ADDR", "")
     9         if ip == "":
    10             return super(MySearchView, self).__call__(request)
    11 
    12         try:
    13             has_search_flag = cache.get("has_search_%s" % ip)
    14         except Exception as e:
    15             settings.LOGGER.error(e)
    16             return super(MySearchView, self).__call__(request)
    17         else:
    18             if has_search_flag is None:
    19                 cache.set("has_search_%s" % ip, 1, settings.SEARCH_FREQUENCY_FORBID_TIME)
    20                 return super(MySearchView, self).__call__(request)
    21 
    22         return render(request, 'search/search.html', {"errmsg":"您的操作过于频繁,请稍后再试"})
    23 
    24 # 2.修改路由匹配
    25 
    26 # 导入这里就不说了
    27 urlpatterns = [
    28     # path('search', include('haystack.urls')),  # 全文检索框架
    29     path('search', MySearchView(), name="haystack_search"),  # 全文检索框架
    30 ]

    ------------------------------

    更新:当搜索结果分页后,用户点击下一页或上一页,是会改变page参数重新发起请求的,这里也会视为频繁操作,那就有问题了。

    于是逻辑修改如下:将缓存中的从固定的1改成存关键字,下次搜索关键字变更了的情况下才加以限制,实现如下:

     1 class MySearchView(SearchView):
     2     """自定义search视图函数,添加IP搜索频率限制"""
     3     def __call__(self, request):
     4         # 获取用户IP
     5         search_q = request.GET.get("q", None)
     6         if search_q is None:
     7             return render(request, 'search/search.html', {"errmsg":"参数有误"})
     8 
     9         ip = request.META.get("REMOTE_ADDR", "")
    10         if ip == "":
    11             return super(MySearchView, self).__call__(request)
    12 
    13         try:
    14             has_search_flag = cache.get("has_search_%s" % ip)
    15         except Exception as e:
    16             settings.LOGGER.error(e)
    17             return super(MySearchView, self).__call__(request)
    18         else:
    19             if has_search_flag:
    20                 if has_search_flag != search_q:
    21                     return render(request, 'search/search.html', {"errmsg":"您的操作过于频繁,请稍后再试"})
    22                 else:
    23                     return super(MySearchView, self).__call__(request)
    24             else:
    25                 cache.set("has_search_%s" % ip, search_q, settings.SEARCH_FREQUENCY_FORBID_TIME)
    26                 return super(MySearchView, self).__call__(request)
  • 相关阅读:
    JAVA Unsafe类
    进程通信的五种普通方法
    监控API的实现 周末补
    INLINE HOOK 简单实现
    跨域资源请求方式
    在博客园放入“可运行”javascript代码
    一些学习资源
    XXE篇-本着就了解安全本质的想法,尽可能的用通俗易懂的语言去解释安全漏洞问题
    Mongodb注入
    SSRF篇-本着就了解安全本质的想法,尽可能的用通俗易懂的语言去解释安全漏洞问题
  • 原文地址:https://www.cnblogs.com/zzmx0/p/15228354.html
Copyright © 2020-2023  润新知