Python + Django4で個人ブログを構築する(19):記事を検索

欲しい記事をすぐに見つけたいというのはユーザー共通のニーズであり、記事検索もブログには必要な機能です。

ビューの変更

検索機能を実装するために、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">
                    &laquo; 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 }} &raquo;</a>
            {% endif %}
        </span>
    </div>
</div>
</div>
{#</div>#}

{% endblock content %}

主な変更点は次のとおりです。

  • ブレッドクラム コンポーネントとページ番号コンポーネントの両方が変更されました。 href: 検索パラメータが追加されました。
  • GET リクエストで検索パラメータを送信するための新しい検索バーを追加します。必須属性により、ユーザーは空白のテキストを送信できなくなります
  • 検索プロンプトを追加しました。優れた UI はユーザーに現状を理解させる必要があります

完了後のテスト結果は次のとおりです。

結論

この記事の時点で、ブログ投稿、コメント、ユーザー管理の中核機能は完成しており、また、単純な並べ替えや検索など、必要な小さな機能モジュールも実装されています。

この一連のブログ投稿のコア モジュールは終了します。次の記事では、最後の課題である展開と起動を完了します。

おすすめ

転載: blog.csdn.net/agelee/article/details/127786796