文章詳情頁(yè)
使用 markdown 語(yǔ)法發(fā)布文章以及評(píng)論功能
Markdown 編輯器
?Markdown 的語(yǔ)法簡(jiǎn)潔明了、學(xué)習(xí)容易,而且功能比純文本更強(qiáng),因此有很多人用它寫(xiě)博客。而作為一個(gè)博客網(wǎng)站,支持 markdown 也是必然的。
安裝 markdown
# 在虛擬環(huán)境中執(zhí)行
$ pip install markdown
修改視圖函數(shù)
?在視圖中將文章內(nèi)容的 markdown 語(yǔ)法 渲染成 HTML 文本
from markdown import markdown
...
def article(request, slug):
context = {}
article = Article.objects.get(title=slug)
# 將內(nèi)容文本渲染成 HTML 文本
article.body = markdown(
article.body,
extensions = [
'markdown.extensions.extra',
'markdown.extensions.codehilite',
'markdown.extensions.toc',
]
)
context['article'] = article
if request.user.is_authenticated:
context['username']= request.user.username
return render(request, 'blog/article.html', context=context)
?這里要注意,在模板文件中 {{ article.body }} 標(biāo)簽要修改成 {{ article.body | safe }} ,因?yàn)?django 處于安全考慮會(huì)將任何 HTML 代碼進(jìn)行轉(zhuǎn)義。
語(yǔ)法高亮
?當(dāng)在文章中添加了一些代碼實(shí)例時(shí),根據(jù)所屬語(yǔ)言渲染,達(dá)到高亮的效果
# 注意在虛擬環(huán)境中安裝
$ pip install Pygments
安裝完成之后,執(zhí)行一下命令生成一個(gè) css 文件
$ pygmentize -S default -f html -a .codehilite > code.css
?把生成的 code.css 文件放入靜態(tài)文件中,再在模板文件中引用
<!-- templates/blog/article.html -->
...
<link rel="stylesheet" type="text/css" href="/static/blog/css/highlights/code.css">
...
評(píng)論功能
?評(píng)論功能相對(duì)獨(dú)立,所以新建一個(gè)應(yīng)用來(lái)完成評(píng)論功能
應(yīng)用 comment
# 在 manage.py 的同級(jí)目錄中執(zhí)行
$ python manage.py startapp comment
?在配置文件中注冊(cè) comment 應(yīng)用
# fbckf/settings.py
...
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'blog',
'comment',
]
...
模型
?評(píng)論表單內(nèi)容
用戶名稱
文章
評(píng)論內(nèi)容
創(chuàng)建時(shí)間
?編寫(xiě)數(shù)據(jù)模型
# comment/models.py
from django.db import models
from django.contrib.auth.models import User
from blog.models import Article
# Create your models here.
class Comment(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
article = models.ForeignKey(Article, on_delete=models.CASCADE)
body = models.TextField()
create_time = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.body[:20]
?數(shù)據(jù)庫(kù)遷移
$ python manage.py makemigrations
$ python manage.py migrate
URL
# comment/urls.py
from django.urls import path
from . import views
app_name = 'comment'
urlpatterns = [
path('/<slug>/', views.comment, name='comment'),
]
?在 fbckf/urls.py 中 include() comment 應(yīng)用的 urls.py 文件
# fbckf/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('blog.urls')),
path('comment/', include('comment.urls')),
]
視圖函數(shù)
?視圖函數(shù)將接受道德評(píng)論更新到數(shù)據(jù)庫(kù)表中,并將新數(shù)據(jù)返回給文章頁(yè)面
# comment/views.py
from django.shortcuts import render, get_object_or_404, redirect
from django.contrib.auth.models import User
from blog.models import Article
from .models import Comment
def comment(request, slug):
article = get_object_or_404(Article, title=slug)
if request.method == "POST":
username = request.POST['username']
body = request.POST['comment']
if username and body:
user = User.objects.get(username=username)
comment = Comment(user=user, article=article, body=body)
comment.save()
return redirect(article)
else:
comment = article.comment_set.all()
return render(request, 'blog/article.html', {'article':article, 'comments':comments})
return redirect(article)
get_object_or_404()獲取Article對(duì)象 ,獲取失敗 返回用戶 404 頁(yè)面redirect()函數(shù) 重定向到文章詳情頁(yè)面,但是需要修改文章數(shù)據(jù)模型
# blog/models.py
from django.urls import reverse
...
class Article(models.Model):
...
# 返回文章詳情頁(yè)的 url
def get_absolute_url(self):
return reverse('blog:article', kwargs={'slug':self.title})
?點(diǎn)開(kāi)文章頁(yè)面是也要獲取評(píng)論列表,因此也要修改 article視圖函數(shù)
# blog/views.py
...
def article(request, slug):
...
comments = article.comment_set.all()
context['comments'] = comments
...
return render(request, 'blog/article.html', context=context)
?Comment 模型和 Article 模型是 ForeignKey 關(guān)聯(lián)關(guān)聯(lián)關(guān)系,因此使用 article.comment_set.all() 反向獲取所有評(píng)論
修改模板文件
<!-- templates/blog/article.html -->
...
<!-- 判斷用戶是否登陸 -->
{% if username %}
<div class="center">
<button class="btn btn-outline-dark btn-lg" type="button" data-toggle="collapse" href="#post-comment" role="button" aria-expanded="false" aria-controls="post-comment">
<i class="fa fa-comment-o" aria-hidden="true"></i> 評(píng)論
</button>
<button id="like_article" value="{{ article.title }}" type="button" class="btn btn-lg btn-outline-danger" data-toggle="body" data-content="您是第 {{ article.likes|add:1 }} 位喜歡這篇文章的讀者!">
<i class="fa fa-heart-o" aria-hidden="true"></i> 喜歡
</button>
<div class="collapse" id="post-comment">
<!-- 將表單數(shù)據(jù)以 post 模式提交給后臺(tái) -->
<form action="{% url 'comment:comment' article.title %}" method="post">
{% csrf_token %}
<div class="form-group">
<textarea name="comment" id="input-comment" cols="30" rows="5" class="form-control"></textarea>
<input class="display_none" name="username" value="{{ username }}">
</div>
<button class="btn btn-outline-dark" type="submit">發(fā)送</button>
</form>
</div>
</div>
{% endif %}
<!-- 判斷是否有評(píng)論 -->
{% if comments %}
<!-- 遍歷評(píng)論列表 -->
{% for comment in comments %}
<hr>
<div class="comment-list">
<div class="comment-detail">
<div class="row justify-content-start">
<img src="{% static 'blog/img/carousel2.jpg' %}" class="rounded" alt="user" style="width: 50px; height: 50px;">
<p class="lead col">{{ comment.user.username }} | {{ comment.create_time }}</p>
</div>
<div class="row justify-content-end">
<p class="col-11">{{ comment.body }}</p>
</div>
</div>
</div>
{% endfor %}
{% else %}
<hr>
<div class="row justify-content-end">
<p class="col-11">暫無(wú)評(píng)論!</p>
</div>
{% endif %}
...
?完成后可以重啟服務(wù)器進(jìn)進(jìn)行測(cè)試
總結(jié)
?Markdown 語(yǔ)法簡(jiǎn)潔易懂,普遍用于博客寫(xiě)作,這里也就選擇讓博客支持 Markdown 寫(xiě)作。另外還有富文本編輯器等其他功能可以選擇,不需要一定是 Markdown。
?評(píng)論功能的用戶關(guān)聯(lián)考慮的不是很恰當(dāng),應(yīng)該改為關(guān)聯(lián)其他平臺(tái)用戶,時(shí)間不夠留待下次修改。