1.2.1更新,详情请看readme.md
This commit is contained in:
parent
796302a954
commit
fb69ea4172
Binary file not shown.
@ -34,6 +34,7 @@ INSTALLED_APPS = [
|
||||
'simpleui',
|
||||
'home',
|
||||
'api',
|
||||
'comment',
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
|
12
README.md
12
README.md
@ -6,10 +6,12 @@
|
||||
# 目录结构描述
|
||||
├── ReadMe.md // 帮助文档
|
||||
|
||||
├── home // 首页app
|
||||
├── home // 文章相关app
|
||||
|
||||
├── api // 项目api
|
||||
|
||||
├── comment // 评论app
|
||||
|
||||
└── Echo-Z // 项目配置等目录
|
||||
|
||||
# 使用说明
|
||||
@ -35,3 +37,11 @@ python manage.py runserver 9999
|
||||
###### 1.2.0
|
||||
2025年6月19日
|
||||
完成文章的基础管理、文章的列表显示、文章的详细信息的功能编写,功能有待完善
|
||||
|
||||
###### 1.2.1
|
||||
2025年6月23日
|
||||
新增
|
||||
1.文章详情页上一篇、下一篇功能
|
||||
2.文章详情页评论列表显示
|
||||
3.文章详情页评论发布
|
||||
4.文章详情页点赞与取消点赞
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
api/__pycache__/views.cpython-39.pyc
Normal file
BIN
api/__pycache__/views.cpython-39.pyc
Normal file
Binary file not shown.
@ -1,6 +1,9 @@
|
||||
from django.contrib import admin
|
||||
from django.urls import path
|
||||
|
||||
from . import views as api_views
|
||||
urlpatterns = [
|
||||
|
||||
path('create_comment/<id>', api_views.add_comment),
|
||||
path('link/<id>/<uuid>', api_views.like),
|
||||
path('unlink/<id>/<uuid>', api_views.un_like),
|
||||
path('check_like/<id>/<uuid>', api_views.check_like),
|
||||
]
|
45
api/views.py
45
api/views.py
@ -1,3 +1,46 @@
|
||||
from django.shortcuts import render
|
||||
from datetime import datetime
|
||||
|
||||
from django.shortcuts import render,HttpResponse
|
||||
from django.http import JsonResponse,HttpResponseNotAllowed,HttpResponseRedirect,JsonResponse
|
||||
from django.views.decorators.http import require_http_methods
|
||||
|
||||
from comment.models import comment
|
||||
from home.models import *
|
||||
# Create your views here.
|
||||
|
||||
@require_http_methods(["POST"])
|
||||
def add_comment(request, id):
|
||||
create_comment = comment.objects.create(comment_Content=request.POST.get("comment"),comment_User=request.POST.get("username"), comment_Time=datetime.now(), archives_Id=id, qq=request.POST.get("qqNum"))
|
||||
create_comment.save()
|
||||
return HttpResponseRedirect("/archives/"+id)
|
||||
|
||||
@require_http_methods(["POST"])
|
||||
def check_like(request, id, uuid):
|
||||
articles_likes = ArticlesLike.objects.filter(articles_id=id,uuid=uuid)
|
||||
if articles_likes:
|
||||
return JsonResponse({"liked":True})
|
||||
else:
|
||||
return JsonResponse({"liked":False})
|
||||
|
||||
@require_http_methods(["POST"])
|
||||
def like(request, id, uuid):
|
||||
article_stat = 0
|
||||
if not ArticlesLike.objects.filter(articles_id=id, uuid=uuid):
|
||||
ArticlesLike.objects.create(articles_id=id, uuid=uuid)
|
||||
article = Articles.objects.get(id=id)
|
||||
article.stat += 1
|
||||
article_stat = article.stat
|
||||
article.save()
|
||||
return JsonResponse({"success":True,"new_count": article_stat})
|
||||
|
||||
@require_http_methods(["POST"])
|
||||
def un_like(request,id, uuid):
|
||||
article_stat = 0
|
||||
if ArticlesLike.objects.filter(articles_id=id, uuid=uuid):
|
||||
ArticlesLike.objects.filter(articles_id=id, uuid=uuid).delete()
|
||||
article = Articles.objects.get(id=id)
|
||||
article.stat -= 1
|
||||
article_stat = article.stat
|
||||
article.save()
|
||||
|
||||
return JsonResponse({"success":True,"new_count": article_stat})
|
||||
|
0
comment/__init__.py
Normal file
0
comment/__init__.py
Normal file
BIN
comment/__pycache__/__init__.cpython-39.pyc
Normal file
BIN
comment/__pycache__/__init__.cpython-39.pyc
Normal file
Binary file not shown.
BIN
comment/__pycache__/admin.cpython-39.pyc
Normal file
BIN
comment/__pycache__/admin.cpython-39.pyc
Normal file
Binary file not shown.
BIN
comment/__pycache__/apps.cpython-39.pyc
Normal file
BIN
comment/__pycache__/apps.cpython-39.pyc
Normal file
Binary file not shown.
BIN
comment/__pycache__/models.cpython-39.pyc
Normal file
BIN
comment/__pycache__/models.cpython-39.pyc
Normal file
Binary file not shown.
7
comment/admin.py
Normal file
7
comment/admin.py
Normal file
@ -0,0 +1,7 @@
|
||||
from django.contrib import admin
|
||||
from comment.models import comment
|
||||
# Register your models here.
|
||||
|
||||
@admin.register(comment)
|
||||
class CommentAdmin(admin.ModelAdmin):
|
||||
list_display = ["comment_Content","comment_User","comment_Time", "archives_Id"]
|
7
comment/apps.py
Normal file
7
comment/apps.py
Normal file
@ -0,0 +1,7 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class CommentConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'comment'
|
||||
verbose_name = "评论"
|
27
comment/migrations/0001_initial.py
Normal file
27
comment/migrations/0001_initial.py
Normal file
@ -0,0 +1,27 @@
|
||||
# Generated by Django 4.2.23 on 2025-06-20 02:43
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='comment',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('comment_Content', models.TextField(verbose_name='评论内容')),
|
||||
('comment_User', models.CharField(max_length=100, verbose_name='评论者')),
|
||||
('comment_Time', models.DateTimeField(verbose_name='评论时间')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '评论',
|
||||
'verbose_name_plural': '评论管理',
|
||||
},
|
||||
),
|
||||
]
|
18
comment/migrations/0002_comment_archives_id.py
Normal file
18
comment/migrations/0002_comment_archives_id.py
Normal file
@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.2.23 on 2025-06-20 03:01
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('comment', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='comment',
|
||||
name='archives_Id',
|
||||
field=models.IntegerField(default=0, verbose_name='文章idßß'),
|
||||
),
|
||||
]
|
@ -0,0 +1,23 @@
|
||||
# Generated by Django 4.2.23 on 2025-06-20 04:53
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('comment', '0002_comment_archives_id'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='comment',
|
||||
name='qq',
|
||||
field=models.IntegerField(default=1000, verbose_name='评论者qq号'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='comment',
|
||||
name='archives_Id',
|
||||
field=models.IntegerField(default=0, verbose_name='文章id'),
|
||||
),
|
||||
]
|
0
comment/migrations/__init__.py
Normal file
0
comment/migrations/__init__.py
Normal file
BIN
comment/migrations/__pycache__/0001_initial.cpython-39.pyc
Normal file
BIN
comment/migrations/__pycache__/0001_initial.cpython-39.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
comment/migrations/__pycache__/__init__.cpython-39.pyc
Normal file
BIN
comment/migrations/__pycache__/__init__.cpython-39.pyc
Normal file
Binary file not shown.
16
comment/models.py
Normal file
16
comment/models.py
Normal file
@ -0,0 +1,16 @@
|
||||
from django.db import models
|
||||
|
||||
# Create your models here.
|
||||
class comment(models.Model):
|
||||
comment_Content = models.TextField(verbose_name="评论内容")
|
||||
comment_User = models.CharField(max_length=100,verbose_name="评论者")
|
||||
comment_Time = models.DateTimeField(verbose_name="评论时间")
|
||||
archives_Id = models.IntegerField(default=0, verbose_name="文章id")
|
||||
qq = models.IntegerField(default=1000, verbose_name="评论者qq号")
|
||||
|
||||
def __str__(self):
|
||||
return self.comment_content
|
||||
|
||||
class Meta:
|
||||
verbose_name = "评论"
|
||||
verbose_name_plural = "评论管理"
|
3
comment/tests.py
Normal file
3
comment/tests.py
Normal file
@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
4
comment/views.py
Normal file
4
comment/views.py
Normal file
@ -0,0 +1,4 @@
|
||||
from django.shortcuts import render
|
||||
|
||||
# Create your views here.
|
||||
|
BIN
db.sqlite3
BIN
db.sqlite3
Binary file not shown.
BIN
home/.DS_Store
vendored
Normal file
BIN
home/.DS_Store
vendored
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,10 +1,9 @@
|
||||
from django.contrib import admin
|
||||
|
||||
from home.models import articles
|
||||
|
||||
from home.models import *
|
||||
|
||||
# Register your models here.
|
||||
@admin.register(articles)
|
||||
@admin.register(Articles)
|
||||
class DepartmentAdmin(admin.ModelAdmin):
|
||||
# 要显示的字段
|
||||
list_display = ('title', 'abstract', 'created','stat')
|
||||
@ -14,4 +13,13 @@ class DepartmentAdmin(admin.ModelAdmin):
|
||||
# 分页显示,一页的数量
|
||||
list_per_page = 10
|
||||
|
||||
actions_on_top = True
|
||||
|
||||
@admin.register(ArticlesLike)
|
||||
class ArticlesLikeAdmin(admin.ModelAdmin):
|
||||
list_display = ('articles_id', 'uuid')
|
||||
readonly_fields = ('articles_id', 'uuid')
|
||||
# 分页显示,一页的数量
|
||||
list_per_page = 10
|
||||
|
||||
actions_on_top = True
|
@ -4,4 +4,4 @@ from django.apps import AppConfig
|
||||
class HomeConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'home'
|
||||
verbose_name = "文章管理"
|
||||
verbose_name = "文章"
|
||||
|
25
home/migrations/0005_articleslike.py
Normal file
25
home/migrations/0005_articleslike.py
Normal file
@ -0,0 +1,25 @@
|
||||
# Generated by Django 4.2.23 on 2025-06-22 18:14
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('home', '0004_articles_author'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='ArticlesLike',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('articles_id', models.IntegerField(default=0, verbose_name='文章id')),
|
||||
('uuid', models.CharField(max_length=100, verbose_name='点赞用户标识')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '点赞',
|
||||
'verbose_name_plural': '点赞管理',
|
||||
},
|
||||
),
|
||||
]
|
BIN
home/migrations/__pycache__/0005_articleslike.cpython-39.pyc
Normal file
BIN
home/migrations/__pycache__/0005_articleslike.cpython-39.pyc
Normal file
Binary file not shown.
@ -2,7 +2,7 @@ from django.db import models
|
||||
|
||||
# Create your models here.
|
||||
|
||||
class articles(models.Model):
|
||||
class Articles(models.Model):
|
||||
title = models.CharField(max_length=100,verbose_name="文章标题")
|
||||
content = models.TextField(verbose_name="文章内容")
|
||||
abstract = models.TextField(verbose_name="文章摘要")
|
||||
@ -20,3 +20,13 @@ class articles(models.Model):
|
||||
def __str__(self):
|
||||
return self.title
|
||||
|
||||
class ArticlesLike(models.Model):
|
||||
articles_id = models.IntegerField(default=0,verbose_name="文章id")
|
||||
uuid = models.CharField(max_length=100,verbose_name="点赞用户标识")
|
||||
|
||||
class Meta:
|
||||
verbose_name = "点赞"
|
||||
verbose_name_plural = "点赞管理"
|
||||
|
||||
def __str__(self):
|
||||
return self.uuid
|
12
home/static/aaa.js
Normal file
12
home/static/aaa.js
Normal file
File diff suppressed because one or more lines are too long
@ -41,6 +41,15 @@
|
||||
color: #bbb;
|
||||
}
|
||||
|
||||
.article-like {
|
||||
margin: 20px 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.link {
|
||||
margin: 4px;
|
||||
}
|
||||
|
||||
/* 文章封面图 */
|
||||
.article-cover {
|
||||
margin: 30px 0;
|
||||
@ -267,6 +276,12 @@
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 20px;
|
||||
|
||||
}
|
||||
.form-group {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.comment-form textarea {
|
||||
@ -285,6 +300,16 @@
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.form-group > .comment-input {
|
||||
width: 49.5%;
|
||||
height: 30px;
|
||||
border: 1px solid #eee;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 10px;
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
|
||||
.submit-btn {
|
||||
background-color: #3498db;
|
||||
color: #fff;
|
||||
|
6
home/static/marked.min.js
vendored
Normal file
6
home/static/marked.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -2,8 +2,12 @@
|
||||
{% load static %}
|
||||
|
||||
{#文章详情#}
|
||||
{% block sitename %}
|
||||
<title>{{ title }}-我的个人博客</title>
|
||||
{% endblock %}
|
||||
{% block stylesheethref %}
|
||||
<link rel="stylesheet" href="{% static 'archives.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'archives.css' %}">
|
||||
<script src="{% static 'marked.min.js' %}"></script>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div class="article-detail-container">
|
||||
@ -13,24 +17,21 @@
|
||||
<h1 class="article-title">{{ title }}</h1>
|
||||
<div class="article-meta">
|
||||
<span class="author">
|
||||
<i class="fas fa-user"></i>
|
||||
{{ author }}
|
||||
作者 {{ author }}
|
||||
</span>
|
||||
<span class="date">
|
||||
<i class="fas fa-calendar-alt"></i>
|
||||
{{ created|date:"Y-m-d" }}
|
||||
发布时间 {{ created|date:"Y-m-d" }}
|
||||
</span>
|
||||
<span class="category">
|
||||
<i class="fas fa-folder"></i>
|
||||
{{ article.category }}
|
||||
分类
|
||||
{{ stat }} 点赞
|
||||
|
||||
</span>
|
||||
<span class="views">
|
||||
<i class="fas fa-eye"></i>
|
||||
{{ read }} 浏览
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="article-cover">
|
||||
<img src="http://iph.href.lu/200x150?text=封面功能,正在开发中" alt="{{ title }}封面图">
|
||||
</div>
|
||||
@ -39,6 +40,145 @@
|
||||
<div class="article-content">
|
||||
{{ content|safe }}
|
||||
</div>
|
||||
<div class="dz" style="width: 42px;height: 42px;margin: 0 auto">
|
||||
<div class="dz-icon" id="likeBtn" style="background-color: red;width: 42px;height: 42px;border-radius: 50%">
|
||||
<div>
|
||||
<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="38" height="38" style="margin: 2px">
|
||||
<path id="link_svg" d="M512 928c-28.928 0-57.92-12.672-86.624-41.376L106.272 564C68.064 516.352 32 471.328 32 384c0-141.152 114.848-256 256-256 53.088 0 104 16.096 147.296 46.592 14.432 10.176 17.92 30.144 7.712 44.608-10.176 14.432-30.08 17.92-44.608 7.712C366.016 204.064 327.808 192 288 192c-105.888 0-192 86.112-192 192 0 61.408 20.288 90.112 59.168 138.688l315.584 318.816C486.72 857.472 499.616 863.808 512 864c12.704.192 24.928-6.176 41.376-22.624l316.672-319.904C896.064 493.28 928 445.696 928 384c0-105.888-86.112-192-192-192-48.064 0-94.08 17.856-129.536 50.272l-134.08 134.112c-12.512 12.512-32.736 12.512-45.248 0s-12.512-32.736 0-45.248L562.24 196c48.32-44.192 109.664-68 173.76-68 141.152 0 256 114.848 256 256 0 82.368-41.152 144.288-75.68 181.696l-317.568 320.8C569.952 915.328 540.96 928 512 928z" fill="#fff"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<p style="text-align: center" id="likeCount">{{ stat }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
<!-- 文章导航 -->
|
||||
<nav class="article-nav">
|
||||
{% if previous %}
|
||||
<a href="/archives/{{ previous.id }}" class="prev">
|
||||
<i class="fas fa-chevron-left"></i>
|
||||
上一篇: {{ previous.title }}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if next %}
|
||||
<a href="/archives/{{ next.id }}" class="next">
|
||||
下一篇: {{ next.title }}
|
||||
<i class="fas fa-chevron-right"></i>
|
||||
</a>
|
||||
{% endif %}
|
||||
</nav>
|
||||
<!-- 评论区域 -->
|
||||
<section class="comment-section">
|
||||
<h3 class="section-title">评论</h3>
|
||||
<div class="comment-form">
|
||||
<form id="comment-form" action="/api/create_comment/{{ id }}" method="post">
|
||||
{% csrf_token %}
|
||||
<div class="form-group">
|
||||
<input name="username" class="comment-input" placeholder="昵称">
|
||||
<input name="qqNum" class="comment-input" placeholder="qq号(仅用于头像显示)">
|
||||
<textarea name="comment" rows="5" placeholder="写下你的评论..."></textarea>
|
||||
</div>
|
||||
<button type="submit" class="submit-btn">提交评论</button>
|
||||
</form>
|
||||
</div>
|
||||
<div class="comment-list">
|
||||
{% for comment in comments %}
|
||||
<div class="comment-item">
|
||||
<div class="comment-avatar">
|
||||
<img src="http://q1.qlogo.cn/g?b=qq&nk={{ comment.qq }}&s=100" alt="用户头像">
|
||||
</div>
|
||||
<div class="comment-content">
|
||||
<div class="comment-header">
|
||||
<span class="comment-user">{{ comment.comment_User }}</span>
|
||||
<span class="comment-time">{{ comment.comment_Time|timesince }}</span>
|
||||
</div>
|
||||
<p>{{ comment.comment_Content }}</p>
|
||||
{% if comment.replies.all %}
|
||||
<div class="comment-replies">
|
||||
{% for reply in comment.replies.all %}
|
||||
<div class="reply-item">
|
||||
<div class="reply-avatar">
|
||||
<img src="{{ reply.user.profile.avatar.url|default:'https://via.placeholder.com/40' }}" alt="用户头像">
|
||||
</div>
|
||||
<div class="reply-content">
|
||||
<div class="reply-header">
|
||||
<span class="reply-user">{{ reply.user.username }}</span>
|
||||
<span class="reply-time">{{ reply.created_at|timesince }}前</span>
|
||||
</div>
|
||||
<p>{{ reply.content }}</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% empty %}
|
||||
<div class="no-comments">暂无评论,快来抢沙发吧~</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block script %}
|
||||
const no_active_path = "M512 928c-28.928 0-57.92-12.672-86.624-41.376L106.272 564C68.064 516.352 32 471.328 32 384c0-141.152 114.848-256 256-256 53.088 0 104 16.096 147.296 46.592 14.432 10.176 17.92 30.144 7.712 44.608-10.176 14.432-30.08 17.92-44.608 7.712C366.016 204.064 327.808 192 288 192c-105.888 0-192 86.112-192 192 0 61.408 20.288 90.112 59.168 138.688l315.584 318.816C486.72 857.472 499.616 863.808 512 864c12.704.192 24.928-6.176 41.376-22.624l316.672-319.904C896.064 493.28 928 445.696 928 384c0-105.888-86.112-192-192-192-48.064 0-94.08 17.856-129.536 50.272l-134.08 134.112c-12.512 12.512-32.736 12.512-45.248 0s-12.512-32.736 0-45.248L562.24 196c48.32-44.192 109.664-68 173.76-68 141.152 0 256 114.848 256 256 0 82.368-41.152 144.288-75.68 181.696l-317.568 320.8C569.952 915.328 540.96 928 512 928z"
|
||||
const active_path = "M736 128c-65.952 0-128.576 25.024-176.384 70.464-4.576 4.32-28.672 28.736-47.328 47.68L464.96 199.04C417.12 153.216 354.272 128 288 128 146.848 128 32 242.848 32 384c0 82.432 41.184 144.288 76.48 182.496l316.896 320.128C450.464 911.68 478.304 928 512 928s61.568-16.32 86.752-41.504l316.736-320 2.208-2.464C955.904 516.384 992 471.392 992 384c0-141.152-114.848-256-256-256z"
|
||||
const path = document.getElementById('link_svg');
|
||||
|
||||
const fpPromise = import('{% static "aaa.js" %}').then(FingerprintJS => FingerprintJS.load());
|
||||
fpPromise.then(fp => fp.get()).then(result => {localStorage.setItem("uuid",result.visitorId)});
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const likeBtn = document.getElementsByClassName('dz')[0];
|
||||
if (!likeBtn) return;
|
||||
fetch(`/api/check_like/{{ id }}/${localStorage.getItem("uuid")}`,{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-CSRFToken': '{{ csrf_token }}'
|
||||
},
|
||||
credentials: 'include'
|
||||
}).then(response => response.json()).then(data => {
|
||||
if (data.liked) {
|
||||
path.setAttribute('d', active_path)
|
||||
likeBtn.classList.add('active');
|
||||
}
|
||||
});
|
||||
const dz_icon = document.getElementsByClassName('dz-icon')[0];
|
||||
dz_icon.addEventListener('click', function() {
|
||||
if (likeBtn.classList.contains('active')) {
|
||||
fetch(`/api/unlink/{{ id }}/${localStorage.getItem("uuid")}`,{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-CSRFToken': '{{ csrf_token }}'
|
||||
},
|
||||
credentials: 'include'
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
likeBtn.classList.remove('active');
|
||||
path.setAttribute('d', no_active_path)
|
||||
document.getElementById('likeCount').textContent = data.new_count;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
fetch(`/api/link/{{ id }}/${localStorage.getItem("uuid")}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-CSRFToken': '{{ csrf_token }}'
|
||||
},
|
||||
credentials: 'include'
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
likeBtn.classList.add('active');
|
||||
path.setAttribute('d', active_path)
|
||||
document.getElementById('likeCount').textContent = data.new_count;
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
{% endblock %}
|
@ -4,7 +4,9 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>我的个人博客</title>
|
||||
{% block sitename %}
|
||||
<title>我的个人博客</title>
|
||||
{% endblock %}
|
||||
<link rel="stylesheet" href="{% static 'bottom.css' %}">
|
||||
{% block stylesheethref %}
|
||||
{% endblock %}
|
||||
@ -92,40 +94,8 @@
|
||||
|
||||
<!-- 简单的交互功能 -->
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// 搜索功能
|
||||
const searchBtn = document.querySelector('.search-box button');
|
||||
const searchInput = document.querySelector('.search-box input');
|
||||
|
||||
searchBtn.addEventListener('click', function() {
|
||||
const query = searchInput.value.trim();
|
||||
if (query) {
|
||||
alert('搜索: ' + query);
|
||||
// 实际应用中这里应该是跳转到搜索页面或执行搜索操作
|
||||
}
|
||||
});
|
||||
|
||||
searchInput.addEventListener('keypress', function(e) {
|
||||
if (e.key === 'Enter') {
|
||||
const query = searchInput.value.trim();
|
||||
if (query) {
|
||||
alert('搜索: ' + query);
|
||||
// 实际应用中这里应该是跳转到搜索页面或执行搜索操作
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 文章卡片交互
|
||||
const articleCards = document.querySelectorAll('.article-card');
|
||||
articleCards.forEach(card => {
|
||||
card.addEventListener('click', function(e) {
|
||||
if (!e.target.closest('.read-more')) {
|
||||
const id = this.querySelector('.article-id').textContent;
|
||||
window.open(`./archives/${id}`)
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
{% block script %}
|
||||
{% endblock %}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -34,4 +34,40 @@
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block script %}
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// 搜索功能
|
||||
const searchBtn = document.querySelector('.search-box button');
|
||||
const searchInput = document.querySelector('.search-box input');
|
||||
|
||||
searchBtn.addEventListener('click', function() {
|
||||
const query = searchInput.value.trim();
|
||||
if (query) {
|
||||
alert('搜索: ' + query);
|
||||
// 实际应用中这里应该是跳转到搜索页面或执行搜索操作
|
||||
}
|
||||
});
|
||||
|
||||
searchInput.addEventListener('keypress', function(e) {
|
||||
if (e.key === 'Enter') {
|
||||
const query = searchInput.value.trim();
|
||||
if (query) {
|
||||
alert('搜索: ' + query);
|
||||
// 实际应用中这里应该是跳转到搜索页面或执行搜索操作
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 文章卡片交互
|
||||
const articleCards = document.querySelectorAll('.article-card');
|
||||
articleCards.forEach(card => {
|
||||
card.addEventListener('click', function(e) {
|
||||
if (!e.target.closest('.read-more')) {
|
||||
const id = this.querySelector('.article-id').textContent;
|
||||
window.open(`/archives/${id}`)
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
{% endblock %}
|
@ -1,11 +1,12 @@
|
||||
from django.shortcuts import render, HttpResponse
|
||||
from . import models
|
||||
from home.models import *
|
||||
from comment.models import comment
|
||||
# Create your views here.
|
||||
|
||||
def index(request):
|
||||
artchle = models.articles.objects.all()
|
||||
artchle = Articles.objects.all()
|
||||
|
||||
artchles = {"artchles": []}
|
||||
print(artchle)
|
||||
for i in artchle:
|
||||
a = {
|
||||
"id":i.id,
|
||||
@ -17,13 +18,19 @@ def index(request):
|
||||
}
|
||||
artchles["artchles"].append(a)
|
||||
return render(request, 'index.html', context=artchles)
|
||||
# return HttpResponse("Hello, world. You're at the polls index.")
|
||||
|
||||
|
||||
def archives(request, id):
|
||||
i = models.articles.objects.get(id=id)
|
||||
i = Articles.objects.get(id=id)
|
||||
i.read += 1
|
||||
i.save()
|
||||
previous_article = Articles.objects.filter(id__lt=id).order_by('-id').first()
|
||||
previous_id = previous_article.id if previous_article else id
|
||||
previous_id_title = previous_article.title if previous_article else "暂无上一篇"
|
||||
next_article = Articles.objects.filter(id__gt=id).order_by('id').first()
|
||||
next_id = next_article.id if next_article else id
|
||||
next_id_title = next_article.title if next_article else "暂无下一篇"
|
||||
comments = comment.objects.filter(archives_Id=id).order_by("-comment_Time").all()
|
||||
a = {
|
||||
"id": i.id,
|
||||
"title": i.title,
|
||||
@ -32,6 +39,22 @@ def archives(request, id):
|
||||
"stat": i.stat,
|
||||
"read": i.read,
|
||||
"content": i.content,
|
||||
"author": i.author
|
||||
"author": i.author,
|
||||
"previous":{
|
||||
"id": previous_id,
|
||||
"title": previous_id_title,
|
||||
},"next":{
|
||||
"id": next_id,
|
||||
"title": next_id_title,
|
||||
},"comments": []
|
||||
}
|
||||
for c in comments:
|
||||
com = {
|
||||
"id": c.id,
|
||||
"comment_Content": c.comment_Content,
|
||||
"comment_User": c.comment_User,
|
||||
"comment_Time": c.comment_Time,
|
||||
"qq": c.qq,
|
||||
}
|
||||
a["comments"].append(com)
|
||||
return render(request, 'archives.html', a)
|
15
requirements.txt
Normal file
15
requirements.txt
Normal file
@ -0,0 +1,15 @@
|
||||
asgiref==3.8.1
|
||||
diff-match-patch==20241021
|
||||
Django==4.2.23
|
||||
django-import-export==4.3.7
|
||||
django-mdeditor==0.1.20
|
||||
django-simpleui==2025.5.262
|
||||
docutils==0.21.2
|
||||
importlib_metadata==8.7.0
|
||||
Markdown==3.8
|
||||
pillow==11.2.1
|
||||
Pygments==2.19.1
|
||||
sqlparse==0.5.3
|
||||
tablib==3.8.0
|
||||
typing_extensions==4.14.0
|
||||
zipp==3.23.0
|
Loading…
x
Reference in New Issue
Block a user