欲しい記事をすぐに見つけたいというのはユーザー共通のニーズであり、記事検索もブログには必要な機能です。
ビューの変更
検索機能を実装するために、article_list
ビューに関数を追加していきます。
ここでクエリを実行するときの一般的な要件は、特定の文字列を入力し、それをタイトルと記事のコンテンツで照合することです。
現時点では、Django で Q オブジェクトを使用する必要があります。
クエリ条件で条件を組み合わせる必要がある場合 (2 つの条件「and」または「or」など)。Q() を使用してオブジェクトをクエリできます。
& または | 記号を使用して複数の Q() オブジェクトを結合し、それらを filter()、exclude()、get() およびその他の関数に渡すことができます。複数の Q() オブジェクトが結合されると、Django は新しい Q() を自動的に生成します。たとえば、次のコードは 2 つの条件を 1 つに結合します。
Q(question__startswith='Who') | Q(question__startswith='What')
上記のコードの使用は、SQL ステートメントを使用して理解できます。
WHEREquestionLIKE 'Who%' ORquestionLIKE 'What%'
それからarticle_list()
それを変換します
def article_list(request):
# 根据GET请求中查询条件
# 返回不同排序的对象数组
search = request.GET.get('search')
order = request.GET.get('order')
# 用户搜索逻辑
if search:
if order == 'total_views':
# 用 Q对象 进行联合搜索
article_list = Article.objects.filter(
Q(title__icontains=search) |
Q(body__icontains=search)
).order_by('-total_views')
else:
article_list = Article.objects.filter(
Q(title__icontains=search) |
Q(body__icontains=search)
)
else:
# 将 search 参数重置为空
search = ''
if order == 'total_views':
article_list = Article.objects.all().order_by('-total_views')
else:
article_list = Article.objects.all()
paginator = Paginator(article_list, 2)
page = request.GET.get('page')
articles = paginator.get_page(page)
# 修改此行
context = {'articles': articles, 'order': order, 'search': search }
return render(request, 'article/list.html', context)
主な改訂内容は以下のとおりです。
- 検索するテキストを保存するための新しいパラメーター検索が追加されました。検索が空でない場合は、特定の記事オブジェクトを取得します。
- Q(title__icontains=search) は、モデルのタイトル フィールドでクエリを実行することを意味します。icontains は大文字と小文字が区別されず、2 つのアンダースコアで区切られます。search はクエリするテキストです。結合クエリの目的を達成するために、複数の Q オブジェクトはパイプ文字 | で区切られます。
テンプレートの変更
次に、リスト テンプレートを変更します。変更するコードはたくさんあります。実際、機能はあまり変更されていません。list.html を直接貼り付けた完全なコードは次のとおりです。
templates/article/list.html
<!-- extends表明此页面继承自 base.html 文件 -->
{% extends "base.html" %}
{% load static %}
<!-- 写入 base.html 中定义的 title -->
{% block title %}
首页
{% endblock title %}
<!-- 写入 base.html 中定义的 content -->
{% block content %}
{#<div class="row">#}
<!-- 定义放置文章标题的div容器 -->
<br>
<div class="container">
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item">
<a href="{% url 'list' %}?search={
{ search }}">
最新
</a>
</li>
<li class="breadcrumb-item">
<a href="{% url 'list' %}?order=total_views&search={
{ search }}">
最热
</a>
</li>
</ol>
</nav>
<!-- 新增,搜索栏 -->
<div class="row">
<div class="col-auto mr-auto">
<form class="form-inline" >
{# <label class="sr-only">content</label>#}
<input type="text"
class="form-control mb-2 mr-sm-2"
name="search"
placeholder="搜索文章..."
required
>
</form>
</div>
</div>
<!-- 新增,搜索提示语 -->
{% if search %}
{% if articles %}
<h4><span style="color: red">"{
{ search }}"</span>的搜索结果如下:</h4>
<hr>
{% else %}
<h4>暂无<span style="color: red">"{
{ search }}"</span>有关的文章。</h4>
<hr>
{% endif %}
{% endif %}
{% for article in articles %}
<div class="row mt-2">
<!-- 文章内容 -->
<div class="col-sm-12">
<!-- 卡片容器 -->
<div class="card h-100">
<!-- 标题 -->
<!-- <h4 class="card-header">{
{ article.title }}</h4>-->
<!-- 摘要 -->
<div class="card-body">
<h4 class="card-title">{
{ article.title }}</h4>
<br>
<p class="card-text">{
{ article.body|slice:'100' }}...</p>
<a href="{% url 'detail' article.id %}" class="card-link">阅读本文</a>
<!-- 这里增加阅读量和图标 -->
<small class="col align-self-end" style="color: gray;">
<span class="bi bi-eye">
{
{ article.total_views }}
</span>
</small>
</div>
</div>
</div>
</div>
{% endfor %}
<br>
<!-- 页码导航 -->
<div class="pagination row">
<div class="m-auto">
<span class="step-links">
<!-- 如果不是第一页,则显示上翻按钮 -->
{% if articles.has_previous %}
<a href="?page=1&order={
{ order }}&search={
{ search }}" class="btn btn-success">
« 1
</a>
<span>...</span>
<a href="?page={
{ articles.previous_page_number }}&order={
{ order }}&search={
{ search }}"
class="btn btn-secondary"
>
{
{ articles.previous_page_number }}
</a>
{% endif %}
<!-- 当前页面 -->
<span class="current btn btn-danger btn-lg">
{
{ articles.number }}
</span>
<!-- 如果不是最末页,则显示下翻按钮 -->
{% if articles.has_next %}
<a href="?page={
{ articles.next_page_number }}&order={
{ order }}&search={
{ search }}"
class="btn btn-secondary">{
{ articles.next_page_number }}</a>
<span>...</span>
<a href="?page={
{ articles.paginator.num_pages }}&order={
{ order }}&search={
{ search }}"
class="btn btn-success">{
{ articles.paginator.num_pages }} »</a>
{% endif %}
</span>
</div>
</div>
</div>
{#</div>#}
{% endblock content %}
主な変更点は次のとおりです。
- ブレッドクラム コンポーネントとページ番号コンポーネントの両方が変更されました。 href: 検索パラメータが追加されました。
- GET リクエストで検索パラメータを送信するための新しい検索バーを追加します。必須属性により、ユーザーは空白のテキストを送信できなくなります
- 検索プロンプトを追加しました。優れた UI はユーザーに現状を理解させる必要があります
完了後のテスト結果は次のとおりです。
結論
この記事の時点で、ブログ投稿、コメント、ユーザー管理の中核機能は完成しており、また、単純な並べ替えや検索など、必要な小さな機能モジュールも実装されています。
この一連のブログ投稿のコア モジュールは終了します。次の記事では、最後の課題である展開と起動を完了します。