Django 完成一個簡單的搜索功能
搜索是一個複雜的功能,但對於一些簡單的搜索任務,我們可以使用 django model 層提供的一些內置方法來完成。本文將結合 django 模型管理器的 filter 方法和 icontains 查詢表達式來實現一個簡單的搜索功能。
以博客為例,博客文章通常包含標題和正文兩個部分。當用戶輸入某個關鍵詞進行搜索後,我們希望為用戶顯示標題中含有被搜索關鍵詞的全部文章。整個搜索的過程如下:
用戶在搜素框中輸入搜索關鍵詞,假設為 「django」,然後用戶點擊了搜索按鈕提交其輸入的結果到伺服器
伺服器接收到用戶輸入的搜索關鍵詞 「django」 後去資料庫查找文章標題中含有該關鍵詞的全部文章
伺服器將查詢結果返回給用戶
整個過程就是這樣,下面來看看 django 如何用實現這些過程。
假設我們的 django 博客應用有如下的文章模型:
blog/models.pyclass Post(models.Model): # 標題 title = models.CharField(max_length=70) # 正文 body = models.TextField() # 其他屬性 def __str__(self): return self.title
先看到第 1 步,用戶在搜索框輸入搜索關鍵詞,因此我們要在博客上為用戶提供一個搜索表單,html 表單代碼大概像這樣:
{% csrf_token %} 搜索
特別注意在 form 標籤下有一個 {% csrf_token %},這是 django 用來防禦跨站請求偽造(CSRF)攻擊的機制。如果不知道什麼是 CSRF 的話也沒有關係,只要記住在使用 django 時,前端的表單代碼里一定要加上 {% csrf_token %} 。
用戶輸入了搜索關鍵詞並點擊了搜索按鈕後,數據就被發送給了 django 後台伺服器。表單的 action 屬性的值為 /search/,表明用戶提交的結果將被發送給 /search/ 這個 URL。我們為這個 URL 綁定一個 django 視圖函數,在這個視圖函數里完成前面第 2 步提到的過程。假設我們把視圖函數的代碼寫在 blog/views.py 里:
blog/views.pydef search(request): q = request.GET.get("q") error_msg = "" if not q: error_msg = "請輸入關鍵詞" return render(request, "blog/errors.html", {"error_msg": error_msg}) post_list = Post.objects.filter(title__icontains=q) return render(request, "blog/results.html", {"error_msg": error_msg, "post_list": post_list})
首先我們使用 request.GET.get("q") 獲取到用戶提交的搜索關鍵詞。用戶通過表單提交的數據 django 為我們保存在 request.GET 里,這是一個類似於 Python 字典的對象,所以我們使用 get 方法從字典里取出鍵 q 對應的值,即用戶的搜索關鍵詞。這裡字典的鍵之所以叫 q 是因為我們的表單中搜索框 input 的 name 屬性的值是 q,如果修改了 name 屬性的值,那麼這個鍵的名稱也要相應修改。
接下來我們做了一個小小的校驗,如果用戶沒有輸入搜索關鍵詞而提交了表單,我們就無需執行查詢,而是渲染一個錯誤頁面提示用戶請輸入關鍵詞。如果用戶輸入了搜索關鍵詞,我們就通過 filter 方法從資料庫里過濾出符合條件的所有文章。這裡的過濾條件是 title__icontains=q,即 title 中包含(contains)關鍵字 q,前綴 i 表示不區分大小寫。這裡 icontains 是查詢表達式(Field lookups),其用法是在模型需要篩選的屬性後面跟上兩個下劃線。django 內置了很多查詢表達式,建議過一遍 django 官方留個印象,了解每個表達式的作用,以後碰到相關的需求就可以快速定位到文檔查詢其用途:Field lookups
接下來就是渲染搜索結果頁面,顯示符合搜索條件的文章列表,下面是一個模板的簡單示例:
results.html {% if error_msg %}
{{ error_msg }}
{% endif %} {% for post in post_list %}
在這裡顯示文章的相應信息
{% empty %}
沒有搜索到符合條件的文章
{% endfor %}
有了視圖函數後記得把視圖函數映射到相應了 URL,前面我們表單數據提交的 URL 為 /search/,因此將視圖函數 search 綁定到該 URL 上。
blog/urls.pyurlpatterns = [ # 其他 url 配置 url(r"^search/$", views.search, name="search"),]
大功告成!
以上示例寫的比較通用,並不是針對某個具體項目。但如果你稍微了解一點 django 的話,肯定能夠看懂文章的內容,並且稍作修改就能應用於自己的項目。如果你對 django 還不是很了解,這裡有一篇從零開始學習 django 的入門指南,能夠幫助你找到高質量的學習教程,以最快的速度入門 django 開發:django 入門學習規劃與資料推薦。
也許你前面已經學習了 django 博客開發入門教程,針對這個教程里的具體項目,我們修改上述代碼的一些細節,就可以在項目里順利運行。
首先是修改表單,打開 templates/base.html,在 header 標籤里找到搜索表單部分的代碼並修改,即添加 {% csrf_token %} 模板標籤、修改搜索框的 name 屬性和表單的 action 屬性:
templates/base.html ...
... {% csrf_token %} ...
然後是編寫視圖函數:
blog/views.pydef search(request): q = request.GET.get("q") error_msg = "" if not q: error_msg = "請輸入關鍵詞" return render(request, "blog/index.html", {"error_msg": error_msg}) post_list = Post.objects.filter(title__icontains=q) return render(request, "blog/index.html", {"error_msg": error_msg, "post_list": post_list})
這裡我們直接渲染了 index.html 頁面,因為這個頁面就是用來顯示文章列表的。我們對 index.html 稍作一點修改,讓它能夠顯示 error_msg。
templates/blog/index.html {% extends "base.html" %} {% block main %} {% if error_msg %}
{{ error_msg }}
{% endif %} {% for post in post_list %} ... {% empty %}
暫時還沒有發布的文章!
{% endfor %} {% endblock main %}
最後就是配置 URL:
blog/urls.pyurlpatterns = [ # 其他 url 配置 url(r"^search/$", views.search, name="search"),]
當然這樣的搜索功能是非常簡略的,難以滿足一些複雜的搜索需求。編寫一個搜索引擎是一個大工程,好在 django-haystack 這款第三方 app 為我們完成了全部工作。使用它我們可以實現更加複雜的搜索功能,比如全文檢索、按搜索相關度排序、關鍵字高亮等等類似於百度搜索的功能,功能十分強大。
![](https://pic.pimg.tw/zzuyanan/1488615166-1259157397.png)
![](https://pic.pimg.tw/zzuyanan/1482887990-2595557020.jpg)
TAG:圓圈 |