Django——实现最基础的评论功能(只有一级评论)

 我对评论功能的理解:

————————(1)数据库建一个评论的表

————————(2)前端建一个提交评论的form表单

————————(3)表单提交评论内容后写入到数据库评论表中

————————(4)将评论表的数据取出来展示到前端评论列表中

 

1、项目目录结构

 

 

2、路由

(1)总路由:

1
2
3
4
5
6
7
from django.contrib import admin
from django.urls import path,include
 
urlpatterns = [
    path('admin/', admin.site.urls),
    path('blog/',include('blog.urls'))
]

  

(2)app路由:

1
2
3
4
5
6
7
from django.urls import path,re_path
from blog import views
 
urlpatterns = [
    path('',views.index),
    re_path('article_detail/(\d+)',views.article_detail)   # 传入文章ID参数
]

  

 

3、模型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
from django.db import models
from django.contrib.auth.models import User
 
class Article(models.Model):
    title = models.CharField(max_length=70,verbose_name='文章标题')
    content = models.TextField(verbose_name='正文')
    author = models.ForeignKey(to=User,on_delete=models.DO_NOTHING,verbose_name='作者')
    created_time = models.DateTimeField(auto_now_add=True,verbose_name='发布时间')
 
    class Meta:
        db_table = 'article'
        verbose_name = '文章'
        verbose_name_plural = verbose_name
 
 
class Comment(models.Model):
    article = models.ForeignKey(to=Article,on_delete=models.DO_NOTHING,verbose_name='文章')
    content = models.TextField(verbose_name='评论内容')
    author = models.ForeignKey(User,on_delete=models.DO_NOTHING,verbose_name='评论者')
    post_time = models.DateTimeField(auto_now_add=True,verbose_name='评论时间')
 
    class Meta:
        db_table = 'comment'
        verbose_name = '评论'
        verbose_name_plural = verbose_name

  

4、视图函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
from django.shortcuts import render,HttpResponse,redirect
from django.core.paginator import Paginator
from blog.models import Article
from blog.models import Comment
 
def index(request):
    all_article_list = Article.objects.all()
    paginator = Paginator(all_article_list,10) #实例化分页器对象
    page = int(request.GET.get('page',1)) #获取页码数
    article_list_obj = paginator.page(page)  #获取当前页的分页对象
    article_list = article_list_obj.object_list #获取当前页的数据列表
    context = {
        'article_list': article_list,
        'paginator': paginator,
        'article_list_obj': article_list_obj
    }
    return render(request,'blog/index.html',context=context)
 
 
def article_detail(request,article_id):
    if request.method == 'GET':
        article = Article.objects.get(id=article_id)
        comment_list = Comment.objects.filter(article_id=article.id)
        context = {
            'article': article,
            'request': request,
            'comment_list': comment_list
        }
        return render(request,'blog/article_detail.html',context=context)
    else:
        c_id = article_id
        c_author = request.user.id
        c_content = request.POST.get('content')
        Comment.objects.create(content=c_content,article_id=c_id,author_id=c_author)
        return redirect('/blog/article_detail/{}/'.format(c_id))

  

5、模板HTML

(1)base.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
<!doctype html>
<html lang="zh-CN">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
    <meta name="description" content="">
    <meta name="author" content="">
    <link rel="icon" href="https://cdn.jsdelivr.net/npm/@bootcss/v3.bootcss.com@1.0.14/favicon.ico">
    <link rel="canonical" href="https://getbootstrap.com/docs/3.4/examples/jumbotron/">
 
    <title>{% block title %}{% endblock %}</title>
 
    <!-- Bootstrap core CSS -->
    <link href="https://cdn.jsdelivr.net/npm/@bootcss/v3.bootcss.com@1.0.14/dist/css/bootstrap.min.css" rel="stylesheet">
    <!-- IE10 viewport hack for Surface/desktop Windows 8 bug -->
    <link href="https://cdn.jsdelivr.net/npm/@bootcss/v3.bootcss.com@1.0.14/assets/css/ie10-viewport-bug-workaround.css" rel="stylesheet">
    <!-- Custom styles for this template -->
    <link href="https://cdn.jsdelivr.net/npm/@bootcss/v3.bootcss.com@1.0.14/examples/jumbotron/jumbotron.css" rel="stylesheet">
    <!-- Just for debugging purposes. Don't actually copy these 2 lines! -->
    <!--[if lt IE 9]><script src="https://cdn.jsdelivr.net/npm/@bootcss/v3.bootcss.com@1.0.14/assets/js/ie8-responsive-file-warning.js"></script><![endif]-->
    <script src="https://cdn.jsdelivr.net/npm/@bootcss/v3.bootcss.com@1.0.14/assets/js/ie-emulation-modes-warning.js"></script>
    <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
    <!--[if lt IE 9]>
      <script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
      <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
    <![endif]-->
  </head>
 
  <body>
    <nav class="navbar navbar-inverse navbar-fixed-top">
      <div class="container">
        <div class="navbar-header">
          <a class="navbar-brand" href="/blog/">博客首页</a>
        </div>
        <div id="navbar" class="navbar-collapse collapse">
          <form class="navbar-form navbar-right">
            <div class="form-group">
              <input type="text" placeholder="Email" class="form-control">
            </div>
            <div class="form-group">
              <input type="password" placeholder="Password" class="form-control">
            </div>
            <button type="submit" class="btn btn-success">登录</button>
          </form>
        </div><!--/.navbar-collapse -->
      </div>
    </nav>
    <br>
 
    {% block content %}
 
    {% endblock %}
 
 
 
  </body>
</html>

  

(2)首页index.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
{% extends 'base.html' %}
 
{% block title %}
    博客首页
{% endblock %}
 
{% block content %}
        <div class="container">
        <div class="row">
          <div class="el-col-md-12">
 
              <table class="table">   {# 文章列表 #}
                  <tr class="info">
                      <th>ID</th>
                      <th>标题</th>
                      <th>正文</th>
                      <th>正文</th>
                      <th>时间</th>
                  </tr>
                  {% for article in article_list %}
                      <tr class="active">
                          <td>{{ article.id }}</td>
                          <td><a href="/blog/article_detail/{{ article.id }}/">{{ article.title}}</a></td>
                          <td>{{ article.content|truncatechars:100}}</td>
                          <td>{{ article.created_time}}</td>
                          <td>{{ article.author.username}}</td>
                      </tr>
                  {% endfor %}
              </table>              {# 文章列表结束 #}
 
              <div>                 {# 分页块 #}
                <nav aria-label="Page navigation">
                  <ul class="pagination">
                      {% if article_list_obj.has_previous %}
                        <li>
                           <a href="/blog/?page={{ article_list_obj.previous_page_number }}" aria-label="Previous">
                             <span aria-hidden="true">«</span>
                           </a>
                        </li>
                      {% endif %}
                      {% for number in paginator.page_range %}
                        <li><a href="/blog/?page={{ number }}">{{ number }}</a></li>
                      {% endfor %}
                      {% if article_list_obj.has_next %}
                          <li>
                           <a href="/blog/?page={{ article_list_obj.next_page_number }}" aria-label="Next">
                             <span aria-hidden="true">»</span>
                           </a>
                        </li>
                      {% endif %}
                  </ul>
                </nav>
              </div>   {# 分页块结束 #}
 
 
 
          </div>
        </div>
    </div>
{% endblock %}

  

(3)文章详情article_detail.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
{% extends 'base.html' %}
 
{% block title %}
    文章详情
{% endblock %}
 
{% block content %}
<div class="container">
    <div class="row">
        <div class="col-md-12">
 
            <div class="panel panel-primary">   {# 文章详情区域 #}
               <div class="panel-body">
                 {{ article.title }}
               </div>
                <div class="panel-body">
                 {{ article.content }}
               </div>
               <div class="panel-footer">{{ article.author }} {{ article.created_time }}</div>
            </div>   {# 文章详情区域结束 #}
 
            <div>
                <hr>
                <h4><b>评论</b></h4>
                <form action="" method="post">
                    <textarea class="form-control" rows="3" name="content"></textarea>
                    <br>
                    <button type="submit" class="btn btn-primary">提交</button>
                </form>
                <hr>
 
                <div class="panel panel-danger">
                    <div class="panel-body">评论列表</div>
 
                    <div>
                        {% for comment in comment_list %}
                            <div> {{ comment.content }}</div>
                            <div> {{ comment.post_time }} & {{ comment.author.username }}</div>
                            <hr>
                        {% endfor %}
                    </div>
                </div>
 
            </div>
         
        </div>
    </div>
</div>
{% endblock %}

  

6、效果

 

 

 

 

posted @   映辉  阅读(257)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示