Django筆記08-博客首頁(2)

博客首頁

博客首頁除了顯示數(shù)據(jù)之外,還有登陸跳轉(zhuǎn)、分頁顯示、搜索等

登陸

?django 內(nèi)置的后臺管理應(yīng)用就是處理注冊登陸、管理文章等的應(yīng)用。在fbckf/urls.py 中規(guī)定了匹配后臺應(yīng)用的 url規(guī)則 ,在瀏覽器中輸入127.0.0.1:8000/admin可進入登陸界面。

?點擊首頁中的 Sign in 按鈕將跳轉(zhuǎn)到登陸界面

模板

<!-- templates/blog/index.html -->
...
<!-- nav -->
<div class="container">
    <nav class="navbar navbar-light border-bottom" style="background-color: white">
        <span class="navbar-brand font-italic">
            Fbckf
        </span>
        <div class="my-2 my-lg-0">
            <!-- 將 button 標(biāo)簽修改為以下內(nèi)容 -->
          {% if username %}
          <a href="/admin" class="btn btn-light text-dark" role="button">{{ username }}</a>
          {% else %}
          <a href="/admin" class="btn btn-light" role="button">Sign in</a>
          {% endif %}
        </div>        
    </nav>
</div>
...

url 規(guī)則

# fbckf/urls.py
...
urlpatterns = [
    path('admin/', admin.site.urls),
    # 修改首頁 url 規(guī)則
    path('', include('blog.urls')),
]
...

?修改完成之后刷新頁面,點擊 Sign in 按鈕時成功跳轉(zhuǎn)到登陸頁面,在后臺點擊查看站點返回首頁。成功登陸之,如果沒有注銷登陸,瀏覽器會有緩存,之后訪問后臺都不用再次輸入賬戶密碼。

視圖函數(shù)

# blog/views.py

...
def index(request):
    ...
    # 判斷用戶是否登陸,若用戶已登陸在線則將用戶名存放到字典 context 中傳遞到模板
    if request.user.is_authenticated:
        context['username']= request.user.username
    return render(request, 'blog/index.html', context=context)
...

?刷新博客首頁,Sign in 按鈕已經(jīng)改為 fbckf,在將用戶注銷登陸,刷新博客首頁,按鈕有恢復(fù)為 Sign in

文章排序

?首頁的文章是按照發(fā)布時間來排序的,從最新到最舊的順序。而之前文章從數(shù)據(jù)庫中取出的順序是相反的,文章排序需要修改有一下視圖函數(shù)

# blog/views.py

...

def index(request):
    # 通過 order_by() 方法來給文章排序
    # order_by() 的參數(shù)是 指定排序的字段,字段前的'-'好表示逆序
    article_list = Article.objects.all().order_by('-create_time') 
...

?刷新是首頁,文章已正確排序。

分頁

?當(dāng)文章增加到一定數(shù)量的時候,就必須要用到分頁功能,將文章按一定數(shù)量分頁顯示。

測試數(shù)據(jù)

?現(xiàn)在的數(shù)據(jù)庫中,僅有兩篇文章,這是遠遠不夠的。分頁功能需較多的測試數(shù)據(jù),而一個一個的手動輸入文章及其麻煩,所以只能通過腳本來輸入,而且使用腳本的話,也可以保證在團隊中
測試數(shù)據(jù)的一致性

# populate.py
"""
數(shù)據(jù)腳本
"""
import os 
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'fbckf.settings')

import django
django.setup()

from blog.models import Category, Article
from django.contrib.auth.models import User
from django.utils import timezone


def run_script():
    author = User.objects.get(username='fbckf')
    category = Category.objects.get(name='古詩')
    article = add_article(
        title="望江南 超然臺作",
        author=author,
        category=category,
        body="春未老,風(fēng)細柳斜斜。試上超然臺上看,半壕春水一城花。煙雨暗千家。寒食后,酒醒卻咨嗟。休對故人思故國,且將新火試新茶。詩酒趁年華。",
    )
    article = add_article(
        title="寄黃幾復(fù)",
        author=author,
        category=category,
        body="我居北海君南海,寄雁傳書謝不能。桃李春風(fēng)一杯酒,江湖夜雨十年燈。持家但有四立壁,治病不蘄三折肱。想見讀書頭已白,隔溪猿哭瘴溪藤。",
    )
    article = add_article(
        title="俠客行",
        author=author,
        category=category,
        body="趙客縵胡纓,吳鉤霜雪明。銀鞍照白馬,颯沓如流星。十步殺一人,千里不留行。事了拂衣去,深藏身與名。閑過信陵飲,脫劍膝前橫。將炙啖朱亥,持觴勸侯嬴。三杯吐然諾,五岳倒為輕。眼花耳熱后,意氣素霓生。救趙揮金槌,邯鄲先震驚。千秋二壯士,烜赫大梁城??v死俠骨香,不慚世上英。誰能書閣下,白首太玄經(jīng)。",
    )
    article = add_article(
        title="畫堂春 一生一代一雙人",
        author=author,
        category=category,
        body="一生一代一雙人,爭教兩處銷魂。相思相望不相親,天為誰春。漿向藍橋易乞,藥成碧海難奔。若容相訪飲牛津,相對忘貧。",
    )
    article = add_article(
        title="丑奴兒 書博山道中壁",
        author=author,
        category=category,
        body="少年不識愁滋味,愛上層樓。愛上層樓。為賦新詞強說愁。 而今識盡愁滋味,欲說還休。欲說還休。卻道天涼好個秋。",
    )
    article = add_article(
        title="折桂令 春情",
        author=author,
        category=category,
        body="平生不會相思,才會相思,便害相思。身似浮云,心如飛絮,氣若游絲??找豢|余香在此,盼千金游子何之。證候來時,正是何時?燈半昏時,月半明時。",
    )
    article = add_article(
        title="鳳求凰",
        author=author,
        category=category,
        body="其一:【琴曲出自王實甫《西廂記》】有美一人兮,見之不忘。(有美人兮,見之不忘。)一日不見兮,思之如狂。鳳飛翱翔兮,四海求凰。無奈佳人兮,不在東墻。將琴代語兮,聊寫衷腸。何時見許兮,慰我彷徨。愿言配德兮,攜手相將。不得於飛兮,使我淪亡。",
    )
    article = add_article(
        title="子衿",
        author=author,
        category=category,
        body="青青子衿,悠悠我心??v我不往,子寧不嗣音?青青子佩,悠悠我思??v我不往,子寧不來?挑兮達兮,在城闕兮。一日不見,如三月兮。",
    )
    article = add_article(
        title="賀新郎 甚矣吾衰矣",
        author=author,
        category=category,
        body="邑中園亭,仆皆為賦此詞。一日,獨坐停云,水聲山色,競來相娛。意溪山欲援例者,遂作數(shù)語,庶幾仿佛淵明思親友之意云。甚矣吾衰矣。悵平生、交游零落,只今馀幾!白發(fā)空垂三千丈,一笑人間萬事。問何物、能令公喜?我見青山多嫵媚,料青山見我應(yīng)如是。情與貌,略相似。一尊搔首東窗里。想淵明《停云》詩就,此時風(fēng)味。江左沉酣求名者,豈識濁醪妙理?;厥捉?、云飛風(fēng)起。不恨古人吾不見,恨古人不見吾狂耳。知我者,二三子。",
    )

def add_category(name, instructions):
    """
    get_or_create() 獲取或創(chuàng)建一個對象 并返回一個元組
    """
    c = Category.objects.get_or_create(name=name)[0]
    c.instructions = instructions
    c.save()
    return c
    
def add_article(title, author, category, body):
    a = Article.objects.get_or_create(title=title)[0]
    a.author = author
    a.category = category
    a.body = body
    a.abstract = body[:17]
    a.create_time = timezone.now()
    a.likes = 0
    a.save()
    return a

if __name__ == "__main__":
    print("Blog populate script running ...")
    run_script()
# 運行腳本插入數(shù)據(jù)
$ python populate.py

?查看后臺文章列表

image

視圖函數(shù)

?django 提供了管理分頁的類 Paginator,可以快速的完成分頁功能呢改,在官方文檔中也有簡單的例子,在視圖函數(shù)中導(dǎo)入Paginator

# blog/views.py
from django.shortcuts import render
# 導(dǎo)入 Paginator 類
from django.core.paginator import Paginator
from django.contrib.auth.models import User
from .models import Category, Article

# 修改 index 函數(shù)
def index(request):
    # 創(chuàng)建字典 context
    context = {}

    article_list = Article.objects.all().order_by('-create_time')
    # 判斷文章數(shù)量是否需要分頁
    if article_list.count > 10:
        # 實例化一個 Paginator 類
        # 第一個參數(shù)是要進行分頁的文章列表,第二個參數(shù)表示每頁文章數(shù)量
        paginator = Paginator(article_list, 3)
        # 從 request 中獲取目標(biāo)頁面數(shù)
        page = request.GET.get('page')
        # 首次訪問頁面 page 為 None
        if page == None:
            page=1
        # 調(diào)用 page 方法獲取目標(biāo)頁面的文章列表
        page_list = paginator.page(page)
        context['article_list'] = page_list
        # 通過該變量判斷是否分頁
        context['is_page'] = True
    else:   
        context['article_list'] = article_list
        
    category_list = Category.objects.all()
    context['category_list'] = category_list

    for category in category_list:
        count = Article.objects.all().filter(category=category).count()
        category.article_count = count
        category.save()

    if request.user.is_authenticated:
        context['username']= request.user.username

    return render(request, 'blog/index.html', context=context)

?每次用戶點擊頁面導(dǎo)航欄中的頁碼后,通過 request.GET.get() 獲取頁碼 page,再獲取頁碼對應(yīng)的文章列表并傳遞給模板。

模板文件

<!-- templates/blog/index.html -->
...
{% if is_page %}
<!-- Pagination -->
<div class="justify-content-center">
    <nav aria-label="Page navigation">
        <ul class="pagination justify-content-center">
          <!-- 跳轉(zhuǎn)到第一頁 -->
          <li class="page-item">
            <a href="?page=1" class="page-link bg-light text-dark" aria-label="Previous">
              <span aria-hidden="true">&laquo;</span>
              <span class="sr-only">Previous</span>
            </a>
          </li>
        {% ifequal article_list.number article_list.paginator.num_pages %}
          <li class="page-item"><a href="?page={{ article_list.number|add:-2 }}" class="page-link bg-light text-dark">{{ article_list.number|add:-2 }}</a></li>
        {% endifequal %}

        {% ifnotequal article_list.number|add:-1 0 %}
          <li class="page-item"><a href="?page={{ article_list.number|add:-1 }}" class="page-link bg-light text-dark">{{ article_list.number|add:-1 }}</a></li>
        {% endifnotequal %}
          <!-- 當(dāng)前頁 -->
          <li class="page-item disabled"><a href="?page={{ article_list.number }}" class="page-link bg-dark text-light">{{ article_list.number}}</a></li>

        {% ifnotequal article_list.number article_list.paginator.num_pages %}
          <li class="page-item"><a href="?page={{ article_list.number|add:1 }}" class="page-link bg-light text-dark">{{ article_list.number|add:1 }}</a></li>
        {% endifnotequal %}

        {% ifequal article_list.number|add:-1 0 %}
          <li class="page-item"><a href="?page={{ article_list.number|add:2 }}" class="page-link bg-light text-dark">{{ article_list.number|add:2 }}</a></li>
        {% endifequal %}
          <!-- 跳轉(zhuǎn)到最后一頁 -->
          <li class="page-item">
            <a href="?page={{ article_list.paginator.num_pages}}" class="page-link bg-light text-dark" aria-label="Next">
              <span aria-hidden="true">&raquo;</span>
              <span class="sr-only">Next</span>
            </a>
          </li>
        </ul>
    </nav>
</div>
{% endif %}
...

?找到模板中的分頁導(dǎo)航部分,即 `` 后面部分。

  • 首先修改 href 屬性,?page=1 表示通過 GET 方法向后臺提交數(shù)據(jù) page=1,通過這個方式向后臺傳遞目標(biāo)頁碼

  • {% ifnotequal %}{% ifequal %} 標(biāo)簽分別判斷兩個值是否相等,當(dāng)變量 a 不等于 變量 b{% ifnotequal a b %} 會執(zhí)行包含在標(biāo)簽內(nèi)的代碼,而 {% ifequal a b %} 標(biāo)簽則相反

  • {{ article_list.number|add:1 }} 返回的結(jié)果是變量 article_list.number 加上 1 的值

?再次刷新頁面,分頁功能已經(jīng)完成。

搜索

?用戶可以根據(jù)關(guān)鍵字所搜文章,關(guān)鍵字在文章內(nèi)容和標(biāo)題中匹配

模板文件

?需要修首頁中的搜索表單以及錯誤信息顯示

<!-- templates/blog/index.html -->
...
<div class="sidebar-module">
    <div class="input-group mb-3 content">
        <div class="input-group-prepend">
            <span class="input-group-text" id="basic-addon1">
                <i class="fa fa-search" aria-hidden="true"></i>
            </span>
        </div>
        <form action="{% url 'blog:search' %}" method="post">
        {% csrf_token %}
            <input name="query" type="text" class="form-control" placeholder="Search" aria-label="Search" aria-describedby="basic-addon1">
        </form>
    </div>
</div>
...

?在模板文件中找到搜索表單,并按照以上代碼修改。

  • {% url 'blog:search' %} 就是 127.0.0.1:8000/search的的意思,調(diào)用命名為 'blog' 的 urls.py 模塊下名稱為 'search'的 url 規(guī)則。

  • {% csrf_token %} 標(biāo)簽會被替換成一個隱藏的 <input> 標(biāo)簽 ,該標(biāo)簽會在上傳搜索關(guān)鍵字的時候,上傳一個名字為 csrfmiddlewaretoken 的變量,這個是 django 用以保護網(wǎng)站不受黑客 csrf 攻擊的一種機制。

<!-- templates/blog/index.html -->
...
{% for article in article_list %}
<div class="jumbotron bg-light">
    <h1 class="display-4">{{ article.title }}</h1>
    <p class="lead">{{ article.abstract }}</p>
    <hr class="my-4">
    <p class="text-muted">{{ article.create_time }} , by  {{ article.author }}</p>
    <a href="#" class="btn btn-dark btn-lg" role="button">Read more</a> 
</div>
{% empty %}
    <!-- 判斷是否有錯誤信息 -->
    {% if error_msg %}
    <div class="jumbotron bg-light">
        <p class="lead">{{ error_msg }}</p>
    </div>
    {% else %}      
    <div class="jumbotron bg-light">
        <p class="lead">暫無文章,敬請期待!</p>
    </div>
    {% endif %}
{% endfor %}
...

添加視圖函數(shù)

# blog/views.p
from django.db.models import Q
...
def search(request):
    context = {}
    # 從 request 請求中獲取關(guān)鍵字
    q = request.POST.get('query')
    # 判斷關(guān)鍵字是否存空 
    # 是則返回錯誤信息
    if q is None or q=="":
        error_msg = "請輸入關(guān)鍵詞!"
        return render(request, 'blog/index.html', {'error_msg': error_msg})
    # Q 用于包裝查詢表達式,提供復(fù)雜的查詢邏輯
    # 用 filter 過濾出含有關(guān)鍵字的文章
    # | 表示或
    article_list = Article.objects.all().filter(Q(title__icontains=q) | Q(body__icontains=q))
    context['article_list'] = article_list

    category_list = Category.objects.all()
    context['category_list'] = category_list

    if request.user.is_authenticated:
        context['username']= request.user.username
    return render(request, 'blog/index.html', context=context)
...

添加 url 規(guī)則

from django.urls import path
from . import views

app_name = 'blog'
urlpatterns = [
    path('', views.index, name='index'),
    # 將規(guī)則命名為 search 之后就可以通過 {% url 'blog:search' %} 使用
    path('search/', views.search , name='search'),
]

? 搜索功能完成后,就可以在搜索表單中輸入關(guān)鍵字來查詢想要的文章。當(dāng)然,這個搜索功能還很簡單,沒有關(guān)鍵字高亮,而且當(dāng)文章一多的時候,效率就會大大下降,假如要解決這個問題,就需要建立數(shù)據(jù)庫索引,這個這里不多說。

?而想要通過其他字段來查詢文章的話,也差不多如此,比如查詢作者,先使用關(guān)鍵字查詢并實例化相應(yīng)的作者,在通過該對象查詢文章并返回即可。

總結(jié)

?首頁的功能到這里就大致完成了,接下來就是完成文章詳情頁。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1、通過CocoaPods安裝項目名稱項目信息 AFNetworking網(wǎng)絡(luò)請求組件 FMDB本地數(shù)據(jù)庫組件 SD...
    陽明AI閱讀 16,172評論 3 119
  • 點我查看本文集的說明及目錄。 本項目相關(guān)內(nèi)容( github傳送 )包括: 實現(xiàn)過程: CH1 創(chuàng)建一個博客應(yīng)用 ...
    學(xué)以致用123閱讀 4,642評論 0 31
  • 在家中 某刻,父愛泛濫。 女:媽媽,爸爸在摸我的手。 妻:老公,女孩的手你怎么敢隨便摸?! 父:(無語凝噎)。。。
    勇者先行閱讀 1,244評論 0 1
  • 1.早起 今早5點半醒來,貪睡又躺下。自7點20分鬧鐘響起,一直到7:50起床。中間拖延30分鐘。 2.靜坐 睡前...
    _我手寫我心_閱讀 192評論 0 0
  • 解夢的目的,是為了更好地了解自己。這篇文章是我學(xué)習(xí)弗洛伊德《夢的解析》的一個階段性實踐筆記。我相信它能給你啟發(fā),讓...
    江欲行閱讀 16,499評論 17 60

友情鏈接更多精彩內(nèi)容