Django搭建博客(五):爲博客添加後臺管理功能

上一篇我們還留了一個小問題沒有解決,其實這個問題我是特意留到這一篇來講的,請往下看 ⇩

現在我們的博客已經具備了基本的頁面,但是如果我想發表一篇新的文章的話,還得到數據庫裏手動添加。

而且如果我們想修改一篇文章的話也很麻煩,這時候一個後臺管理界面就很有用了。

一、需求分析

在添加後臺管理界面之前,讓我們想一想需要一些什麼功能:

  • 能夠添加文章
  • 能夠修改文章
  • 能夠刪除文章

還有一些功能,比如在線編輯、實時預覽、markdown支持我們以後再添加。

現在我們已經把功能列出來了,接下來就是分析一下需要什麼頁面:

  • 查看所有文章的頁面,在這個頁面裏應該有修改和刪除文章的選項,還要有添加新文章的選項
  • 點擊修改文章應該出現編輯頁面
  • 點擊刪除文章應該出現確認頁面
  • 點擊添加文章應該出現文章編輯頁面,這個和修改文章的頁面應該是相同的

然後在修改、添加、刪除文章後應該返回文章列表。

二、顯示文章頁面

確定下來頁面我們就可以開始敲代碼了,按照頁面之間的邏輯關係,我們先完成顯示文章列表的頁面。

這個頁面和我們的首頁很相似,我們只需要添加幾個按鈕即可:

{% extends 'myblog/base.html' %}

{% block title %}Post List{% endblock %}

{% block main %}

<ul class="list-unstyled">
{% for post in pagedata.post_list %}
<li>
    <div class="row">
        <div class="col-lg-10">
            <h1><a href="{{post.get_absolute_url}}">{{post.title}}</a></h1>
            <span class="d-block">{{post.tags}}</span>
            <span class="d-block">{{post.get_format_date}}</span>
            <p>{{post.get_brief_content}}</p>
        </div>
        <div class="col-lg-2">
            <div class="row">
                <div class="col"><a href="#">修改</a></div>
            </div>
            <div class="row">
                <div class="col"><a href="#">刪除</a></div>
            </div>
        </div>
    </div>
</li>
{% endfor %}
 </ul>

{% endblock %}

再把鏈接和視圖添加上去,運行一下看看效果:

三、添加文章功能

添加一個新建文章的按鈕:

現在按鈕的位置都添加好了,我們分別爲每個按鈕添加鏈接,首先是添加文章的按鈕,這個鏈接是一個固定的值,我們可以直接寫到頁面中去(當然,等以後頁面多了肯定不能這麼寫,不過現在只有幾個頁面,所以問題不大)。

<div class="add-article">
    <a class="text-success" href="/myblog/addArticle">添加文章</a>
</div>

然後再創建一個視圖和模板,再添加鏈接:

修改 urls.py文件:

# myblog/urls.py
from django.urls import re_path
from . import views


urlpatterns = [
    re_path(r'^index/{0,1}$', views.index),
    re_path(r'^article/\d{4,4}/\d{1,2}/(?P<title>.+)/{0,1}$', views.article),
    re_path(r'^articles/list/{0,1}$', views.article_list),
    
    re_path(r'^addArticle/{0,1}$', views.addArticle),
]

創建一個模板文件 add_article.html:

{% extends 'myblog/base.html' %}

{% block title %}Add Article{% endblock %}

{% block main %}

<div class="row">
    <div class="col">
        <form action="/myblog/addArticle" method="post">
            {% csrf_token %}
            <div class="row my-3">
                <div class="col">
                    <label for="title">標題</label>
                    <input type="text" name="title" id="title">
                </div>
            </div>
            <div class="row my-3">
                <div class="col">
                    <label for="tags">標籤</label>
                    <input type="text" name="tags" id="tags">
                </div>
            </div>
            <div class="row my-3">
                <div class="col">
                    <label for="content">正文</label>
                    <textarea class="d-block" type="text" name="content" id="content"></textarea>
                </div>
            </div>
            <div class="row my-3">
                <div class="col">
                    <button type="submit">提交</button>
                </div>
            </div>
        </form>
    </div>
</div>

{% endblock %}

再添加一個視圖函數 addArticle:

def addArticle(request):
    if request.method == 'GET':
        return render(request, 'myblog/add_article.html')
    elif request.method == 'POST':
        title = request.POST['title']
        key = abs(hash(title))
        tags = request.POST['tags']
        content = request.POST['content']
        date = datetime.datetime.now().strftime('%Y-%m-%d')

        Post(key=key, title=title, tags=tags, content=content, date=date).save()

        return HttpResponseRedirect('/myblog/articles/list/')

當請求方式爲 get請求時,addArticle函數會返回 add_article頁面:

當請求方式爲 post時,也就是點擊提交後,addArticle函數會接收頁面提交的數據,並將其保存到數據庫中,然後重定向到 article_list頁面查看添加結果。

注意到在保存到數據庫時多了一個 key參數。

這就是我們用來替換 title用來查找文章的值,key是由 title經過哈希運算得到的值,我們可以認爲 key和 title是一一對應的。

這樣文章鏈接就可以根據 key來生成。

要應用這個變化,我們還需要修改一些文件:

首先修改文章的鏈接:

re_path(r'^article/\d{4,4}/\d{1,2}/(?P<key>\d+)/{0,1}$', views.article),

然後修改 Post類的 get_absolute_url方法:

def get_absolute_url(self):
    return f'/myblog/article/{self.date.year}/{self.date.month}/{self.key}'

注意:

這裏鏈接以 ” / “開頭說明該鏈接是相對於網站根目錄的鏈接,即最終的鏈接是:

http://127.0.0.1:8000/myblog/article/2018/8/1/45555555544

如果不以 ” /“開頭則說明該鏈接是相對於當前頁面的鏈接,假設當前頁面是

http://127.0.0.1:8000/myblog/index

那麼最終的鏈接是: http://127.0.0.1:8000/myblog/myblog/article/2018/8/1/45555555544

可以看到,myblog重複了兩次,由於當前頁面的不確定性,所以我們在所有的頁面裏都使用帶反斜槓的鏈接。

改了上面兩處還不夠,我們還需要改一下 article視圖函數,其實就是將 title改爲了 key:

def article(request, key):
    post = Post.objects.filter(key=key).get()
    return render(
        request,
        'myblog/article.html',
        {'pagedata':
             {'post': post}
        }
    )

接下來訪問一下文章詳情頁面 :

這樣我們就把添加文章的功能給做好了,接下來我們再來完成修改文章的功能。

四、修改文章功能

首先我們先添加一個鏈接:

re_path(r'^modifyArticle/{0,1}$', views.modifyArticle)

再修改 articles_list.html模板文件,爲每篇文章添加對應的修改鏈接:

<div class="row">
    <div class="col text-info">
        <a href="{{post.get_modify_url}}">修改</a>
    </div>
</div>

再給 Post類添加 get_modify_url方法:

    def get_modify_url(self):
        return f'/modifyArticle/{self.key}'

做完這些我們還需要添加一個 modify_article模板:

{% extends 'myblog/base.html' %}

{% block title %}Modify Article{% endblock %}

{% block main %}

<div class="row">
    <div class="col">
        <form action="{{pagedata.post.get_modify_url}}" method="post">
            {% csrf_token %}
            <div class="row my-3">
                <div class="col">
                    <label for="title">標題</label>
                    <input type="text" name="title" id="title" value="{{pagedata.post.title}}">
                </div>
            </div>
            <div class="row my-3">
                <div class="col">
                    <label for="tags">標籤</label>
                    <input type="text" name="tags" id="tags" value="{{pagedata.post.tags}}">
                </div>
            </div>
            <div class="row my-3">
                <div class="col">
                    <label for="content">正文</label>
                    <textarea class="d-block" type="text" name="content" id="content">{{pagedata.post.content}}</textarea>
                </div>
            </div>
            <input type="hidden" name="key" value="{{pagedata.post.key}}">
            <div class="row my-3">
                <div class="col">
                    <button type="submit">提交</button>
                </div>
            </div>
        </form>
    </div>
</div>

{% endblock %}

這個模板和 add_article模板基本一致,我們只做了一些小的改動。

我們爲每個 input標籤添加了一個 value,value的值就是文章對應屬性的值。

最後我們還需要添加一個視圖函數 modifyArticle來處理請求:

def modifyArticle(request, key):
    if request.method == 'GET':
        post_list = Post.objects.filter(key=key)
        if len(post_list) == 0:
            return HttpResponse('文章不存在')
        else:
            return render(
                request,
                'myblog/modify_article.html',
                {'pagedata':
                     {'post':post_list[0]}
                }
            )
    elif request.method == 'POST':
        title = request.POST['title']
        key = request.POST['key']
        tags = request.POST['tags']
        content = request.POST['content']
        date = datetime.datetime.now().strftime('%Y-%m-%d')

        post = Post.objects.filter(key=key)[0]
        post.title = title
        post.tags = tags
        post.content = content
        post.date = date

        post.save()

        return HttpResponseRedirect('/myblog/articles/list/')

我們來測試一下:

現在只剩下刪除功能沒有做了,刪除功能其實很簡單,只需要添加一個確認頁面,然後在數據庫裏執行刪除操作即可,這些我就不再多寫了。

最後看看整體效果:

不過我們得後臺管理還有很多問題,比如:沒有進行身份驗證。 在下一篇我們會爲博客添加身份認證機制

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章