提示:(1)功能不全面,僅僅實現評論(2)樣式簡單
1、項目目錄結構

2、模型
from django.db import models
from django.contrib.auth.models import User
class Article(models.Model): #定義文章模型類
title = models.CharField(max_length=100,verbose_name='文章標題') #verbose_name是
content = models.TextField(verbose_name='文章內容')
publish_time = models.DateTimeField(auto_now_add=True,verbose_name='發布時間')
author = models.ForeignKey(User,on_delete=models.DO_NOTHING,verbose_name='作者')
class Meta:
db_table = 'article_tb' #定義表名
verbose_name = '文章' #后台顯示
verbose_name_plural = verbose_name #后台顯示的復數
class Comment(models.Model): #定義評論模型
article = models.ForeignKey(to=Article,on_delete=models.DO_NOTHING,verbose_name='評論文章')
comment_content = models.TextField(verbose_name='評論內容')
comment_author = models.ForeignKey(to=User,on_delete=models.DO_NOTHING,verbose_name='評論者')
comment_time = models.DateTimeField(auto_now_add=True,verbose_name='評論時間')
pre_comment = models.ForeignKey('self',on_delete=models.DO_NOTHING,null=True,verbose_name='父評論id') #父級評論,如果沒有父級則為空NULL, "self"表示外鍵關聯自己
class Meta:
db_table = 'comment_tb'
verbose_name = '評論'
verbose_name_plural = verbose_name
3、路由:
from django.contrib import admin
from django.urls import path,re_path
from myapp import views #導入myapp中的視圖函數
urlpatterns = [
path('admin/', admin.site.urls),
path('register/',views.register), #用戶注冊路由
path('user_login/',views.user_login), #用戶登錄路由
path('index/',views.index), #首頁路由
re_path('article_detail/(\d)/',views.article_detail), #文章詳情頁路由,並傳入文章的id
path('comment_control/',views.comment_control) #提交評論處理的路由
]
4、視圖函數
from django.http import JsonResponse
from django.shortcuts import render,HttpResponse,redirect
from django.contrib import auth #使用Django的auth認證組件
from django.contrib.auth.models import User #使用Django的認證組件需要使用User用戶表
from myapp.models import Article #導入Article模型
from myapp.models import Comment #導入Comment模型
def register(request): #用戶注冊函數
if request.method == 'GET':
return render(request,'register.html') #返回一個注冊的頁面
else:
username = request.POST.get('username') #獲取注冊輸入的信息
password = request.POST.get('password')
User.objects.create_user(username=username,password=password) #在User表創建用戶記錄
return HttpResponse('注冊成功')
def user_login(request): #用戶登錄函數
if request.method == 'GET':
return render(request,'user_login.html')
else:
username = request.POST.get('username') #獲取登錄輸入的信息
password = request.POST.get('password')
user = auth.authenticate(username=username,password=password) #用戶驗證
if user:
auth.login(request,user) #認證成功則保持登錄狀態
return HttpResponse('登陸成功')
else:
return redirect('/user_login/') #認證失敗則跳轉到登錄頁面進行重新登錄
def index(request): #首頁函數
if request.user.username: #判斷用戶是否已登錄(用戶名是否存在)
all_article_list = Article.objects.all() #取出所有的文章對象,結果返回一個QuerySet[]對象
context = {
'all_article_list': all_article_list
}
return render(request,'index.html',context=context) #返回首頁的頁面,並將文章對象傳到模板進行渲染
else:
return redirect('/user_login/') #如果用戶沒有登錄,則跳轉至登錄頁面
def article_detail(request,article_id):
if request.user.username:
article = Article.objects.get(id=article_id) #從數據庫找出id=article_id的文章對象
comment_list = Comment.objects.filter(article_id=article_id) #從數據庫找出該文章的評論數據對象
context = {
'article': article,
'comment_list': comment_list
}
return render(request,'article_detail.html',context=context) #返回對應文章的詳情頁面
else:
return redirect('/user_login/')
def comment_control(request): #提交評論的處理函數
if request.user.username:
comment_content = request.POST.get('comment_content')
article_id = request.POST.get('article_id')
pid = request.POST.get('pid')
author_id = request.user.id #獲取當前用戶的ID
Comment.objects.create(comment_content=comment_content,pre_comment_id=pid,article_id=article_id,comment_author_id=author_id) #將提交的數據保存到數據庫中
article = list(Comment.objects.values('id','comment_content','pre_comment_id','article_id','comment_author_id','comment_time')) #以鍵值對的形式取出評論對象,並且轉化為列表list類型
return JsonResponse(article,safe=False) #JsonResponse返回JSON字符串,自動序列化,如果不是字典類型,則需要添加safe參數為False
else:
return redirect('/user_login/')
5、模板templates
(1)注冊頁面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>注冊頁面</title>
</head>
<body>
<h6>注冊</h6>
<form action="" method="post"> {# 注冊提交信息的表單,POST方式提交注冊信息 #}
<input type="text" placeholder="用戶名" name="username">
<input type="password" placeholder="密碼" name="password">
<input type="submit" value="注冊">
</form>
</body>
</html>
(2)登錄頁面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登錄頁面</title>
</head>
<body>
<h6>登錄</h6>
<form action="" method="post"> {# 登錄時提交信息的表單,POST方式 #}
<input type="text" placeholder="用戶名" name="username">
<input type="password" placeholder="密碼" name="password">
<input type="submit" value="登錄">
</form>
</body>
</html>
(3)首頁
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>首頁</title>
<style>
.article{
width: 80%;
}
.article_list{
width: 100%;
border: red 1px dashed;
}
.article .article_list th{
text-align: center;
border: 1px skyblue dashed;
}
.article .article_list td{
text-align: center;
border: 1px green dashed;
}
</style>
</head>
<body>
<div class="article">
<table class="article_list">
<tr>
<th>文章ID</th>
<th>文章標題</th>
<th>文章內容</th>
<th>發布時間</th>
<th>作者</th>
</tr>
{% for article in all_article_list %}
<tr>
<td>{{ article.id }}</td>
<td><a href="/article_detail/{{ article.id }}/">{{ article.title }}</a> {# 點擊鏈接打開文章詳情頁,並傳入文章的ID #}
<td>{{ article.content }}</td>
<td>{{ article.publish_time | date:"Y-m-d H:i:s"}}</td>
<td>{{ article.author }}</td>
</tr>
{% endfor %}
</table>
</div>
</body>
</html>
(4)文章詳情頁
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>文章詳情</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
<style>
.article_detail{
width: 80%;
margin-left: 100px;
}
.comment_post{
width: 80%;
margin-left: 100px;
}
.comment_show{
width: 80%;
margin-left: 100px;
}
#commentform_title {
background-image: url(//static.cnblogs.com/images/icon_addcomment.gif);
background-repeat: no-repeat;
padding: 0 0 0 25px;
margin-bottom: 10px;
}
.feedback_area_title {
border-bottom: 1px solid #ddd;
font-size: 14px;
font-weight: bold;
margin: 20px 0 10px;
}
#p{
border: deepskyblue 1px dashed;
background-color: antiquewhite;
}
</style>
</head>
<body>
<div class="article_detail"> {# 文章詳情區域的div #}
<h4>{{ article.title }}</h4>
<p>{{ article.content }}</p>
<p>發布時間:{{ article.publish_time | date:"Y-m-d H:i:s"}} 作者:{{ article.author }}</p>
</div>
<div class="comment_post"> {# 提交評論區域的div #}
<div id="commentform_title">發表評論</div>
<textarea rows="10" cols="60" id="comment_content"></textarea>
<p><button>提交評論</button></p>
</div>
<div class="comment_show"> {# 評論展示區域的div #}
<div class="feedback_area_title">評論列表</div>
<div class="comment_list">
{% for comment in comment_list %} {# 循環展示評論的數據 #}
<div>
<p>第{{ forloop.counter}}樓 -> By:{{ comment.comment_author.username }} -> {{ comment.comment_time }} -> <button class="reply" username={{ comment.comment_author.username }} pk={{ comment.pk }}>回復</button></p> {# 在此處定義一個回復按鈕,用戶實現子評論,並且自定義屬性username和pk,用於下面回復功能的實現 #}
{% if comment.pre_comment_id %} {# 判斷評論是否有父級評論 #}
<p id="p">原評論內容:{{ comment.pre_comment.comment_content }}</p> {# 如果有父級評論,則在中間顯示父級評論的評論內容 #}
{% endif %}
<p>評論內容:{{ comment.comment_content }}</p>
<hr>
</div>
{% endfor %}
</div>
</div>
{# 提交評論的JS,發送Ajax請求 #}
<script>
var pid = "" {# 設置一個變量pid默認為空,用於后面作為數據庫存儲的父級評論的ID,如果沒有父級評論則為空,子評論有父級評論 #}
{# 提交評論按鈕的點擊事件 #}
$(".comment_post p button").click(function (){
$.ajax({
url: '/comment_control/',
type: 'post',
data: {
comment_content: $("#comment_content").val(), {# 提交的數據內容data #}
article_id: {{ article.id }},
pid: pid
},
success: function (res){ {# 本例中返回的數據僅僅用於在控制台打印而已 #}
console.log(res) {# 控制台打印返回的數據 #}
$("#comment_content").val("") {# 提交完成后,清空評論輸入框的內容 #}
pid = "" {# 子評論提交完成后,將pid默認設置為空,恢復為默認的父評論 #}
}
})
})
{# 回復按鈕的點擊事件 #}
$(".reply").click(function (){
$("#comment_content").focus() {# 回復按鈕的事件,點擊時,將光標聚集到評論輸入框中 #}
var val = "@" + $(this).attr("username") + "\n" {# $(this)指代".reply"標簽本身,獲取這個標簽的username值 #}
$("#comment_content").val(val) {# 回復時,自動在輸入框加入:@要回復的人 #}
pid = $(this).attr("pk") {# 當點擊回復時,父評論ID不再為空,此時修改為:對應評論的主鍵值ID #}
})
</script>
</body>
</html>
6、數據庫表


7、結果展示

