留言板模塊包括讀者留言和管理員回復(fù),屏蔽或刪除留言。
- 讀者留言按時(shí)間倒序排列。
- 管理員回復(fù)的留言在每條讀者留言的下方。
- 管理員可以對(duì)評(píng)論進(jìn)行回復(fù),屏蔽或刪除某條留言。
首先構(gòu)造留言板的模型。
#comment 模塊 models.py
from django.db import models
from user.models import MyUser
class Message(models.Model):
msgid = models.AutoField('序號(hào)', primary_key=True)
content = models.TextField('留言內(nèi)容', )
date = models.DateField('留言時(shí)間',)
from_user = models.ForeignKey(MyUser, on_delete=models.CASCADE, verbose_name='留言者')
msg_status= models.IntegerField('留言狀態(tài)', default=1)
parent_msgid = models.ForeignKey('self', verbose_name="回復(fù)留言", on_delete=models.CASCADE, blank=True, null=True)
def __str__(self):
return self.content
class Meta:
verbose_name = '用戶留言'
verbose_name_plural = '用戶留言'
上面的字段中,msg_status用來表示是否顯示用戶的留言,默認(rèn)為1表示顯示留言,parent_msgid外鍵關(guān)聯(lián)自身的msgid,表示是對(duì)關(guān)聯(lián)的留言的回復(fù)留言。其他的字段很好理解。模型建好以后執(zhí)行數(shù)據(jù)遷移,創(chuàng)建好數(shù)據(jù)表。
然后到項(xiàng)目的urls.py中開啟最后一道大門。
下面就是編寫comment應(yīng)用的URL地址信息和視圖函數(shù),以及在templates下添加message.html模板文件
# comment 下的 urls.py
from django.urls import path
from . import views
#設(shè)置URL的地址信息
urlpatterns = [
path('message/', views.messageView, name='message'),
]
#comment 下的 views.py
from django.shortcuts import render
from .models import Message
from user.models import Library, MyUser
from datetime import datetime
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.contrib.auth.decorators import login_required
@login_required(login_url='/user/login.html')
def messageView(request, page):
#獲取該用戶所屬館的館名和館實(shí)例對(duì)象
lib_name = request.user.lib_id
library = Library.objects.get(lib_name=lib_name)
#如果是POST請(qǐng)求,則說明用戶在發(fā)表留言
if request.method == 'POST':
user_id = MyUser.objects.get(id=request.user.id)
time = datetime.now()
content = request.POST.get('content')
Message.objects.create(content=content, date=time, from_user=user_id)
#查詢所在館的留言記錄倒序排列
messages = Message.objects.select_related('from_user__lib_id').filter(from_user__lib_id__lib_id=library.lib_id).order_by('-msgid')
#分頁
paginator = Paginator(messages, 5)
try:
pageInfo = paginator.page(page)
except PageNotAnInteger:
pageInfo = paginator.page(1)
except EmptyPage:
pageInfo = paginator.page(paginator.num_pages)
return render(request, 'message.html', locals())
簡(jiǎn)單的講解一下邏輯,接收到用戶請(qǐng)求后,首先獲取圖書館館名和館的實(shí)例對(duì)象,然后判斷是不是POST請(qǐng)求,如果是則說明用戶在發(fā)表留言,將留言相關(guān)信息保存到數(shù)據(jù)庫,如果是GET請(qǐng)求,獲取該用戶所在圖書館的所有留言記錄并且倒序排列,輸出到模板文件message.html。最后看下模板文件。
{% extends "base.html" %}
{% load staticfiles %}
<link rel="stylesheet" href="{% static 'css/mycss.css' %}">
{# 隱藏頂部搜索框 #}
{% block search %}
{% endblock %}
{% block body %}
<div class="alert alert-success mx-auto">
<span><h5>{{ lib_name }}-留言板</h5></span>
</div>
<ul class="list-group">
{% for msg in pageInfo %}
{% if msg.parent_msgid == NULL %}
<div class="alert alert-info">
<lable>由 <strong>{{ msg.from_user }}</strong> <small>{{ msg.date }} </small>留言</lable>
<li class="list-group-item">{{ msg.content }}</li>
</div>
{% else %}
<div class="alert alert-info">
<lable>由 <strong>{{ msg.parent_msgid.from_user }}</strong> <small>{{ msg.parent_msgid.date }} </small>留言
<li class="list-group-item">{{ msg.parent_msgid.content }}</li>
</div>
<div class="alert alert-warning">
<div class="clearfix">
<div class="float-right">
<lable>由 <strong>{{ msg.from_user }}</strong> <small>{{ msg.date }} </small>回復(fù)</lable>
</div>
</div>
<li class="list-group-item">{{ msg.content }}</li>
</div>
{% endif %}
{% endfor %}
</ul>
{# 分頁 #}
<div class="center">
<ul class="pagination">
{% if pageInfo.has_previous %}
<li class="page-item"><a class="page-link" href="{% url 'message' pageInfo.previous_page_number %}">上一頁</a></li>
{% endif %}
{% if pageInfo.has_next %}
<li class="page-item"><a class="page-link" href="{% url 'message' pageInfo.next_page_number %}">下一頁</a></li>
{% endif %}
</ul>
</div>
<form action="{% url 'message' 1 %}" method="POST">
{% csrf_token %}
<div class="form-group alert alert-info col-sm-12">
<label for="comment">用戶名:<strong>{{ user.username }}</strong></label>
<textarea class="form-control" rows="5" name="content" id="comment" placeholder="請(qǐng)留言..." required></textarea>
<button type="submit" class="btn btn-primary">留言</button>
</div>
</form>
{% endblock %}
實(shí)現(xiàn)效果如下:

然后就是做個(gè)留言板后臺(tái)管理模塊,在library應(yīng)用里添加新的URL地址信息
path('lib_msgadmin/<int:page>/', views.LibMsgAdminView, name='lib_msgadmin'),
編寫留言板后臺(tái)管理的視圖函數(shù)LibMsgAdminView,別忘記頭部導(dǎo)入相關(guān)模塊和模型,這里只貼出了部分代碼。
#登陸驗(yàn)證和身份驗(yàn)證
@login_required(login_url='/user/login.html')
@permission_required(perm='recommend.change_recommend')
#圖書館留言管理
def LibMsgAdminView(request, page):
#獲取該用戶所屬館名
lib_name = request.user.lib_id
#獲取該館實(shí)例對(duì)象
library = Library.objects.get(lib_name=lib_name)
#如果是POST請(qǐng)求,則說明是管理員在回復(fù)用戶留言
if request.method == 'POST':
#獲取用戶的實(shí)例對(duì)象
myuser = MyUser.objects.get(id=request.user.id)
#通過隱藏表單獲取用戶留言的msgid
msgid=request.POST.get('msgid')
#轉(zhuǎn)為msg的實(shí)例對(duì)象
msginstance = Message.objects.get(msgid=msgid)
content = request.POST.get('content')
time = datetime.now()
Message.objects.create(content=content, date=time, from_user=myuser, parent_msgid=msginstance)
#查詢所在館的留言記錄倒序排列
messages = Message.objects.select_related('from_user__lib_id').filter(from_user__lib_id__lib_id=library.lib_id).order_by('-msgid')
#分頁
paginator = Paginator(messages, 5)
try:
pageInfo = paginator.page(page)
except PageNotAnInteger:
pageInfo = paginator.page(1)
except EmptyPage:
pageInfo = paginator.page(paginator.num_pages)
return render(request, 'lib_msgadmin.html', locals())
后臺(tái)管理的邏輯和前臺(tái)差不多,主要差別就是回復(fù)留言的時(shí)候獲取了隱藏表單中用戶留言的msgid保存到數(shù)據(jù)表中的parent_id外鍵中。
模板文件lib_msgadmin.html如下:
{% extends "base.html" %}
{% load staticfiles %}
<link rel="stylesheet" href="{% static 'css/mycss.css' %}">
{# 隱藏頂部搜索框 #}
{% block search %}
{% endblock %}
{% block body %}
<div class="alert alert-success mx-auto">
<span><h5>{{ lib_name }}-留言板管理</h5></span>
<label><small>點(diǎn)擊留言內(nèi)容可回復(fù)留言</small></label>
</div>
<ul class="list-group">
{% for msg in pageInfo %}
{% if msg.parent_msgid == NULL %}
<div class="alert alert-info">
<lable>由 <strong>{{ msg.from_user }}</strong> <small>{{ msg.date }} </small>留言</lable>
<li class="list-group-item" data-toggle="modal" data-target="#modal{{ forloop.counter }}">{{ msg.content }}</li>
</div>
<div class="modal fade" id="modal{{ forloop.counter }}">
<div class="modal-dialog">
<div class="modal-content">
<!-- 模態(tài)框主體 -->
<form action="{% url 'lib_msgadmin' page %}" method="POST">
{% csrf_token %}
<input type="hidden" name="msgid" value="{{ msg.msgid }}">
<div class="form-group alert alert-info col-sm-12">
<label for="comment">回復(fù)用戶:<strong>{{ msg.from_user }}</strong></label>
<textarea class="form-control" rows="5" name="content" id="comment" placeholder="回復(fù)留言..." required></textarea>
<button type="submit" class="btn btn-primary">回復(fù)</button>
</div>
</form>
</div>
</div>
</div>
{% else %}
<div class="alert alert-info">
<lable>由 <strong>{{ msg.parent_msgid.from_user }}</strong> <small>{{ msg.parent_msgid.date }} </small>留言
<li class="list-group-item">{{ msg.parent_msgid.content }}</li>
</div>
<div class="alert alert-warning">
<div class="clearfix">
<div class="float-right">
<lable>由 <strong>{{ msg.from_user }}</strong> <small>{{ msg.date }} </small>回復(fù)</lable>
</div>
</div>
<li class="list-group-item">{{ msg.content }}</li>
</div>
{% endif %}
{% endfor %}
</ul>
{# 分頁 #}
<div class="center">
<ul class="pagination">
{% if pageInfo.has_previous %}
<li class="page-item"><a class="page-link" href="{% url 'lib_msgadmin' pageInfo.previous_page_number %}">上一頁</a></li>
{% endif %}
{% if pageInfo.has_next %}
<li class="page-item"><a class="page-link" href="{% url 'lib_msgadmin' pageInfo.next_page_number %}">下一頁</a></li>
{% endif %}
</ul>
</div>
{% endblock %}
回復(fù)留言

回復(fù)后的效果

留言板里的效果

如果需要對(duì)留言板有一個(gè)控制,比如能夠屏蔽某些非法留言,就可以用到msg_status這個(gè)字段,數(shù)據(jù)表中默認(rèn)是 1,我們把它該成非1的值就能實(shí)現(xiàn)屏蔽留言的功能。
首先到瀏覽展示的模板文件message.html中添加一個(gè)條件判斷。
{% if msg.msg_status == 1 %}
然后在留言板管理后臺(tái)模板lib_msgadmin.html添加一個(gè)屏蔽留言的功能按鈕
{% if msg.msg_status == 1 %}
<div class="float-right">
<a href="{% url 'lib_msgadmin' page %}?msgid={{ msg.msgid }}"><button type="text" class="btn btn-secondary">屏蔽該留言</button></a>
</div>
{% else %}
<div class="float-right">
<button type="text" class="btn btn-secondary">已屏蔽</button>
</div>
{% endif %}
模板將瀏覽的msgid通過GET參數(shù)傳遞給視圖函數(shù)處理。
視圖函數(shù)中多做一個(gè)If判斷,將GET獲取到的msgid的msg_status設(shè)置為0或任意其他值即可實(shí)現(xiàn)留言的屏蔽。
#如果通過GET獲取到了msgid,說明是管理員用戶要屏蔽該條留言
if request.GET.get('msgid'):
msgid = request.GET.get('msgid')
#將留言狀態(tài)設(shè)置為0
Message.objects.filter(msgid=msgid).update(msg_status=0)

點(diǎn)擊屏蔽按鈕后,該條留言成為已屏蔽狀態(tài),進(jìn)入留言板模板可以發(fā)現(xiàn)被屏蔽的留言不見了。

但是,我們發(fā)現(xiàn)留言被屏蔽了2條,現(xiàn)在第一頁只有3條留言了,被屏蔽的留言雖然沒有顯示,但還是被從數(shù)據(jù)庫中讀取出來了,這種情況,我們只要在查詢數(shù)據(jù)的時(shí)候再加 msg_status=1 這個(gè)條件,這樣讀取的就全是正常狀態(tài)的留言了。
#comment 的 views.py
messages = Message.objects.select_related('from_user__lib_id').filter(from_user__lib_id__lib_id=library.lib_id,msg_status=1).order_by('-msgid')
現(xiàn)在再看留言板,第一頁就是完整的5條留言了。
