整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

Django 博客实现简单的全文搜索

者:HelloGitHub-追梦人物

搜索是一个复杂的功能,但对于一些简单的搜索任务,我们可以使用 Django Model 层提供的一些内置方法来完成。现在我们来为我们的博客提供一个简单的搜索功能。

概述

博客文章通常包含标题和正文两个部分。当用户输入某个关键词进行搜索后,我们希望为用户显示标题和正文中含有被搜索关键词的全部文章。整个搜索的过程如下:

  1. 用户在搜素框中输入搜索关键词,假设为 “django”,然后用户点击了搜索按钮提交其输入的结果到服务器。
  2. 服务器接收到用户输入的搜索关键词 “django” 后去数据库查找文章标题和正文中含有该关键词的全部文章。
  3. 服务器将查询结果返回给用户。

整个过程就是这样,下面来看看 Django 如何用实现这些过程。

将关键词提交给服务器

先来回顾一下我们的 Django 博客的 Post(文章)模型:

blog/models.py
class Post(models.Model):
    # 标题
    title = models.CharField("标题", max_length=70)
    # 正文
    body = models.TextField("正文")
    
    # 其他属性...
    
	def __str__(self):
        return self.title

先看到第 1 步,用户在搜索框输入搜索关键词,因此我们要在博客上为用户提供一个搜索表单,HTML 表单代码大概像这样:

templates/base.html
<form role="search" method="get" id="searchform" action="{% url 'blog:search' %}">
  <input type="search" name="q" placeholder="搜索" required>
  <button type="submit"><span class="ion-ios-search-strong"></span></button>
</form>

特别注意这里 <input type="search" name="q" placeholder="搜索" required> 中的 name 属性,当用户在这个 input 中输入搜索内容并提交表单后,键入的数据会以键值对的形式提交服务器,这个键的名字就是通过 name 属性指定的。这样服务器就可以根据 name 的值来取得用户输入的内容。

用户输入了搜索关键词并点击了搜索按钮后,数据就被发送给了 Django 后台服务器。表单的 action 属性的值为 {% url 'blog:search' %}(虽然我们还没有写这个视图函数),表明用户提交的结果将被发送给 blog 应用下 search 视图函数对应的 URL。

查找含有搜索关键词的文章

搜索的功能将由 search 视图函数提供,代码写在 blog/views.py 里:

blog/views.py
from django.contrib import messages
def search(request):
    q = request.GET.get('q')
    if not q:
        error_msg = "请输入搜索关键词"
        messages.add_message(request, messages.ERROR, error_msg, extra_tags='danger')
        return redirect('blog:index')
    post_list = Post.objects.filter(Q(title__icontains=q) | Q(body__icontains=q))
    return render(request, 'blog/index.html', {'post_list': post_list})

首先我们使用 request.GET.get('q') 获取到用户提交的搜索关键词。用户通过表单 get 方法提交的数据 Django 为我们保存在 request.GET 里,这是一个类似于 Python 字典的对象,所以我们使用 get 方法从字典里取出键 q 对应的值,即用户的搜索关键词。这里字典的键之所以叫 q 是因为我们的表单中搜索框 input 的 name 属性的值是 q,如果修改了 name 属性的值,那么这个键的名称也要相应修改。

接下来我们做了一个小小的校验,如果用户没有输入搜索关键词而提交了表单,我们就无需执行查询,我们给给用户发一条错误提醒消息,这里使用了 django messages 应用,这在 交流的桥梁:评论功能中讲过。然后将用户重定向到首页。这里的 redirect 函数也在那篇教程中讲过。

如果用户输入了搜索关键词,我们就通过 filter 方法从数据库里过滤出符合条件的所有文章。这里的过滤条件是 title__icontains=q,即 title 中包含(contains)关键字 q,前缀 i 表示不区分大小写。这里 icontains 是查询表达式(Field lookups),我们在之前也使用过其他类似的查询表达式,其用法是在模型需要筛选的属性后面跟上两个下划线。Django 内置了很多查询表达式,建议过一遍 Django 官方留个印象,了解每个表达式的作用,以后碰到相关的需求就可以快速定位到文档查询其用途 Field lookups

此外我们这里从 from django.db.models 中引入了一个新的东西:Q 对象。Q 对象用于包装查询表达式,其作用是为了提供复杂的查询逻辑。例如这里 Q(title__icontains=q) | Q(body__icontains=q) 表示标题(title)含有关键词 q 或者正文(body)含有关键词 q ,或逻辑使用 | 符号。如果不用 Q 对象,就只能写成 title__icontains=q, body__icontains=q,这就变成标题(title)含有关键词 q 正文(body)含有关键词 q,就达不到我们想要的目的。

绑定 URL

有了视图函数后记得把视图函数映射到相应了 URL,如下。

blog/urls.py
urlpatterns = [
    # 其他 url 配置
    path('search/', views.search, name='search'),
]

大功告成,在导航栏尝试输入一些关键词,看看效果吧!

当然这样的搜索功能是非常简略的,难以满足一些复杂的搜索需求。编写一个搜索引擎是一个大工程,好在 django-haystack 这款第三方 app 为我们完成了全部工作。使用它我们可以实现更加复杂的搜索功能,比如全文检索、按搜索相关度排序、关键字高亮等等类似于百度搜索的功能,功能十分强大。当然其使用也会复杂一些,下一篇教程将向大家介绍 django-haystack 结合 Elasticsearch 搜索引擎的使用方法。


『讲解开源项目系列』——让对开源项目感兴趣的人不再畏惧、让开源项目的发起者不再孤单。跟着我们的文章,你会发现编程的乐趣、使用和发现参与开源项目如此简单。欢迎留言联系我们、加入我们,让更多人爱上开源、贡献开源

文分享的技术,是用Web做一个二分查找算法的小网页,包括所有的代码。

通过二分查找的原理,做一个闭环Web小应用,这个网页包括HTML、CSS和JavaScript的配合。通过制作这个网页,老铁们可以熟悉网页设计、练习算法的落地应用,做到学以致用

最终的二分算法网页效果展示 最终的二分算法网页效果展示

本文代码分为3个部分:

核心JavaScript代码讲解(包括调用函数JS代码);

HTML网页设计讲解;

CSS的美化讲解。

第1部分 JavaScript代码讲解

本案例的JavaScript代码包括核心的算法代码和调用代码。

先介绍核心算法代码:

function binarySearch(nums, target) //定义了一个名为 binarySearch 的函数,
//该函数接受两个参数,nums 是已排序数组,target 是要查找的目标值。
{
let left = 0;//声明两个变量 left 和 right,它们分别代表搜索范围的左边界和右边界。
//初始时,左边界为数组的第一个元素索引(0),右边界为数组的最后一个元素索引。
let right = nums.length - 1;
    while (left <= right) //使用循环来执行二分查找,条件是左边界小于等于右边界。
    {
    let middle = left + Math.floor((right - left) / 2);
    //计算当前搜索范围的中间位置,使用 Math.floor 函数确保取整。
    if (nums[middle] > target) //如果中间位置的元素值大于目标值。
        {
        right = middle - 1;//将右边界更新为中间位置的前一个位置,缩小搜索范围至左半部分。
        } 
    else if (nums[middle] < target) //如果中间位置的元素值小于目标值。
        {
        left = middle + 1;//将左边界更新为中间位置的后一个位置,缩小搜索范围至右半部分。
        } 
    else 
        {
        return middle;//直接返回中间位置的索引,表示找到目标值。
        }
    }
    return -1;
 }

这段代码的含义是:先定义两个边界索引,左边界初始值为0,右边界初始值为数组的长度。循环条件是左边界的数值小于右边界。

二分查找原理演示

二分查找是很基础的算法,很容易搜索到,在此不做更多的原理讲解。只要记住查找的数组必须有序排列即可。

由于这个算法要在Web端调用,因此还需要进行调用代码的编写:

function calculateBinarySearch() 
{
    const inputNums = document.getElementById("output").value.split(" ").map(Number);
    // 获取页面上 id 为 "output" 的元素的值,将其以空格分割成数字数组并映射为数字类型
    const inputTarget = parseInt(document.getElementById("textBox1").value);
    // 获取页面上 id 为 "textBox1" 的元素的值,将其解析为整数,作为二分查找的目标值
    const result = binarySearch(inputNums, inputTarget);
    // 调用二分查找函数 binarySearch,传入数字数组和目标值,并将结果保存在变量 result 中
    if (result !== -1) 
    // 如果结果不等于 -1,表示找到了目标值
    {
        document.getElementById("textBox2").value = `数字${inputTarget}排在第${result + 1}位`;
        // 在页面上 id 为 "textBox2" 的元素中显示目标值在数组中的位置(索引 + 1)
    } 

    else 
    {
       document.getElementById("textBox2").value = "这个数字不存在";
       // 如果结果等于 -1,表示目标值不存在于数组中
    }
}

在本案例中,显示25个数字的窗口是一个文本框“output”,一个输入查找数字的文本框“textBox1”和一个输出查找结果的文本框“textBox2”。

调用代码是将随机生成的25个数字提取成数组,把textBox1里输入的数字也进行必要的清洗,然后作为二分查找函数的输入值,进行计算,结算结果显示在textBox2中。

显示结果要进行一下必要的美化,做一下人机交互的设计。

如何生成25个随机数字,我会在另一篇文章仔细讲解,在此不做赘述。

第2部分 HTML代码讲解

本案例的HTML包括一个标题文件(其中包含一个LOGO图片)、1个展示25个数字的文本框output,1个输入文本框textBox1和1个输出文本框textBox2。还有两个按钮,分别控制生成25个数字和清除25个数字。

<h1>
    <img src="logo.png" alt="Logo" width="130" height="130">JavaScript编程练习:二分算法演示
</h1>

<textarea id="output" readonly>
</textarea>
<textarea id="textBox2" readonly> 
</textarea>

<br>
<div class="button-container">
    <button onclick="generateNumbers()">生成数字</button>
    <button onclick="clearText()">清空数字</button>
</div> 

<input type="text" id="textBox1">

<div class="color-box-container">
<div class="color-box" id="whiteBox" onclick="changeBackgroundColor('white')"></div>
<div class="color-box" id="blueBox" onclick="changeBackgroundColor('rgba(247, 160, 255, 0.348)')"></div>
<div class="color-box" id="pinkBox" onclick="changeBackgroundColor('rgba(202, 251, 189, 0.966)')"></div>
</div>

<a href="index.html">
    <button id="backToHomeButton">回到主页</button>
</a>

第3部分 CSS代码讲解

CSS代码考虑到了手机竖屏的应用。注意按钮使用了群组,本案例还有颜色代码块,纯装饰用,不是必须的。

在说这个之前,想必大家应该都比较了解搜索引擎了,它就是通过用户在浏览器输入框中输入文本,从而显示一些结果,你觉得哪项符合你要搜索的内容,你就点击哪项。

【一、项目准备】

浏览器:360浏览器

编辑器:Sublime Text 3

插件:Jquery-3.2.1.Min.Js

【二、项目实现】

由于是要实现一个网页搜索引擎,所以我们需要借用网页三剑客(Html+Css+Javascript),然后实现这一功能。

1.打开百度分析网页结构

我们可以先看看百度的搜索引擎:

可以看到,这个搜索框的部分设置,比如关闭自动完成功能。然后我们在随便搜索内容来查看它的变化:

image

可以看到某些我们查询的关键字,于是我们便发现了请求规律:

https://www.baidu.com/s?+查询字符参数

这就构成了我们的一个完整的get请求,而且这里面有很多关键字参数可以省略掉,只需要保留重要的一部分就好了。于是,经试验,得出如下结论:

https://www.baidu.com/s?wd=keyword

这个才是请求的接口地址,只需将keyword参数替换为任意搜索关键字即可实现查询并跳转到相应结果页面。

2.编写Html输入框,搜索按钮

看过之前写的Html系列的文章,你将不再对此感到困惑。

<html>
<head>
 <title></title>
 <style type="text/css">
    *{           内外边距初始时为0
       margin:0;    
       padding:0
    }
     input{
        width:300px;
        height:30px
    }
     span{
       position:absolute; 绝对定位
       background-color:red; 背景颜色
       border:1px solid gray; 边框设置
       width:60px;
       height:32px;
       text-align:center 文字位置
    }
    span:hover{ 鼠标悬停时的样式
        background-color:blue
    }
 </style>
</head>
<body>
<input type="text" name="" placeholder="请输入要搜索的内容"> 文本框
<span>search</span> 搜索按钮
</body>
</html>

编写完成后进入浏览器查看,即可看到:

可以看到,已经有点浏览器搜索框的意思了。

3.导入Jquery插件

<script src='jquery-3.2.1.min.js'></script>

4.编写js脚本

这个是重中之重,打开浏览器,network,继续分析:

可以看到搜索结果就在里面。然后打开这个请求的url地址,经过多次实验,发现就只有图中标记的参数有变化:

image.png

所以我们可以得出结论,我们只需要改变这两个值即可。

1).创建删除脚本

于是我先创建一个脚本标签,不用它的时候随时可以清除,避免占用内存,导致页面打开迟缓,性能降低:

var script=document.createElement('script');  创建script的标签
script.id='jsonp';   设置id为jsonp
script.src='https://www.baidu.com/sugrec?prod=pc&cb=getData&wd='+wd;  设置它的地址
document.body.appendChild(script);   添加script元素到body中

然后等它不用了,随时将它删除:

var script=document.createElement('script');  创建script的标签
script.id='jsonp';   设置id为jsonp
script.src='https://www.baidu.com/sugrec?prod=pc&cb=getData&wd='+wd;  设置它的地址
document.body.appendChild(script);   添加script元素到body中

2).生成选项下拉菜单

我们在浏览器可以看到,只要一输入文本,它就会弹出对应的选项让我们选择,那么这是如何办到的了?

<script>
function getlist(wd){    /*获取下拉列表*/
   var script=document.createElement('script');  /*创建script的标签*/
   script.id='jsonp';   /*设置id为jsonp*/
   script.src='https://www.baidu.com/sugrec?prod=pc&cb=getData&wd='+wd; /* 设置它的地址*/
   document.body.appendChild(script);   /*添加script元素到body中*/
}
function getData(data){  /*获取数据*/
     var script=document.querySelector('#jsonp'); /*选择id为jsonp的元素*/
     script.parentNode.removeChild(script);  /*从这个元素的父元素中删除这个元素*/
     $('ol').html('');  /* 设置有序列表的值为空*/
     var da=data.g;   /* 获取搜索的结果*/
  if(da){                     /*结果存在的话就将结果放到li标签中*/
   da.forEach(function(item,index){  
     $('<li><a target="_blank" href ="https://www.baidu.com/s?wd='+item.q+'">'+item.q+'</a></li>').appendTo('ol');
    })
    }
}


     /* 判断键盘是否按下*/
   $('input:text').keyup(function(){
      var wd=$(this).val();  /* 输入框的值*/
      if(wd==''){           /*如果值是空,那么就隐藏,否则显示*/
          $('ol').css('display','none');
          $('ol').css('zIndex',-10);  
      }else{
          $('ol').css('display','block');
       $('ol').css('zIndex',20);
      }
         getlist(wd);
  });
   </script>

可以看到,搜索结果已经出来了,而且有序列表下的"li"标签也都对应的生成了。

3).给选项标记序列

我们可以看到,结果终于出来,但是我想给它个序列号,这样就可以知道搜索结果有多少个了。要设置的标记方式有很多种,可以以数字开头,也可以是大小写字母或者罗马时间。在这里我选择数字,很简单。

终于非常完美的实现了这一功能,是不是很惊艳了,赶快去试下吧。

4).搜索刷新

看到这里相信大家应该都知道这个功能已经算是完成了,我们只需要随便点击哪个li标签都可以访问到相应的页面。于是,我决定添加一个刷新的功能,属于重连服务器的那种刷新:

<span onclick='window.location.reload()'>search</span> 点击后立即刷新

【三、项目总结】

总的来说,对于初学者小白是个很不错的练手项目,希望大家能从中有所收获。

需要源码的小伙伴,后台回复“搜索引擎”四个字即可获取。

****看完本文有收获?请转发分享给更多的人****

想学习更多Python网络爬虫与数据挖掘知识,可前往专业网站:http://pdcfighting.com/