Django3.0+Python3.8+MySQL8.0 個人博客搭建十五|評論區

一、前言

博客中的評論系統其實是個很複雜的東西,但是網上已經有現成的輪子了,比如django-contrib-comments,可以直接拿過來用。咱們的博客主頁是抓取別人的,目的是使用 Django 還原實現,達到快速藉助 Wordpress 主題,使用 Djano 框架建站。這樣你就可以找一個自己喜歡的前端模板,快速搭建自己的小天地了。那麼這裏就不便使用輪子,這裏會根據 崔慶才 博客主頁評論功能自己設計後臺邏輯。

推薦學習:django-contrib-comments

二、創建評論應用

參考

Django3.0+Python3.8+MySQL8.0 個人博客搭建四|創建第一個APP

創建 comment 評論應用,放入 apps 應用管理文件中,不要忘記在 settings.py 中註冊新添加的 app 應用。

(fswy) blog xiatian$ django-admin startapp comment

下邊編寫老四樣:

  • models
  • view
  • templatetags
  • urls.py

三、添加評論模型

這個評論其實是一個很複雜的功能,但是考慮到博客主要是展示自己學習、生活、成長的地方,並不是論壇,所以就沒有考慮很多東西,評論搞的就很簡陋。

數據分析

首先根據頁面分析一下需要什麼表

文章評論給我留言關於自己頁面都有評論功能,而且崔慶才個人博客的評論功能,還支持遊民評論

需要一個遊民表CommentUser

需要一個評論信息表 (Comment)

有三個頁面有評論功能看,在這裏我打算把三個評論區分別建表存儲

  • 文章評論(ArticleComment)
  • 關於自己(AboutComment)
  • 給我留言(MessageComment)
blog -> comment -> models.py
from django.db import models
from django.conf import settings
from apps.fswy.models import Article

import markdown
import emoji
# Create your models here.

# 遊民評論者信息表
class CommentUser(models.Model):
    nickname = models.CharField(max_length=20, verbose_name='暱稱')
    email = models.CharField(max_length=30, verbose_name='郵箱')
    address = models.CharField(max_length=200, verbose_name='地址')


# 評論信息表
class Comment(models.Model):
    author = models.ForeignKey(CommentUser,
                               related_name='%(class)s_related',
                               verbose_name='評論人',
                               on_delete=models.CASCADE)
    create_date = models.DateTimeField('創建時間', auto_now_add=True)
    content = models.TextField('評論內容')
    parent = models.ForeignKey('self',
                               related_name ='%(class)s_child_comments',
                               verbose_name='父評論',
                               blank=True,
                               null=True,
                               on_delete=models.CASCADE)
    rep_to = models.ForeignKey('self',
                               verbose_name='回覆',
                               related_name='%(class)s_rep_comments',
                               blank=True,
                               null=True,
                               on_delete=models.CASCADE)

    class Meta:
        '''這是一個元類,用來繼承的'''
        abstract = True

    def __str__(self):
        return self.content[:20]

    def content_to_markdown(self):
        # 先轉換成emoji然後轉換成markdown,'escape':所有原始HTML將被轉義幷包含在文檔中
        to_emoji_content = emoji.emojize(self.content, use_aliases=True)
        to_md = markdown.markdown(to_emoji_content,
                                  safe_mode='escape',
                                  extension=[
                                      'markdown.extensions.extra',
                                      'markdown.extensions.codehilite',
                                  ])
        return to_md

# 文章評論區,據繼承評論信息表
class ArticleComment(Comment):
    # 記錄評論屬於哪篇文章
    belong = models.ForeignKey(Article,
                               related_name='article_comments',
                               verbose_name='所屬文章',
                               on_delete=models.CASCADE)

    class Meta:
        verbose_name = '文章評論'
        verbose_name_plural = verbose_name
        ordering = ['create_date']


# 關於自己頁面評論信息
class AboutComment(Comment):
    class Meta:
        verbose_name = '關於自己評論'
        verbose_name_plural = verbose_name
        ordering = ['create_date']


# 給我留言頁面評論信息
class MessageComment(Comment):
    class Meta:
        verbose_name = '給我留言'
        verbose_name_plural = verbose_name
        ordering = ['create_date']

這裏評論信息表其實可以只創建一個表即可,但是這裏分開創建,有兩個目的:

  1. 方便後期擴展
  2. 瞭解模型內繼承的使用

參考

Django3.0+Python3.8+MySQL8.0 個人博客搭建六|數據庫結構設計

數據表信息變動

每當數據表信息變動時
在終端執行:

(fswy) blog xiatian$ python3 manage.py makemigrations
(fswy) blog xiatian$ python3 manage.py migrate
(fswy) blog xiatian$ python3 manage.py makemigrations
Migrations for 'comment':
  apps/comment/migrations/0001_initial.py
    - Create model CommentUser
    - Create model MessageComment
    - Create model ArticleComment
    - Create model AboutComment
(fswy) blog xiatian$ python3 manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, comment, contenttypes, django_comments, fswy, sessions, sites, user
Running migrations:
  Applying comment.0001_initial... OK
  Applying sites.0001_initial... OK
  Applying django_comments.0001_initial... OK
  Applying django_comments.0002_update_user_email_field_length... OK
  Applying django_comments.0003_add_submit_date_index... OK
  Applying sites.0002_alter_domain_unique... OK

再在PyCharm中打開Database可以看到:
在這裏插入圖片描述

四、分析評論區信息

因爲後臺邏輯,其實就是對用戶需求進行處理反饋的東西,那麼首先咱們的頁面已經有了,就是 崔慶才 個人博客,所以需要分析一下 崔慶才 個人博客評論區設麼怎麼個功能,這裏怎麼分析呢?

首先進入 抓取到的 崔慶才 博客的前端源碼,結合前端 HTML 標籤對傳遞的數據進行分析

static -> js -> jquery.js
a.ajax({
    url:_deel.url+"/ajax/comment.php",
    data:a(this).serialize(),type:a(this).attr("method"),
    error:function(w) {
        a(".comt-loading").hide();
        a(".comt-error").show().html(w.responseText);
        setTimeout(function(){$submit.attr("disabled",false).fadeTo("slow",1);
        a(".comt-error").fadeOut()},3000)},
    success:function(B){
        a(".comt-loading").hide();
        r.push(a("#comment").val());
        a("textarea").each(function(){this.value=""});
        var y=addComment,A=y.I("cancel-comment-reply-link"),w=y.I("wp-temp-form-div"),C=y.I(y.respondId),x=y.I("comment_post_ID").value,z=y.I("comment_parent").value;
        if(!o&&$comments.length){
            n=parseInt($comments.text().match(/\d+/));
            $comments.text($comments.text().replace(n,n+1))
        }
        new_htm='" id="new_comm_'+k+'"></';
        new_htm=(z=="0")?('\n<ol style="clear:both;' + '" class="commentlist commentnew'+new_htm+"ol>"):('\n<ul class="children'+new_htm+"ul>");
        ok_htm='\n<span id="success_'+k+b;ok_htm+="</span><span></span>\n";
        if(z=="0"){
            if(a("#postcomments .commentlist").length){a("#postcomments .commentlist").before(new_htm)
            }else {
                a("#respond").after(new_htm)
            }
        }else{
            a("#respond").after(new_htm)}a("#comment-author-info").slideUp();
            console.log(a("#new_comm_"+k));a("#new_comm_"+k).hide().append(B);
            a("#new_comm_"+k+" li").append(ok_htm);
            a("#new_comm_"+k).fadeIn(4000);
            $body.animate({scrollTop:a("#new_comm_"+k).offset().top-200},500);
            a(".comt-avatar .avatar").attr("src",a(".commentnew .avatar:last").attr("src"));
            l();
            k++;
            o="";
            a("*").remove("#edit_id");A.style.display="none";
            A.onclick=null;
            y.I("comment_parent").value="0";
        if(w&&C){
            w.parentNode.insertBefore(C,w);
            w.parentNode.removeChild(w)
        }
    }
});

不要被 JS 源碼給嚇到,掌握了JS套路,局部分析,經過前端標籤屬性比如comment_parent、respond等屬性值在這個文件內查找,定位到以上 AJAX 代碼塊

經過調試分析這段 AJAX 代碼給後臺傳遞了這些數據

w:評論內容
comment_post_ID:評論所屬頁面,給我留言、文章留言、關於自己頁面
author:評論者
email:評論者郵箱
url:評論者網址

其實前端都是已經寫好的只需要把

url:_deel.url+"/ajax/comment.php",

改爲:

url: "/comment/add/",

但是由於,這裏我多加了一個判斷登錄用戶和遊民的功能

success: function(B) {
    console.log('success');
    a(".comt-loading").hide();
    r.push(a("#comment").val());
    a("textarea").each(function() {
        this.value = ""
    });

    //在這裏添加如下代碼
    //獲取seeion信息,判斷用戶是否登錄
    var user_id = "<%=session.getAttribute('uid','')%>";
    var nick = $('#author').val();
    if (user_id != ''){     //如果用戶處於登錄狀態,展示用戶ID
        $('#nick').html(nick);
    }
    else {                 //如果沒有登錄,證明是遊民,遊民可以換馬甲
        $('#nick').html(nick + '&nbsp; <a class="switch-author" href="javascript:;" data-type="switch-author" style="font-size:12px;">換個身份</a>');
    }

完整源碼:Github

五、編寫視圖函數

blog -> comment -> view.py
from django.shortcuts import render
from apps.fswy.models import Article
from .models import ArticleComment, CommentUser, AboutComment, MessageComment
from django.conf import settings
from django.http import HttpResponse
from django.views.decorators.http import require_POST
from django.views.decorators.csrf import csrf_exempt

# Create your views here.

import re

# 獲取用戶模型
user_model = settings.AUTH_USER_MODEL


# 確定重複是否重複
def confirm(new_content, comment_post_ID, auser):
    if comment_post_ID == 'about':
        res = AboutComment.objects.filter(content=new_content, author=auser)
    elif comment_post_ID == 'message':
        res = MessageComment.objects.filter(content=new_content, author=auser)
    else:
        res = ArticleComment.objects.filter(content=new_content, author=auser, belong_id=comment_post_ID)
    if res:
        return False
    else:
        return True


# @login_required
@csrf_exempt
@require_POST
def AddcommentView(request):
    if request.is_ajax():
        data = request.POST
        # 評論內容哦你
        new_content = data.get('w')
        # 評論對象,指的是頁面留言、文章、等
        comment_post_ID = data.get('comment_post_ID')
        # 評論者
        author = data.get('author', '')
        # 評論者郵箱
        email = data.get('email', '')
        # 評論者網址
        url = data.get('url', '')

        """
        驗證信息格式
        """
        if not re.match('^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.[a-zA-Z0-9]{2,6}$', email):
            return HttpResponse('請輸入有效的郵箱格式!', content_type='text/html;charset="utf-8"', status=405)

        if not new_content:
            return HttpResponse('請寫點什麼吧!', content_type='text/html;charset="utf-8"', status=405)

        if not author or not email:
            return HttpResponse('請填寫郵箱和暱稱', content_type='text/html;charset="utf-8"', status=405)

        # 存儲評論者信息
        CommentUser.objects.get_or_create(nickname=author, email=email, address=url)
        # 評論對象,父級對象,就是評論的是誰
        comment_parent = data.get('comment_parent')
        # 獲取用戶信息
        auser = CommentUser.objects.get(nickname=author, email=email, address=url)

        if not confirm(new_content, comment_post_ID, auser):
            return HttpResponse('請勿發表重複內容!', content_type='text/html;charset="utf-8"', status=405)

        """
        存儲評論信息
        """

        # 關於自己頁面評論
        if comment_post_ID == 'about':
            # 父級評論
            if comment_parent == '0':
                new_comment = AboutComment(author=auser, content=new_content, parent=None, rep_to=None)
            # 評論他人評論
            else:
                parent = AboutComment.objects.get(id=comment_parent)
                new_comment = AboutComment(author=auser, content=new_content, parent=parent, rep_to=None)
            new_comment.save()
        # 給我留言頁面評論
        elif comment_post_ID == 'message':
            if comment_parent == '0':
                new_comment = MessageComment(MessageComment, auser, new_content)
            else:
                parent = MessageComment.objects.get(id=comment_parent)
                new_comment = MessageComment(author=auser, content=new_content, parent=parent, rep_to=None)
            new_comment.save()
        # 文章評論
        else:
            the_article = Article.objects.get(id=comment_post_ID)
            if comment_parent == '0':
                new_comment = ArticleComment(author=auser, content=new_content, belong=the_article, parent=None, rep_to=None)
            else:
                parent = ArticleComment.objects.get(id=comment_parent)
                new_comment = ArticleComment(author=auser, content=new_content, belong=the_article, parent=parent, rep_to=None)
            new_comment.save()

        # 獲取用什麼,分登陸身份和遊民身份
        request.session['nick'] = new_comment.author.nickname
        request.session['tid'] = new_comment.author.id

        # 返回當前評論,直接返回HTML內容剛給前端,使用JS在指定位置進行數據展示
        return HttpResponse('''<li class="" id="comment-"><div class="c-avatar"><img alt='' src='https://cuiqingcai.com/avatar/.png' class='avatar avatar-54 photo avatar-default' height='54' width='54' /><div class="c-main" id="div-comment-">{0}<div class="c-meta"><span class="c-author">{1}</span></div></div></div>'''.format(new_content, author), content_type='text/html;charset="utf-8"')

    return HttpResponse('參數錯誤', content_type='text/html;charset="utf-8"')

六、配置路由

blog -> blog -> urls.py

一級路由

# 評論欄
path('comment/', include(('apps.comment.urls','apps.comment'), namespace='comment')),

二級路由

blog -> comment -> urls.py
from django.urls import path
from .views import AddcommentView


urlpatterns = [
    path(r'add/', AddcommentView, name='add_comment'),
]

七、編寫自定義模板標籤

先在comment中新建templatetags目錄,再新建comment_tags.py文件

blog -> comment -> templatetags -> comment_tags.py
# 創建了新的tags標籤文件後必須重啓服務器
from django.utils.safestring import mark_safe
from django import template
from ..models import ArticleComment,AboutComment, MessageComment


register = template.Library()


@register.simple_tag
def get_comment_count(category, entry=0):
    """獲取一個文章的評論總數"""
    if category == 'about':
        lis = AboutComment.objects.all()
    elif category == 'message':
        lis = MessageComment.objects.all()
    else:
        lis = ArticleComment.objects.filter(belong_id=entry)
    return lis.count()


@register.simple_tag
def get_parent_comments(category, entry=0):
    """獲取一個文章的父評論列表"""
    if category == 'about':
        lis = AboutComment.objects.filter(parent=None)
    elif category == 'message':
        lis = MessageComment.objects.filter(parent=None)
    else:
        lis = ArticleComment.objects.filter(belong_id=entry,parent=None)
    return lis


@register.simple_tag
def get_child_comments(category,com):
    """獲取一個父評論的子評論列表"""
    if category == 'about':
        lis = AboutComment.objects.filter(parent=com)
    elif category == 'message':
        lis = MessageComment.objects.filter(parent=com)
    else:
        lis = ArticleComment.objects.filter(parent=com)
    return lis


@register.simple_tag
def get_comment_user_count(category, entry=0):
    """獲取評論人總數"""
    p = []
    if category == 'about':
        lis = AboutComment.objects.all()
    elif category == 'message':
        lis = MessageComment.objects.all()
    else:
        lis = ArticleComment.objects.filter(belong_id=entry)
    for each in lis:
        if each.author not in p:
            p.append(each.author)
    return len(p)


# 遞歸查找父評論
def find_father(dic, comment_obj):
    # 對字典中的每一組元素進行循環操作
    for k, v_dic in dic.items():
        # 如果k等於comment_obj的父節點,那麼表示找到了父親。
        if k == comment_obj.parent:
            # 找到了父親,認祖歸宗,把自己歸位到父親下面,並給將來的兒子留個位置
            dic[k][comment_obj] = {}
            # 找到了父親,處理完畢,返回
        else:
            # 剛纔沒找到,剝一層,接着往下找。
            find_father(dic[k], comment_obj)


# 遞歸生成HTML字符串,展示評論區內容
def generate_comment_html(sub_comment_dic, category, path, s=2):
    html = "<ul class='children'>"
    # 對傳入的字典進行循環操作
    for k, v_dic in sub_comment_dic.items():
        html += '''
<li class="comment odd alt depth-{0}" id="comment-{1}"><div class="c-avatar"><img alt='' data-original='https://cuiqingcai.com/avatar/ee89e6709c344980b7b82d1a13d496fb.png' class='avatar avatar-54 photo' height='54' width='54' /><div class="c-main" id="div-comment-{1}">{2}<div class="c-meta"><span class="c-author"><a href='http://fsfs' rel='external nofollow' class='url'>{3}</a></span>{4}<a rel='nofollow' class='comment-reply-link' href='{6}?replytocom={1}#respond' οnclick='return addComment.moveForm( "div-comment-{1}", "{1}", "respond", "{5}" )' aria-label='回覆給{3}'>回覆</a></div></div></div>'''.format(s,k.id,k.content,k.author.nickname,k.create_date.strftime('%Y-%m-%d %H:%M:%S'),category,path)

        # 有可能v_dic中依然有元素, 遞歸繼續加
        if v_dic:
            s += 1
            html += generate_comment_html(v_dic, category, path, s)
        html += "</li>"
    # 循環完成最後返回html
    html += "</ul>"
    return html


# 生成層級評論
@register.simple_tag
def build_comment_tree(category, path, entry=0):
    if category == 'about':
        comment_list = AboutComment.objects.all()
    elif category == 'message':
        comment_list = MessageComment.objects.all()
    else:
        comment_list = ArticleComment.objects.filter(belong_id=entry)
    # 定義一個空字典用來保存轉換之後的結果
    comment_dic = {}
    # 對comment_list中的每個元素進行循環
    for comment_obj in comment_list:
        # 判斷comment_obj是否存在父節點。如果沒有,這把該評論作爲第一個節點
        if comment_obj.parent is None:
            comment_dic[comment_obj] = {}
        else:
            # 否則去找該對象的父節點。
            find_father(comment_dic, comment_obj)

    # 上面執行完畢,comment_dic中會有轉換好的結果
    # 開始拼接html字符串
    html = "<ol class='commentlist'>"
    # 規定一個margin left,每次有遞歸的時候就往右縮進一點。

    # 對comment_dic中的每一組元素進行操作
    for k, v in comment_dic.items():
        # 第一層html
        html += '''<li class="comment even thread-even depth-1" id="comment-{0}"><div class="c-avatar"><img alt='' data-original='https://cuiqingcai.com/avatar/5e43cb2c27191170aaece6a30a9d49f4.png' class='avatar avatar-54 photo' height='54' width='54' /><div class="c-main" id="div-comment-{0}">{1}<div class="c-meta"><span class="c-author">{2}</span>{3}<a rel='nofollow' class='comment-reply-link' href='{5}?replytocom={0}#respond' οnclick='return addComment.moveForm( "div-comment-{0}", "{0}", "respond", "{4}" )' aria-label='回覆給{2}'>回覆</a></div></div></div>'''.format(k.id,k.content,k.author.nickname, k.create_date.strftime('%Y-%m-%d %H:%M:%S'), category, path)
        # 通過遞歸把他的兒子加上
        html += generate_comment_html(v, category, path)
    # 最後把ul關上
    html += " </ol>"
    # 關掉轉義
    return mark_safe(html)

八、編寫評論區 HTML

blog -> templates中新建comment_list.html文件

blog -> templates -> comment_list.html

{% load static %}
{% load comment_tags oauth_tags %}
<div id="respond" class="no_webshot">
		<form action="/comment/add" method="post" id="commentform">

		<div class="comt-title">
            {% if request.session.username|default:'' != '' %}
            {% get_user_data request.session.uid as user %}
                <div class="comt-avatar pull-left">
                    <img alt='' src='/media/{{ user.avatar }}' class='avatar avatar-54 photo avatar-default' height='54' width='54' />			    </div>
                <div class="comt-author pull-left" id="nick">
                {{ request.session.username }}
                </div>
            {% endif %}

            {% if request.session.nick|default:'' != '' %}
                {% get_tourist_data request.session.tid as tourist %}
                <div class="comt-avatar pull-left">
                    <img alt='' src='/media/avatar' class='avatar avatar-54 photo avatar-default' height='54' width='54' />			    </div>
                <div class="comt-author pull-left" id="nick">
                {{ tourist.nickname }}

                &nbsp; <a class="switch-author" href="javascript:;" data-type="switch-author" style="font-size:12px;">換個身份</a>

                </div>
                {% else %}

                <div class="comt-author pull-left" id="nick">

                </div>
            {% endif %}

			<a id="cancel-comment-reply-link" class="pull-right" href="javascript:;">取消評論</a>
		</div>

		<div class="comt">
			<div class="comt-box">
                <h3>發表我的評論</h3>
				<textarea placeholder="寫點什麼..." class="input-block-level comt-area" name="w" id="comment" cols="100%" rows="3" tabindex="1" onkeydown="if(event.ctrlKey&amp;&amp;event.keyCode==13){document.getElementById('submit').click();return false};"></textarea><textarea name="comment" cols="100%" rows="4" style="display:none"></textarea>
				<div class="comt-ctrl">
					<button class="btn btn-primary pull-right" type="submit" name="submit" id="submit" tabindex="5"><i class="fa fa-check-square-o"></i> 提交評論</button>
					<div class="comt-tips pull-right"><input type='hidden' name='comment_post_ID' value='{{ category }}' id='comment_post_ID' />
<input type='hidden' name='comment_parent' id='comment_parent' value='0' />
<p style="display: none;"><input type="hidden" id="akismet_comment_nonce" name="akismet_comment_nonce" value="da9dc5c77a" /></p><p style="display: none;"><input type="hidden" id="ak_js" name="ak_js" value="50"/></p></div>
					<span data-type="comment-insert-smilie" class="muted comt-smilie"><i class="fa fa-smile-o"></i> 表情</span>
					<span class="muted comt-mailme"><label for="comment_mail_notify" class="checkbox inline" style="padding-top:0"><input type="checkbox" name="comment_mail_notify" id="comment_mail_notify" value="comment_mail_notify" checked="checked"/>有人回覆時郵件通知我</label></span>
				</div>
			</div>

												<div class="comt-comterinfo" id="comment-author-info" >
						<h4>Hi,您需要填寫暱稱和郵箱!</h4>
						<ul>
							<li class="form-inline"><label class="hide" for="author">暱稱</label><input class="ipt" type="text" name="author" id="author" value="{% if user %}{{ user.username }}{% elif tourist %}{{ tourist.nickname }}{% endif %}" tabindex="2" placeholder="暱稱"><span class="help-inline">暱稱 (必填)</span></li>
							<li class="form-inline"><label class="hide" for="email">郵箱</label><input class="ipt" type="text" name="email" id="email" value="{% if user %}{{ user.email }}{% elif tourist %}{{ tourist.email }}{% endif %}" tabindex="3" placeholder="郵箱"><span class="help-inline">郵箱 (必填)</span></li>
							<li class="form-inline"><label class="hide" for="url">網址</label><input class="ipt" type="text" name="url" id="url" value="{% if user %}{{ user.link }}{% elif tourist %}{{ tourist.address }}{% endif %}" tabindex="4" placeholder="網址"><span class="help-inline">網址</span></li>
						</ul>
					</div>
									</div>


	</form>
	</div>

<div id="postcomments">

{% if category == 'message'%}

    {% get_comment_user_count category as  user_num%}
    {% build_comment_tree category request.path as htm %}
{% elif category == 'about' %}
    {% get_comment_user_count category as  user_num%}
    {% build_comment_tree category request.path as htm %}
{% else %}
    {% get_comment_user_count category category as  user_num%}
    {% build_comment_tree category  request.path category as htm %}
{% endif %}
<div id="comments">
		<i class="fa fa-comments-o"></i> <b> ({{ user_num }})</b>個小夥伴在吐槽
	</div>
   {{ htm }}
<div class="commentnav"	>
			</div>
</div>

九、添加評論功能

這裏以文章頁面爲例

blog -> templates -> article.html

把評論區添加到文章詳情頁底部

        </div>
        </div>

        {% include 'comment_list.html' %}
    </div>
</div>
{% endblock body %}

哪個頁面需要評論功能,就把下邊的代碼放在需要得而位置

{% include 'comment_list.html' %}

關於自己給我留言也在相應位置添加此代碼即可

完整源碼:Github

十、效果圖

在這裏插入圖片描述

十一、總結

這裏我這裏寫的評論區功能其實很獨立,只要在需要添加評論功能的頁面需要的地方加入

{% include 'comment_list.html' %}

這個評論功能,純自己寫的,沒有寫太多功能,比如刪除評論、過濾垃圾用戶、修改評論、評論郵件提醒等。

教程目錄

Django3.0+Python3.8+MySQL8.0 個人博客搭建一|前言
Django3.0+Python3.8+MySQL8.0 個人博客搭建二|創建虛擬環境
Django3.0+Python3.8+MySQL8.0 個人博客搭建三|創建博客項目
Django3.0+Python3.8+MySQL8.0 個人博客搭建四|創建第一個APP
Django3.0+Python3.8+MySQL8.0 個人博客搭建五|makemigrations連接MySQL數據庫的坑
Django3.0+Python3.8+MySQL8.0 個人博客搭建六|數據庫結構設計
Django3.0+Python3.8+MySQL8.0 個人博客搭建七|makemigrations創建數據庫的坑(第二彈)
Django3.0+Python3.8+MySQL8.0 個人博客搭建八|通過admin管理後臺
Django3.0+Python3.8+MySQL8.0 個人博客搭建九|博客首頁開發(一)
Django3.0+Python3.8+MySQL8.0 個人博客搭建十|整理項目結構
Django3.0+Python3.8+MySQL8.0 個人博客搭建十一|博客首頁開發(二)
Django3.0+Python3.8+MySQL8.0 個人博客搭建十二|博客首頁開發(三)
Django3.0+Python3.8+MySQL8.0 個人博客搭建十三|博客詳情頁面
Django3.0+Python3.8+MySQL8.0 個人博客搭建十四|註冊登錄

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章