Python Django 學習紀錄:架設個人部落格(二)
分頁、統計文章、富文本編輯
六.、分頁和 shell 命令行模式
(1)分頁功能的用途
部落格文章數量較多的時候,全部加載速度會十分緩慢
而採用分頁加載能夠有效改善
(2)shell 命令行模式添加部落格文章
使用shell的方式,有助於熟悉對於django的操作
在專案虛擬環境輸入 python manage.py shell 進入 shell 命令行模式
接著導入會使用到的資料庫模組
就可以透過 shell 命令行模式來新增部落格文章了
以下為範例程式:
可以 runserver 來看看成果
緊接著使用 for 迴圈 一次新增多篇文章,供之後測試分頁使用
(3)分頁器實現分頁
1.分頁器介紹
使用 Django 本身提供的分頁器 Paginator
請在<views.py>的上方加入以下代碼導入:
from django.core.paginator import Paginator
分頁器的使用方式:
paginator = Paginator(object_list(資料庫列表), each_page_count(每頁資料數量))
頁面呼叫方式:
page1 = paginator.page(1)
2.設定模型默認排序
使用分頁器的時候需要有排序的準則,或沒有設置的話系統會跳出提醒
所以打開 <models.py> 來對 Blog 資料表添加默認排序的設置
以下為 <models.py> 更新後的代碼:
from django.db import models from django.contrib.auth.models import User #導入內建的使用者模組 # Create your models here. class BlogType(models.Model): #部落格文章類型 type_name = models.CharField(max_length=15) def __str__(self): return self.type_name class Blog(models.Model): #部落格文章(由於會用外鍵連接到部落格文章類型,所以此模型要放在後面) title = models.CharField(max_length=50) content = models.TextField() author = models.ForeignKey(User, on_delete=models.CASCADE) #使用外鍵連接到使用者模組,由於尚未建立先不做任何事情 created_time = models.DateTimeField(auto_now_add = True) last_updated_time = models.DateTimeField(auto_now = True) blog_type = models.ForeignKey(BlogType, on_delete=models.CASCADE) #使用外鍵連接到部落格文章類型 def __str__(self): return "<Blog: %s>" % self.title class Meta: ordering = ['-created_time']
設定好後要進行makemigrations 和 migrate 並重新 runserver
(4)分頁的使用
前端:發送請求,請求打開具體分頁內容
後端:處理請求,返回具請分頁內容響應請求
這邊採用 GET 的方法取得分頁參數,而非之前採用Django傳送參數的方法
首先在<views.py>中,修改blog_list的內容,將分頁器加入其中:
from django.shortcuts import render, render_to_response, get_object_or_404 from django.core.paginator import Paginator #導入分頁器 from .models import Blog, BlogType def blog_list(request): blogs_all_list = Blog.objects.all() paginator = Paginator(blogs_all_list, 5) #每5篇進行分頁 page_num = request.GET.get('page', 1) #獲取url的頁面參數 (GET請求) page_of_blogs = paginator.get_page(page_num) #get_page會自動識別頁碼,若無效則返回1,超出頁數則顯示最後一頁 context={} #建立字典 context['blogs'] = page_of_blogs.object_list context['page_of_blogs'] = page_of_blogs context['blog_types'] = BlogType.objects.all() #將資料放入字典 return render(request, 'blog/blog_list.html', context) #將字典返回到'bloglist.html'
修改<blog_list.html>,在文章內容後加入分頁:
<!-- 分頁 --> <div> <ul class="pagination"> <!-- 上一頁 --> <li> {% if page_of_blogs.has_previous %} <a href="?page={{ page_of_blogs.previous_page_number }}" aria-label="Previous"> <span aria-hidden="true">«</span> </a> {% else %} <span aria-hidden="true">«</span> {% endif %} </li> <!-- 全部頁碼 --> {% for page_num in page_of_blogs.paginator.page_range %} <li><a href="?page={{ page_num }}">{{ page_num }}</a></li> {% endfor %} <!-- 下一頁 --> <li> {% if page_of_blogs.has_next %} <a href="?page={{ page_of_blogs.next_page_number }}" aria-label="Next"> <span aria-hidden="true">»</span> </a> {% else %} <span aria-hidden="true">»</span> {% endif %} </li> </ul> </div>
(5)settings 自定義參數
公用的全局設置可以放在settings中來統一管理
在文件開頭添加以下代碼:
from django.conf import settings
而這邊我們在settings文件的最下方加入以下代碼,為每個分頁的文章篇數,供之後使用:
#自定義參數 EACH_PAGE_BLOGS_NUMBER = 2
(6)分頁的優化顯示
友好的用戶體驗:凸顯當前頁碼、不要過多的頁碼選擇(影響頁面布局)
1.縮減頁碼與加入省略符號
這邊有些對於初學者可能會有些複雜,我將詳細的註解都打在程式碼之中
打開<views.py>,並在 blog_list 中加入關於分頁器的代碼:
def blog_list(request): blogs_all_list = Blog.objects.all() paginator = Paginator(blogs_all_list, settings.EACH_PAGE_BLOGS_NUMBER) #根據settings的自定義參數進行分頁 page_num = request.GET.get('page', 1) #獲取url的頁面參數 (GET請求) page_of_blogs = paginator.get_page(page_num) #get_page會自動識別頁碼,若無效則返回1,超出頁數則顯示最後一頁 current_page_num = page_of_blogs.number #獲取當前頁碼 #獲取當前頁碼前後各2頁範圍 #list 建立串列、range 範圍內的所有值(不包含最後一項,所以尾項要+1)、max 取最大值、min 取最小值、paginator.num_pages 取得總頁數 #串列(範圍(當前頁數-2,到當前頁數,再跟1相比,小於1則取1) # +範圍(當前頁數,到當前頁數+2,再跟總頁數相比,若大於總頁數則取總頁數)尾項加上1) page_range = list(range(max(1, current_page_num - 2), current_page_num)) + \ list(range(current_page_num, min(paginator.num_pages, current_page_num + 2) + 1)) #加上省略頁碼標記 if page_range[0] -1 >= 2: #若第0項減1小於等於2 page_range.insert(0, '...') #則在串列插入省略符號 if page_range[-1] + 2 <= paginator.num_pages: #若最後一項加2大於等於總頁數 page_range.append('...') #則在串列最後加上省略符號 #加上首頁與尾頁 if page_range[0] != 1: #若串列第0項不為1 page_range.insert(0, 1) #則在第0項插入1 if page_range[-1] != paginator.num_pages: #若串列最後一項項不為總頁數 page_range.append(paginator.num_pages) #則在串列最後加上總頁數 context={} #建立字典 context['blogs'] = page_of_blogs.object_list context['page_of_blogs'] = page_of_blogs context['blog_types'] = BlogType.objects.all() #將資料放入字典 context['page_range'] = page_range #取得分頁器資訊 return render(request, 'blog/blog_list.html', context) #將字典返回到'bloglist.html'
這裡先完成了後端,接著前端與凸顯代碼一起編寫
2.凸顯當前頁碼與 刪除省略符號的超連結
使用 if 條件判斷
在使用者到該分頁的時候,頁碼將呈現active狀態
而如果頁碼為省略符號,也使用 if 條件判斷 顯示為無超連結的頁碼
在 <blog_list.html> 中的<ul class="pagination"> 修改為以下代碼:
<ul class="pagination"> <!-- 上一頁 --> <li> {% if page_of_blogs.has_previous %} <a href="?page={{ page_of_blogs.previous_page_number }}" aria-label="Previous"> <span aria-hidden="true">«</span> </a> {% else %} <span aria-hidden="true">«</span> {% endif %} </li> <!-- 全部頁碼 --> {% for page_num in page_range %} <!-- 若為當前頁碼,則加入active狀態 --> {% if page_num == page_of_blogs.number %} <li class="active"><span>{{ page_num }}</span></li> {% else %} <!-- 若為省略號,則沒有超連結 --> {% if page_num == '...' %} <li ><span>{{ page_num }}</span></li> {% else %} <li ><a href="?page={{ page_num }}">{{ page_num }}</a></li> {% endif %} {% endif %} {% endfor %} <!-- 下一頁 --> <li> {% if page_of_blogs.has_next %} <a href="?page={{ page_of_blogs.next_page_number }}" aria-label="Next"> <span aria-hidden="true">»</span> </a> {% else %} <span aria-hidden="true">»</span> {% endif %} </li> </ul>
下方為目前完成部分的展示:
(7)分類列表的分頁整合
之前添加的分頁器只包含在部落格文章列表
在分類列表還無法生效,所以要打開<views.py> 修改 blogs_with_type 的代碼:
def blogs_with_type(request, blog_type_pk): #導入 blog_type_pk 變數 blog_type = get_object_or_404(BlogType, pk=blog_type_pk) #獲取編號 blogs_all_list = Blog.objects.filter(blog_type=blog_type) #取得分類後的資料 paginator = Paginator(blogs_all_list, settings.EACH_PAGE_BLOGS_NUMBER) #根據settings自定義參數進行分頁 page_num = request.GET.get('page', 1) #獲取url的頁面參數 (GET請求) page_of_blogs = paginator.get_page(page_num) #get_page會自動識別頁碼,若無效則返回1,超出頁數則顯示最後一頁 current_page_num = page_of_blogs.number #獲取當前頁碼 #獲取當前頁碼前後各2頁範圍 #list 建立串列、range 範圍內的所有值(不包含最後一項,所以尾項要+1)、max 取最大值、min 取最小值、paginator.num_pages 取得總頁數 #串列(範圍(當前頁數-2,到當前頁數,再跟1相比,小於1則取1) # +範圍(當前頁數,到當前頁數+2,再跟總頁數相比,若大於總頁數則取總頁數)尾項加上1) page_range = list(range(max(1, current_page_num - 2), current_page_num)) + \ list(range(current_page_num, min(paginator.num_pages, current_page_num + 2) + 1)) #加上省略頁碼標記 if page_range[0] -1 >= 2: #若第0項減1小於等於2 page_range.insert(0, '...') #則在串列插入省略符號 if page_range[-1] + 2 <= paginator.num_pages: #若最後一項加2大於等於總頁數 page_range.append('...') #則在串列最後加上省略符號 #加上首頁與尾頁 if page_range[0] != 1: #若串列第0項不為1 page_range.insert(0, 1) #則在第0項插入1 if page_range[-1] != paginator.num_pages: #若串列最後一項項不為總頁數 page_range.append(paginator.num_pages) #則在串列最後加上總頁數 context={} #建立字典 context['blogs'] = page_of_blogs.object_list #取得當前頁碼的資料 context['page_of_blogs'] = page_of_blogs context['page_range'] = page_range #取得分頁器資訊 context['blog_type'] = blog_type #將過濾後的資料存入變數 context['blog_types'] = BlogType.objects.all() #將資料放入字典(繼承blog_list需要用到相同的變數) return render(request, 'blog/blogs_with_type.html', context)
修改<blog_with_type.html>
由於文章數量會繼承<blog_list.html>分頁器下方的文章數量訊息,所以這邊可以將原先的訊息刪除:
<!-- 繼承模板 --> {% extends "blog/blog_list.html" %} {% load staticfiles %} <!-- 加載靜態文件 --> <!-- 繼承標題區塊 --> {% block title %} {{ blog_type.type_name }} {% endblock %} <!-- 繼承內容區塊 --> {% block blog_list_title %} 分類:{{ blog_type.type_name }} <a href="{% url 'blog_list' %}">查看全部部落格文章</a> {% endblock %}
下方為目前完成部分的展示:
六.、上下篇文章按月分類
(1)filter 篩選條件(等於)
大於:__gt (greater than)
大於等於:__gte
小於:__lt (less than)
小於等於:__lte
包含:__contains (加icontain忽略大小寫)
開頭是:__startswith
結尾是:__endswith
其中之一:__in
範圍:__range
(2)exclude 排除條件(不等於)
為filter的條件取反
(3)條件中的雙下畫線
字段查詢類型
外鍵拓展(以部落格分類為例)
日期拓展(以月分分類為例)
支持鏈式查詢:可以一直鏈接下去
(4)上一篇和下一篇部落格文章
在文章詳細頁面<blog_detail.html> 添加 上一篇、下一篇的文章標題與連結
在<views.py>中的 blog_detail 函數中修改以下代碼:
def blog_detail(request, blog_pk): #導入 blog_pk 變數 context={} #建立字典 blog = get_object_or_404(Blog, pk=blog_pk) #獲取blog_pk #資料庫文章日期已經為由新到舊排列(新文章日期大於舊文章日期) #獲取前一篇文章,取得大於該文章的日期中的最後一篇 context['previous_blog'] = Blog.objects.filter(created_time__gt=blog.created_time).last() #獲取後一篇文章,取得小於該文章的日期中的第一篇 context['next_blog'] = Blog.objects.filter(created_time__lt=blog.created_time).first() context['blog'] = blog return render(request, 'blog/blog_detail.html', context) #將字典返回到'blog_detail.html'
接著在<blog_detail.html>下方添加上一篇、下一篇的文章標題與連結
若已經無文章,則顯示"沒有了",代碼如下˙:
<!-- 繼承模板 --> {% extends "base.html" %} <!-- 繼承標題區塊 --> {% block title %}{{ blog.title }}{% endblock %} {% block nav_blog_active %}active{% endblock %} {% load staticfiles %} <!-- 加載靜態文件 --> {% block header_extends %} <link rel="stylesheet" href="{% static 'css/blog.css' %}"> {% endblock %} <!-- 用於擴展額外 css --> <!-- 繼承內容區塊 --> {% block content %} <div class="container"> <div class="row"> <div class="col-xs-10 col-xs-offset-1"> <h3>{{ blog.title }}</h3> <ul class="blog-info-description"> <li>作者:{{ blog.author }}</li> <li>分類:<a href="{% url 'blogs_with_type' blog.blog_type.pk %}">{{ blog.blog_type }}</a></li> <!-- 將日期改為純數字24時制顯示 --> <li>發表日期:{{ blog.created_time|date:"Y-m-d H:i:s" }}</li> </ul> <div class="blog-content">{{ blog.content }}</div> <!-- 上一篇、下一篇文章標題連結 --> <div class="blog_more"> <p>上一篇: {% if previous_blog %} <a href="{% url 'blog_detail' previous_blog.pk %}">{{ previous_blog.title }}</a></p> {% else %} 沒有了 {% endif %} <p>下一篇:{% if next_blog %} <a href="{% url 'blog_detail' next_blog.pk %}">{{ next_blog.title }}</a></p> {% else %} 沒有了 {% endif %} </p> </div> </div> </div> </div> {% endblock %}
(5)按月分類
1.url路徑設定
首先在blog專案的<urls.py>添加新的路徑:
from django.urls import path from . import views urlpatterns = [ path('',views.blog_list, name='blog_list'), #將原先的部落格頁面路徑修改至此 #連接文章標題至文章詳細頁面 path('<int:blog_pk>', views.blog_detail, name = "blog_detail"), #連接文章份類至分類頁面 path('type/<int:blog_type_pk>', views.blogs_with_type, name = "blogs_with_type"), path('date/<int:year>/<int:month>', views.blogs_with_date, name = "blogs_with_date"), ]
2.後端編寫
接著在blog目錄中的<views.py>中,新建一個名為blogs_with_date 的函數
由於與blogs_with_type 函數大部分內容相同,這邊只在有修改的部分加上註解:
def blogs_with_date(request, year, month): blogs_all_list = Blog.objects.filter(created_time__year = year, created_time__month = month) #篩選取得日期歸檔後的資料 paginator = Paginator(blogs_all_list, settings.EACH_PAGE_BLOGS_NUMBER) page_num = request.GET.get('page', 1) page_of_blogs = paginator.get_page(page_num) current_page_num = page_of_blogs.number page_range = list(range(max(1, current_page_num - 2), current_page_num)) + \ list(range(current_page_num, min(paginator.num_pages, current_page_num + 2) + 1)) if page_range[0] -1 >= 2: page_range.insert(0, '...') if page_range[-1] + 2 <= paginator.num_pages: page_range.append('...') if page_range[0] != 1: page_range.insert(0, 1) if page_range[-1] != paginator.num_pages: page_range.append(paginator.num_pages) context={} #供面板標題使用(傳送到<blogs_with_date.html>模板頁面) context['blogs_with_date'] = '%s年%s月' % (year, month) context['blog_dates'] = Blog.objects.dates('created_time','month',order='DESC')#降序排序日期 context['blogs'] = page_of_blogs.object_list context['page_of_blogs'] = page_of_blogs context['page_range'] = page_range context['blog_types'] = BlogType.objects.all() return render(request, 'blog/blogs_with_date.html', context) #傳送到<blogs_with_date.html>模板頁面
在blog_list 函數的字典也要加上日期的變數:
context['blog_dates'] = Blog.objects.dates('created_time','month',order='DESC')#降序排序日期
3.前端文章列表添加"日期歸檔"面板、創建日期歸檔模板
打開<blog_list.html>在分類面板下面新增日期歸檔面板:
<div class="panel panel-default"> <div class="panel-heading">日期歸檔</div> <div class="panel-body"> <ul class="blog_date"> {% for blog_date in blog_dates %} <li> <a href="{% url 'blogs_with_date' blog_date.year blog_date.month %}">{{ blog_date|date:"Y年m月" }}</a> </li> {% endfor %} </ul> </div> </div>
在blog目錄創建一個名為<blog_with_date.html>的模板
內容與<blog_with_type.html>大部分相同,只有面板標題需要做更改:
<!-- 繼承模板 --> {% extends "blog/blog_list.html" %} {% load staticfiles %} <!-- 加載靜態文件 --> <!-- 繼承標題區塊 --> {% block title %} {{ blog_type.type_name }} {% endblock %} <!-- 繼承內容區塊 --> {% block blog_list_title %} 日期歸檔:{{ blogs_with_date }} <a href="{% url 'blog_list' %}">查看全部部落格文章</a> {% endblock %}
(6)重複程式碼精簡:
這邊將blog目錄的<views.py>中,多個函數共同使用的相同代碼獨立出來
新定義一個名為 get_blog_list_common_data 的函數,並將會共同使用的代碼寫入其中
最後返回字典,供其他函數使用:
def get_blog_list_common_data(request, blogs_all_list): paginator = Paginator(blogs_all_list, settings.EACH_PAGE_BLOGS_NUMBER) #根據settings自定義參數進行分頁 page_num = request.GET.get('page', 1) #獲取url的頁面參數 (GET請求) page_of_blogs = paginator.get_page(page_num) #get_page會自動識別頁碼,若無效則返回1,超出頁數則顯示最後一頁 current_page_num = page_of_blogs.number #獲取當前頁碼 #獲取當前頁碼前後各2頁範圍 #list 建立串列、range 範圍內的所有值(不包含最後一項,所以尾項要+1)、max 取最大值、min 取最小值、paginator.num_pages 取得總頁數 #串列(範圍(當前頁數-2,到當前頁數,再跟1相比,小於1則取1) # +範圍(當前頁數,到當前頁數+2,再跟總頁數相比,若大於總頁數則取總頁數)尾項加上1) page_range = list(range(max(1, current_page_num - 2), current_page_num)) + \ list(range(current_page_num, min(paginator.num_pages, current_page_num + 2) + 1)) #加上省略頁碼標記 if page_range[0] -1 >= 2: #若第0項減1小於等於2 page_range.insert(0, '...') #則在串列插入省略符號 if page_range[-1] + 2 <= paginator.num_pages: #若最後一項加2大於等於總頁數 page_range.append('...') #則在串列最後加上省略符號 #加上首頁與尾頁 if page_range[0] != 1: #若串列第0項不為1 page_range.insert(0, 1) #則在第0項插入1 if page_range[-1] != paginator.num_pages: #若串列最後一項項不為總頁數 page_range.append(paginator.num_pages) #則在串列最後加上總頁數 context={} #建立字典 context['blogs'] = page_of_blogs.object_list context['page_of_blogs'] = page_of_blogs context['blog_types'] = BlogType.objects.all() #將資料放入字典 context['blog_dates'] = Blog.objects.dates('created_time','month',order='DESC') context['page_range'] = page_range #取得分頁器資訊 return context
而其他三個函數修改如下:
def blog_list(request): blogs_all_list = Blog.objects.all() context= get_blog_list_common_data(request, blogs_all_list) return render(request, 'blog/blog_list.html', context) #將字典返回到'bloglist.html' def blogs_with_type(request, blog_type_pk): #導入 blog_type_pk 變數 blog_type = get_object_or_404(BlogType, pk=blog_type_pk) #獲取編號 blogs_all_list = Blog.objects.filter(blog_type=blog_type) #取得分類後的資料 context = get_blog_list_common_data(request, blogs_all_list) context['blog_type'] = blog_type #將過濾後的資料存入變數 return render(request, 'blog/blogs_with_type.html', context) def blogs_with_date(request, year, month): blogs_all_list = Blog.objects.filter(created_time__year = year, created_time__month = month) #篩選取得日期歸檔後的資料 context = get_blog_list_common_data(request, blogs_all_list) #供面板標題使用(傳送到<blogs_with_date.html>模板頁面) context['blogs_with_date'] = '%s年%s月' % (year, month) return render(request, 'blog/blogs_with_date.html', context) #傳送到<blogs_with_date.html>模板頁面
七.、文章統計
在文章分類與日期歸檔的地方,添加統計文章數量的部分
最後執行結果如圖:
1.文章分類統計:
使用 annotate 註釋,拓展查詢字段
在 <views.py> get_blog_list_common_data 函數中,修改查詢分類的字典,將文章數量也加入字典中
首先導入計算資料庫數量的模組:
from django.db.models import Count
接著建立一個名為 blog_type_count 的變數,來放入查詢文章與數量的資料:
#獲取分類文章與數量 blog_type_count = BlogType.objects.annotate(blog_count=Count('blog')) #統計BlogType關聯項的Blog模組的小寫 context['blog_types'] = blog_type_count
修改<blog_list.html>頁面:
<div class="hidden-xs col-sm-4 col-md-3 col-lg-2"> <div class="panel panel-default"> <div class="panel-heading">部落格分類</div> <div class="panel-body"> <ul class="blog-types"> {% for blog_type in blog_types %} <li><a href="{% url 'blogs_with_type' blog_type.pk %}">{{ blog_type.type_name }}({{ blog_type.blog_count }})</a></li> {% empty %} <li>暫無分類,敬請期待</li> {% endfor %} </ul> </div> </div>
2.日期歸檔統計:
使用字典的方式來查詢,鍵為日期歸檔的資料,值為篇數
在 <views.py> get_blog_list_common_data 函數中,修改查詢日期歸檔的字典,將文章數量也加入字典中:
#獲取日期歸檔與數量 blog_dates = Blog.objects.dates('created_time','month',order='DESC') #日期歸檔資料 blog_dates_dict={} #建立字典(鍵(日期歸檔的資料):值(篇數)) for blog_date in blog_dates: blog_count = Blog.objects.filter(created_time__year=blog_date.year, created_time__month=blog_date.month).count() blog_dates_dict[blog_date] = blog_count #迴圈儲存"鍵 = [值]"
修改<blog_list.html>頁面:
<div class="panel panel-default"> <div class="panel-heading">日期歸檔</div> <div class="panel-body"> <ul class="blog_date"> {% for blog_date, blog_count in blog_dates.items %} <li> <a href="{% url 'blogs_with_date' blog_date.year blog_date.month %}">{{ blog_date|date:"Y年m月" }}({{ blog_count }})</a> </li> {% endfor %} </ul> </div> </div>
八.、部落格後台富文本編輯與上傳圖片
1.使用django-ckeditor:
django有許多的編輯器,選擇 django-ckeditor 的標準如下:
- 具有基本的富文本編輯功能
- 可以上傳圖片
- 可以查看原碼
- 有持續更新
django-ckeditor 的相關文件點此
2.安裝django-ckeditor:
(1)安裝
在虛擬環境中的 mysite 專案安裝套件,指令如下:
pip install django-ckeditor
(2)註冊應用
在 settings 的應用中,添加以下代碼:
'ckeditor',
(3)配置 model
導入套件,並將文章內文的字段改為RichTextField:
from django.db import models from django.contrib.auth.models import User #導入內建的使用者模組 from ckeditor.fields import RichTextField #導入富文本套件 # Create your models here. class BlogType(models.Model): #部落格文章類型 type_name = models.CharField(max_length=15) def __str__(self): return self.type_name class Blog(models.Model): #部落格文章(由於會用外鍵連接到部落格文章類型,所以此模型要放在後面) title = models.CharField(max_length=50) content = RichTextField() #改為RichTextField author = models.ForeignKey(User, on_delete=models.CASCADE) #使用外鍵連接到使用者模組,由於尚未建立先不做任何事情 created_time = models.DateTimeField(auto_now_add = True) last_updated_time = models.DateTimeField(auto_now = True) blog_type = models.ForeignKey(BlogType, on_delete=models.CASCADE) #使用外鍵連接到部落格文章類型 def __str__(self): return "<Blog: %s>" % self.title class Meta: ordering = ['-created_time']
(4)解析html
導入富文本編輯後,顯示的文字會連同html代碼一同顯示,所以要將這些代碼屏蔽掉
首先是<blog_detail.html>,只需修改一行代碼:
<div class="blog-content">{{ blog.content | safe }}</div>
接著是<blog_list.html>,由於此處有省略字符,不適合用safe的方式,所以採用以下代碼:
<!-- truncatechars:<int> (縮略長文) --> <p>{%autoescape off%} {{blog.content|truncatechars:120}} {%endautoescape%}</p>
3.添加上傳圖片的功能:
(1)安裝
在虛擬環境中的 mysite 專案安裝套件,指令如下:
pip install pillow
(2)註冊應用
在 settings 的應用中,添加以下代碼:
'ckeditor_uploader',
(3)配置settings
在 settings 的最下方自定義參數前,添加以下代碼: :
# media MEDIA_URL = '/media/' MEDIA_ROOT = os.path.join(BASE_DIR,'media') #配置ckeditor CKEDITOR_UPLOAD_PATH = 'upload/'
(4)配置url
開發的時候使用下列方法添加url,部屬的時候需要用其他的方法:
from django.contrib import admin from django.urls import path, include from . import views from django.conf import settings #導入settings from django.conf.urls.static import static #導入static urlpatterns = [ path('', views.home, name = 'home'), #新增的首頁路徑 path('admin/', admin.site.urls), path('blog/', include('blog.urls')), #導入應用中設置的路徑 path('ckeditor',include('ckeditor_uploader.urls')), #引入路徑 ] urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) #導入路徑
(5)配置model把字段改成RichTextUploadingField
將<models.py>的代碼修改如下:
from django.db import models from django.contrib.auth.models import User #導入內建的使用者模組 from ckeditor_uploader.fields import RichTextUploadingField #改為從uploader導入 RichTextUploadingField # Create your models here. class BlogType(models.Model): #部落格文章類型 type_name = models.CharField(max_length=15) def __str__(self): return self.type_name class Blog(models.Model): #部落格文章(由於會用外鍵連接到部落格文章類型,所以此模型要放在後面) title = models.CharField(max_length=50) content = RichTextUploadingField() #修改此處 author = models.ForeignKey(User, on_delete=models.CASCADE) #使用外鍵連接到使用者模組,由於尚未建立先不做任何事情 created_time = models.DateTimeField(auto_now_add = True) last_updated_time = models.DateTimeField(auto_now = True) blog_type = models.ForeignKey(BlogType, on_delete=models.CASCADE) #使用外鍵連接到部落格文章類型 def __str__(self): return "<Blog: %s>" % self.title class Meta: ordering = ['-created_time']
※要點擊上傳到伺服器,才能取得網址