django1.10開發部落格(7)——文章的新增、釋出、編輯、刪除

weixin_34124651發表於2016-12-28

前幾節我們實現了在admin介面對部落格文章進行新增、釋出、編輯和刪除,但是每次我們都要進入admin才能進行這些操作實在太麻煩,而且admin介面也難以定製和美化。這一節我們要實現在正常部落格介面進行這些操作。

django可以定製一個表單,並建立一個ModelForm來將表單結果儲存為一個模型。我們可以建立一個ModelForm來將表單轉換為一個Article模型。語言說明太難懂了,邊做邊理解吧!

定製表單


mysite\blog裡面建立forms.py,PyCharm裡面看現在的工程結構應該是:


4176027-c7858febfd0c07fd.JPG
17.jpg

在forms.py裡面寫下:

from django import forms
from .models import Article

class ArticleForm(forms.ModelForm):
    class Meta:
        model = Article
        fields = ('title', 'text', 'category')

ArticleForm需要繼承自forms.ModelForm,這樣django就能實現某些神奇的效果。 在裡面我們定義了元類Meta,然後指定model為Article,還有欄位為title、text和category。 因為我們只需要對外暴露標題、內容和標籤分類,至於作者就是登陸使用者了,而釋出日期和建立日期就是提交時間。

更多django 表單的學習:Working with forms

文章新增


在base.html的<head>...</head>內增加兩條CSS,注意他們的位置:

<head>
    <meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
    <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
    <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.4/css/bootstrap.min.css">
    <link rel="stylesheet" href="{% static 'css/blog.css' %}">
    <title>Django Simple Blog</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="This is a simple django blog!">
    <title>Simple Django Blog</title>
    <link rel="shortcut icon" href="{% static 'img/favicon.ico' %}">
</head>

然後page-header的div做如下修改:

<div class="page-header">
    <div class="row">
        <div style="float: left" > <h1><a href="/">Django Simple Blog</a></h1></div>
        <div style="float: right">
            <ul class="nav nav-pills">
                <li class="active"><a href="{% url 'post_new' %}"><span class="glyphicon glyphicon-pencil"></span> 新建</a></li>
            </ul>
        </div>
    </div>
</div>

也就是用style將標題和按鈕設定為浮動,標題靠左,按鈕靠右,這樣標題和按鈕就會在同一行的兩側,更美觀。新建按鈕使用了bootstrap字型圖示,使用方法可以參考:Bootstrap按鈕圖示

新建按鈕指向了名為post_new的url,因此在mysite\mysite\urls.py中增加一條url:

url(r'^post/new/$', views.post_new, name='post_new'),

views.post_new檢視無效,那就去views.py裡面新增post_new:

from .forms import ArticleForm
from django.shortcuts import redirect

def post_new(request):
    if request.method == "POST":
        form = ArticleForm(request.POST)
        if form.is_valid():
            post = form.save(commit=False)
            post.author = request.user
            post.save()
            return redirect('post_detail', pk=post.pk)
    else:
        form = ArticleForm()
    return render(request, 'blog/post_edit.html', {'form': form})

在mysite\templates\blog下建立post_edit.html:

{% extends 'blog/base.html' %}
{% block content %}
    <h3>New post</h3>
    <form method="POST" class="post-form">{% csrf_token %}
        {{ form.as_p }}
        <button type="submit" class="save btn btn-default">Save</button>
    </form>
{% endblock %}

把檢視和模板接合起來理解,post_new檢視先按照ArticleForm(else部分)和post_edit.html組成編輯頁面,使用者寫完文章後點選submit按鈕POST提交,再次回到post_new檢視(if部分),儲存文章,轉到post_detail檢視,也就是顯示當前寫好的文章詳情頁面。

重新整理頁面按照上面的操作,新建:


4176027-caab9f7d184dee1b.JPG
19.jpg

儲存:


4176027-cdfa74e530094137.JPG
20.jpg

成功!

還可以在blog.css裡調整導航欄高度、標題大小、標題和按鍵與兩側、上下的距離等,請自行探索。。。

草稿箱


回到主頁面,發現並沒有我們剛剛新建的文章,但是admin頁面裡面有。在admin頁面中,我們可以看到新建的文章只有Created date而沒有Publish date,也就是說這篇文章還沒有正式釋出,而主頁面只會顯示有釋出時間即已釋出的文章(看檢視post_list)。要想看到沒有已建立但未釋出的文章,我們還需要一個草稿箱功能。

首先新增一個連結。就像剛才的新增文章按鈕一樣,在base.html的page-header內新增一個草稿箱按鈕,按鈕區就變成了這樣:

<div style="float: right">
    <ul class="nav nav-pills">
        <li class="active"><a href="{% url 'post_new' %}"><span class="glyphicon glyphicon-pencil"></span> 新建</a></li>
        <li class="active"><a href="{% url 'post_draft_list' %}"><span class="glyphicon glyphicon-th-list"></span> 草稿箱</a></li>
    </ul>
</div>

接著在mysite\mysite\urls.py增加一條url:

url(r'^drafts/$', views.post_draft_list, name='post_draft_list'),

然後在mysite\blog\views.py新增一個檢視,這個檢視和post_list檢視只有一個是否有釋出時間的不同:

def post_draft_list(request):
    posts = Article.objects.filter(published_date__isnull=True).order_by('-created_date')
    return render(request, 'blog/post_draft_list.html', {'posts': posts})

最後在mysite\templates\blog下新建一個post_draft_list.html模板,和post_list.html也很像:

{% extends 'blog/base.html' %}
{% block content %}
    {% for post in posts %}
        <div class="post">
            <p class="date">created: {{ post.created_date|date:'m d, Y' }}</p>
            <h2><a href="{% url 'post_detail' pk=post.pk %}">{{ post.title }}</a></h2>
            <p>{{ post.text|truncatechars:200 }}</p>
        </div>
    {% endfor %}
{% endblock %}

重新整理頁面點選按鈕開啟草稿箱,就可以看到我們剛才新建的文章了。


4176027-8db61d3cb7e84d69.JPG
21.jpg

這裡有一點要說明的是,對照post_draft_list.html和草稿箱列表的實際顯示介面,我們可以看到文章的建立時間是顯示出來的。點選文章標題進入文章詳情頁,實際用的是post_detail的檢視和模板,post_detail.html裡面通過if判斷是否顯示釋出時間,這使得這個模板可以被post_draft_list和post_list公用,如果沒有這個判斷而是直接顯示的話,對於未釋出文章的詳情頁就會因缺少引數publish_date而出錯。可見這個if的重要性。

文章釋出


在文章詳情頁面新增一個釋出的按鈕,如果覺得合適的時候就能釋出文章了。仍然是四步,很簡單。

第一步,新增連結。
開啟post_detail.html,把我們剛才說的if判斷,也就是:

{% if post.published_date %}
    {{ post.published_date |date:'M d, Y'}}
{% endif %}

替換成下面的:

{% if post.published_date %}
    {{ post.published_date|date:'M d, Y' }}
{% else %}
    <a class="btn btn-default" href="{% url 'post_publish' pk=post.pk %}">Publish</a>
{% endif %}

也就是說,如果有釋出時間就顯示釋出時間,否則就顯示釋出按鈕。這裡要連結名為post_publish的url。

第二步,在mysite\mysite\urls.py新增一條url,指向檢視post_publish:

url(r'^post/(?P<pk>[0-9]+)/publish/$', views.post_publish, name='post_publish'),

第三步,在mysite\blog\views.py新增:

def post_publish(request, pk):
    post = get_object_or_404(Article, pk=pk)
    post.publish()
    return redirect('post_detail', pk=pk)

通過model裡面定義的publish方法建立釋出時間,釋出後重定向到post_detail詳情頁。

第四步,不需要建立新的模板,所以這一步省略。

重新整理後釋出看看,有釋出日期了:


4176027-28dc765ce8045640.JPG
22.jpg

主頁面也看到它了:

4176027-c106595197009be7.JPG
23.jpg


文章編輯與刪除


文章編輯和刪除功能就一起說吧,畢竟都是那幾步。

第一步,mysite\templates\blog\post_detail.html新增按鈕連結,跟釋出按鈕差不多,最終變成這樣:

{% extends 'blog/base.html' %}
{% block content %}
    <div class="date">
        {% if post.published_date %}
            {{ post.published_date|date:'M d, Y' }}
        {% else %}
            <a class="btn btn-default" href="{% url 'post_publish' pk=post.pk %}">Publish</a>
        {% endif %}
        <a class="btn btn-default" href="{% url 'post_edit' pk=post.pk %}"><span class="glyphicon glyphicon-pencil"></span></a>
        <a class="btn btn-default" href="{% url 'post_remove' pk=post.pk %}"><span class="glyphicon glyphicon-remove"></span></a>
    </div>
    <h3>{{ post.title }}</h3>
    <a class="post-category post-category-js" href="#">{{ post.category }}</a>
    <p>{{ post.text|linebreaks }}</p>
{% endblock %}

第二步,mysite\mysite\urls.py新增url,最終變成這樣:

from django.conf.urls import url
from django.contrib import admin
from blog import views

urlpatterns = [
    url(r'admin/', admin.site.urls),
    url(r'^$', views.post_list, , name='post_list'),
    url(r'^post/(?P<pk>[0-9]+)/$', views.post_detail, name='post_detail'),
    url(r'^post/new/$', views.post_new, name='post_new'),
    url(r'^drafts/$', views.post_draft_list, name='post_draft_list'),
    url(r'^post/(?P<pk>[0-9]+)/publish/$', views.post_publish, name='post_publish'),
    url(r'^post/(?P<pk>[0-9]+)/edit/$', views.post_edit, name='post_edit'),
    url(r'^post/(?P<pk>[0-9]+)/remove/$', views.post_remove, name='post_remove'),
]

注意這裡給post_list的url命名了,方便以後對映。

第三步,mysite\blog\views.py增加檢視邏輯:

def post_edit(request, pk):
    post = get_object_or_404(Article, pk=pk)
    if request.method == "POST":
        form = ArticleForm(request.POST, instance=post)
        if form.is_valid():
            post = form.save(commit=False)
            post.author = request.user
            post.save()
            return redirect('post_detail', pk=post.pk)
    else:
        form = ArticleForm(instance=post)
    return render(request, 'blog/post_edit.html', {'form': form})

def post_remove(request, pk):
    post = get_object_or_404(Article, pk=pk)
    post.delete()
    return redirect('post_list')

第四步,post_edit重用post_edit.html模板,post_remove沒有模板,所以這一步又省略了。

效果自己看吧,多試試,編輯和刪除功能對已釋出和草稿箱文章都適用,這裡不截圖了。

2016.10.24

相關文章