CJ 1 سال پیش
والد
کامیت
c5f5e5a835

+ 7 - 0
blog/admin.py

@@ -1,3 +1,10 @@
 from django.contrib import admin
 from django.contrib import admin
 
 
+
 # Register your models here.
 # Register your models here.
+class CommentAdmin(admin.ModelAdmin):
+    # 需要显示的字段信息
+    list_display = ('id', 'nick_name', 'website', 'email', 'comment')
+
+    # 设置哪些字段可以点击进入编辑界面,默认是第一个字段
+    list_display_links = ['nick_name']

+ 3 - 2
blog/controller/article.py

@@ -2,7 +2,6 @@ import json
 from datetime import datetime
 from datetime import datetime
 
 
 from django.contrib.auth.decorators import login_required
 from django.contrib.auth.decorators import login_required
-from django.core import serializers
 from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage
 from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage
 from django.http import JsonResponse, HttpResponseRedirect
 from django.http import JsonResponse, HttpResponseRedirect
 from django.shortcuts import render
 from django.shortcuts import render
@@ -52,11 +51,13 @@ def show_article(request, pk):
                                                                'user__first_name', 'user_id',
                                                                'user__first_name', 'user_id',
                                                                'user__last_name', 'markdown_text', 'is_top',
                                                                'user__last_name', 'markdown_text', 'is_top',
                                                                'html_text').first()
                                                                'html_text').first()
+    comments = models.Comment.objects.filter(article_id=int(pk))
+
     from blog.views import get_record_and_tags
     from blog.views import get_record_and_tags
     result = get_record_and_tags()
     result = get_record_and_tags()
 
 
     return render(request, 'blog.html', context={'article': article, 'records': result['records'],
     return render(request, 'blog.html', context={'article': article, 'records': result['records'],
-                                                 'tags': result['tags']})
+                                                 'tags': result['tags'], 'comments': comments})
 
 
 
 
 @login_required(login_url='/')
 @login_required(login_url='/')

+ 46 - 0
blog/controller/comment.py

@@ -0,0 +1,46 @@
+import datetime
+
+from django.http import JsonResponse, HttpResponseRedirect
+
+from blog import models
+from system.error.ServerException import ServerException
+
+
+
+
+def add_comment(request):
+    if request.method == 'POST':
+        nick_name = request.POST.get("nick_name")
+        avatar = request.POST.get("avatar")
+        website = request.POST.get("website")
+        article_id = request.POST.get("article_id")
+        comment = request.POST.get('comment')
+        email = request.POST.get('email')
+        article = models.Article.objects.get(id=int(article_id))
+        if article is None:
+            return JsonResponse({"success": False, "message": "没有找到对应文章"}, safe=False)
+
+        def is_empty(val):
+            return val is None or val == ''
+
+        if is_empty(nick_name):
+            request.session['msg'] = "请填写昵称"
+            return HttpResponseRedirect('/article/' + article_id + '.html')  # 跳转到主界面
+
+        if is_empty(comment):
+            request.session['msg'] = "请填写评论内容"
+            return HttpResponseRedirect('/article/' + article_id + '.html')  # 跳转到主界面
+
+        if is_empty(email):
+            request.session['msg'] = "请填写Email"
+            return HttpResponseRedirect('/article/' + article_id + '.html')  # 跳转到主界面
+
+        request.session['msg'] = ""
+        models.Comment.objects.create(nick_name=nick_name, avatar=avatar, article=article,
+                                                    website=website,
+                                                    comment=comment,
+                                                    created_time=datetime.datetime.now(), email=email)
+        return HttpResponseRedirect('/article/' + article_id + '.html')  # 跳转到主界面
+
+    else:
+        raise ServerException("错误的请求")

+ 0 - 62
blog/migrations/0001_initial.py

@@ -1,62 +0,0 @@
-# Generated by Django 4.2.3 on 2023-07-14 15:58
-
-from django.conf import settings
-from django.db import migrations, models
-import django.db.models.deletion
-
-
-class Migration(migrations.Migration):
-
-    initial = True
-
-    dependencies = [
-        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
-    ]
-
-    operations = [
-        migrations.CreateModel(
-            name='Category',
-            fields=[
-                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
-                ('name', models.CharField(max_length=100, unique=True, verbose_name='分类')),
-            ],
-        ),
-        migrations.CreateModel(
-            name='FileRecord',
-            fields=[
-                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
-                ('origin_name', models.CharField(max_length=200, verbose_name='源文件名称')),
-                ('file_name', models.CharField(max_length=200, verbose_name='文件名称')),
-                ('file_path', models.FilePathField(max_length=255, verbose_name='文件路径')),
-                ('create_date', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
-                ('suffix', models.CharField(max_length=10, verbose_name='文件类型')),
-                ('file_net_path', models.CharField(max_length=200, verbose_name='文件网络路径')),
-            ],
-        ),
-        migrations.CreateModel(
-            name='Tags',
-            fields=[
-                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
-                ('name', models.CharField(max_length=100, unique=True, verbose_name='标签')),
-            ],
-        ),
-        migrations.CreateModel(
-            name='Article',
-            fields=[
-                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
-                ('title', models.CharField(max_length=70, verbose_name='标题')),
-                ('intro', models.TextField(blank=True, max_length=200, verbose_name='摘要')),
-                ('html_text', models.TextField(blank=True)),
-                ('markdown_text', models.TextField(blank=True)),
-                ('created_time', models.DateTimeField(auto_now_add=True, verbose_name='发布时间')),
-                ('type', models.SmallIntegerField(choices=[(1, 'ARTICLE'), (2, 'MUSIC'), (3, 'ESSAY'), (4, 'MEDIA')], default=1, verbose_name='类型')),
-                ('status', models.SmallIntegerField(choices=[(1, 'RELEASE'), (0, 'PADDING'), (-1, 'DELETE')], default=1, verbose_name='状态')),
-                ('is_top', models.BooleanField(default=True, verbose_name='是否在首页显示')),
-                ('category', models.ForeignKey(default='1', on_delete=django.db.models.deletion.CASCADE, to='blog.category', verbose_name='分类')),
-                ('cover', models.ForeignKey(blank=True, default='', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='cover', to='blog.filerecord', verbose_name='封面')),
-                ('music', models.ForeignKey(blank=True, default='', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='music', to='blog.filerecord', verbose_name='音乐路径')),
-                ('tags', models.ManyToManyField(blank=True, to='blog.tags')),
-                ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='作者')),
-            ],
-        ),
-    ]

+ 0 - 18
blog/migrations/0002_rename_is_show_index_article_is_top.py

@@ -1,18 +0,0 @@
-# Generated by Django 4.2.3 on 2023-07-15 02:26
-
-from django.db import migrations
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ('blog', '0001_initial'),
-    ]
-
-    operations = [
-        migrations.RenameField(
-            model_name='article',
-            old_name='is_top',
-            new_name='is_top',
-        ),
-    ]

+ 0 - 18
blog/migrations/0003_category_seq.py

@@ -1,18 +0,0 @@
-# Generated by Django 4.2.3 on 2023-07-16 06:19
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ('blog', '0002_rename_is_show_index_article_is_top'),
-    ]
-
-    operations = [
-        migrations.AddField(
-            model_name='category',
-            name='seq',
-            field=models.IntegerField(default=1, verbose_name='排序'),
-        ),
-    ]

+ 21 - 3
blog/models.py

@@ -1,6 +1,9 @@
-from django.db import models
-from django.contrib.auth.models import User, AbstractUser
+from django.contrib import admin
 from django.contrib.auth import get_user_model as user_model
 from django.contrib.auth import get_user_model as user_model
+from django.contrib.auth.models import User, AbstractUser
+from django.db import models
+
+from blog.admin import CommentAdmin
 
 
 # Create your models here.
 # Create your models here.
 User = user_model()
 User = user_model()
@@ -16,7 +19,7 @@ class Category(models.Model):
     然后给name设置了一个'分类'的名称
     然后给name设置了一个'分类'的名称
     """
     """
     name = models.CharField('分类', max_length=100, unique=True)
     name = models.CharField('分类', max_length=100, unique=True)
-    seq = models.IntegerField('排序',default=1)
+    seq = models.IntegerField('排序', default=1)
 
 
 
 
 class Tags(models.Model):
 class Tags(models.Model):
@@ -70,3 +73,18 @@ class Article(models.Model):
         (-1, "DELETE"))
         (-1, "DELETE"))
     status = models.SmallIntegerField(verbose_name="状态", choices=status_choices, default=1)
     status = models.SmallIntegerField(verbose_name="状态", choices=status_choices, default=1)
     is_top = models.BooleanField(verbose_name="是否在首页显示", default=True)
     is_top = models.BooleanField(verbose_name="是否在首页显示", default=True)
+
+
+class Comment(models.Model):
+    article = models.ForeignKey(Article, on_delete=models.CASCADE, verbose_name='评论', default='1')
+    nick_name = models.CharField('昵称', max_length=100)
+    avatar = models.URLField('头像', max_length=255)
+    website = models.URLField('网址', max_length=100)
+    created_time = models.DateTimeField('创建时间', auto_now_add=True)
+    email = models.EmailField('Email', null=True, blank=True)
+    comment = models.TextField('评论', max_length=500, null=False, blank=False)
+
+
+admin.site.register(Comment, CommentAdmin)  # 注册模型 并 按照定制化的形式展示
+
+admin.site.site_title = 'CyberSick.net'  # 修改title

+ 0 - 0
blog/router/comment_url/__init__.py


+ 27 - 0
blog/router/comment_url/comment_url.py

@@ -0,0 +1,27 @@
+"""IBE URL Configuration
+
+The `urlpatterns` list routes URLs to views. For more information please see:
+    https://docs.djangoproject.com/en/3.2/topics/http/urls/
+Examples:
+Function views
+    1. Add an import:  from my_app import views
+    2. Add a URL to urlpatterns:  path('', views.home, name='home')
+Class-based views
+    1. Add an import:  from other_app.views import Home
+    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
+Including another URLconf
+    1. Import the include() function: from django.urls import include, path
+    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
+"""
+from django.contrib import admin
+from django.contrib.staticfiles.urls import staticfiles_urlpatterns
+from django.urls import path
+from blog import views
+from blog.controller import comment
+
+urlpatterns = [
+    path('add', comment.add_comment),
+
+
+]
+urlpatterns += staticfiles_urlpatterns()

+ 5 - 0
blog/templatetags/day_util.py

@@ -19,3 +19,8 @@ def days_until(date):
     elif (day / 30) >= 1:
     elif (day / 30) >= 1:
         return str(int((day / 30))) + '个月前'
         return str(int((day / 30))) + '个月前'
     return str(day) + '天前'
     return str(day) + '天前'
+
+
+@register.filter
+def get_avatar(name):
+    return f'https://semantic-ui.com/images/avatar/small/{name}.jpg'

+ 5 - 0
blog/templatetags/page_tag.py

@@ -41,3 +41,8 @@ def circle_page_index(curr_page, loop_page):
         return format_html(page_ele)
         return format_html(page_ele)
     else:
     else:
         return ''
         return ''
+
+
+@register.simple_tag
+def find_string(value:str, arg:str):
+    return value.find(arg) > -1

+ 1 - 0
system/urls.py

@@ -32,6 +32,7 @@ urlpatterns = [
     path('index', views.index),
     path('index', views.index),
     path('category/', include('blog.router.category_url.category_url')),
     path('category/', include('blog.router.category_url.category_url')),
     path('article/', include('blog.router.article_url.article_url')),
     path('article/', include('blog.router.article_url.article_url')),
+    path('comment/', include('blog.router.comment_url.comment_url')),
     path('search', views.search),
     path('search', views.search),
     path('date/<date>', views.current_record),
     path('date/<date>', views.current_record),
 
 

+ 121 - 0
templates/blog.html

@@ -211,7 +211,106 @@
             {% autoescape off %}
             {% autoescape off %}
                 {{ article.html_text }}
                 {{ article.html_text }}
             {% endautoescape %}
             {% endautoescape %}
+            <h3 class="ui dividing header" style="margin-top: 10vh">评论</h3>
+            <div class="ui comments">
+                {% for comment in comments %}
+                    <div class="comment">
+                        <a class="avatar">
+                            <img src="{{ comment.avatar | get_avatar }}">
+                        </a>
+                        <div class="content">
+                            <a target="_blank" href="{{ comment.website }}" class="author">{{ comment.nick_name }}</a>
+                            <div class="text">{{ comment.comment }}</div>
+                            <div class="actions">
+                                <a href="mailto:{{ comment.email }}"> <i class="mail icon"></i>联系他</a>
+                                <a>
+                                    <i class="time icon"></i>
+                                    {{ comment.created_time }}
+                                </a>
+                            </div>
+                        </div>
+                    </div>
+
+                {% endfor %}
+
+            </div>
 
 
+            <form onsubmit="save()" method="post" action="/comment/add" id="comment_form" style="margin-top: 10px"
+                  class="ui form">
+                {% csrf_token %}
+                <input hidden="hidden" name="article_id" value="{{ article.id }}">
+                <h4 class="ui dividing header">发表评论</h4>
+
+                <div class="field">
+                    <div class="two fields">
+                        <div class="field">
+                            <label>昵称<span style="color: red">*</span></label>
+                            <input id="nick_name" type="text" name="nick_name" placeholder="昵称">
+                        </div>
+                        <div class="field">
+                            <label>Email<span style="color: red">*</span></label>
+                            <input id="email" type="email" name="email" placeholder="Email">
+                        </div>
+                    </div>
+                </div>
+                <div class="field">
+                    <div class="two fields">
+                        <div class="twelve wide field">
+                            <label>网站(可不填)</label>
+                            <input id="website" type="url" name="website" placeholder="网站">
+                        </div>
+                        <div class="four wide field">
+                            <label>头像<span style="color: red">*</span></label>
+                            <div class="ui fluid selection dropdown">
+                                <input value="jenny" type="hidden" name="avatar">
+                                <i class="dropdown icon"></i>
+                                <div class="default text">
+                                    Jenny Hess
+                                </div>
+                                <div class="menu">
+                                    <div class="item" data-value="jenny">
+                                        <img class="ui mini avatar image"
+                                             src="https://semantic-ui.com/images/avatar/small/jenny.jpg">
+                                        Jenny Hess
+                                    </div>
+                                    <div class="item" data-value="elliot">
+                                        <img class="ui mini avatar image"
+                                             src="https://semantic-ui.com/images/avatar/small/elliot.jpg">
+                                        Elliot Fu
+                                    </div>
+                                    <div class="item" data-value="stevie">
+                                        <img class="ui mini avatar image"
+                                             src="https://semantic-ui.com/images/avatar/small/stevie.jpg">
+                                        Stevie Feliciano
+                                    </div>
+                                    <div class="item" data-value="christian">
+                                        <img class="ui mini avatar image"
+                                             src="https://semantic-ui.com/images/avatar/small/christian.jpg">
+                                        Christian
+                                    </div>
+                                    <div class="item" data-value="matt">
+                                        <img class="ui mini avatar image"
+                                             src="https://semantic-ui.com/images/avatar/small/matt.jpg">
+                                        Matt
+                                    </div>
+                                    <div class="item" data-value="justen">
+                                        <img class="ui mini avatar image"
+                                             src="https://semantic-ui.com/images/avatar/small/justen.jpg">
+                                        Justen Kitsune
+                                    </div>
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+                <div class="field">
+                    <textarea name="comment" placeholder="评论"></textarea>
+                </div>
+                <div style="color: red">{{ msg }}</div>
+                <button class="ui blue labeled submit icon button">
+                    <i class="icon edit"></i> 提交
+                </button>
+            </form>
 
 
             <div class="ui hidden divider"></div>
             <div class="ui hidden divider"></div>
         </div>
         </div>
@@ -268,7 +367,29 @@
 <script src="{% static 'highlightjs/highlight.min.js' %}"></script>
 <script src="{% static 'highlightjs/highlight.min.js' %}"></script>
 <script type="application/javascript" src="{% static 'photoswipe/photoswipe.umd.min.js' %}"></script>
 <script type="application/javascript" src="{% static 'photoswipe/photoswipe.umd.min.js' %}"></script>
 <script type="application/javascript" src="{% static 'photoswipe/photoswipe-lightbox.umd.min.js' %}"></script>
 <script type="application/javascript" src="{% static 'photoswipe/photoswipe-lightbox.umd.min.js' %}"></script>
+<script>
+    restoreComment()
+
+    function restoreComment() {
+        if (localStorage.getItem('nick_name') !== undefined && localStorage.getItem('nick_name') !== '') {
+            $("#nick_name").val(localStorage.getItem('nick_name'))
+        }
+        if (localStorage.getItem('email') !== undefined && localStorage.getItem('email') !== '') {
+            $("#email").val(localStorage.getItem('email'))
+        }
+        if (localStorage.getItem('website') !== undefined && localStorage.getItem('website') !== '') {
+            $("#website").val(localStorage.getItem('website'))
+        }
+    }
 
 
+    function save() {
+        var data = $('#comment_form').serializeArray();
+        localStorage.setItem('nick_name', $('#nick_name').val())
+        localStorage.setItem('email', $('#email').val())
+        localStorage.setItem('website', $('#website').val())
+        return true
+    }
+</script>
 <script>
 <script>
     $(document).ready(function () {
     $(document).ready(function () {
         $(".ui.toggle.button").click(function () {
         $(".ui.toggle.button").click(function () {

+ 15 - 5
templates/index.html

@@ -2,6 +2,7 @@
 {% block css %}
 {% block css %}
     {% load avatar_tags %}
     {% load avatar_tags %}
     {% load day_util %}
     {% load day_util %}
+    {% load page_tag %}
 
 
 {% endblock %}
 {% endblock %}
 {% block container %}
 {% block container %}
@@ -45,11 +46,20 @@
                                             {{ item.user__first_name }}{{ item.user__last_name }}</a>
                                             {{ item.user__first_name }}{{ item.user__last_name }}</a>
                                             发布了{{ item.category__name }}:<a
                                             发布了{{ item.category__name }}:<a
                                                     href="/article/{{ item.id }}.html">{{ item.title }}</a></div>
                                                     href="/article/{{ item.id }}.html">{{ item.title }}</a></div>
-                                        {% autoescape off %}
-                                            <div class="extra images">
-                                                {{ item.html_text }}
-                                            </div>
-                                        {% endautoescape %}
+                                        {% if '<iframe' in item.intro %}
+                                            {% autoescape off %}
+                                                <div class="extra images">
+                                                    {{ item.intro }}
+                                                </div>
+                                            {% endautoescape %}
+                                        {% else %}
+                                            {% autoescape off %}
+                                                <div class="extra images">
+                                                    {{ item.html_text }}
+                                                </div>
+                                            {% endautoescape %}
+                                        {% endif %}
+
 
 
                                     </div>
                                     </div>