完成了基本的博客功能编写
This commit is contained in:
parent
66892199f1
commit
796302a954
Binary file not shown.
Binary file not shown.
@ -32,6 +32,8 @@ ALLOWED_HOSTS = []
|
||||
|
||||
INSTALLED_APPS = [
|
||||
'simpleui',
|
||||
'home',
|
||||
'api',
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
@ -104,8 +106,8 @@ AUTH_PASSWORD_VALIDATORS = [
|
||||
# Internationalization
|
||||
# https://docs.djangoproject.com/en/4.2/topics/i18n/
|
||||
|
||||
LANGUAGE_CODE = 'en-us'
|
||||
|
||||
# LANGUAGE_CODE = 'en-us'
|
||||
LANGUAGE_CODE = 'zh-hans'
|
||||
TIME_ZONE = 'UTC'
|
||||
|
||||
USE_I18N = True
|
||||
@ -122,3 +124,12 @@ STATIC_URL = 'static/'
|
||||
# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field
|
||||
|
||||
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
||||
|
||||
SIMPLEUI_CONFIG = {
|
||||
'system_keep': True,
|
||||
'menus': [{
|
||||
'name': '开源地址',
|
||||
'icon': 'fas fa-code',
|
||||
'url': 'https://git.zxqblog.cn/xqz_admin/Echo_Z'
|
||||
}],
|
||||
}
|
@ -1,22 +1,11 @@
|
||||
"""
|
||||
URL configuration for Echo_Z project.
|
||||
|
||||
The `urlpatterns` list routes URLs to views. For more information please see:
|
||||
https://docs.djangoproject.com/en/4.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.urls import path
|
||||
from django.urls import path,include
|
||||
|
||||
admin.site.site_title = 'Echo-Z'
|
||||
admin.site.site_header = '后台管理'
|
||||
|
||||
urlpatterns = [
|
||||
path('admin/', admin.site.urls),
|
||||
path('api/', include('api.urls')),
|
||||
path('', include('home.urls')),
|
||||
]
|
||||
|
@ -32,3 +32,6 @@ python manage.py runserver 9999
|
||||
2025年6月19
|
||||
项目建立
|
||||
|
||||
###### 1.2.0
|
||||
2025年6月19日
|
||||
完成文章的基础管理、文章的列表显示、文章的详细信息的功能编写,功能有待完善
|
||||
|
0
api/__init__.py
Normal file
0
api/__init__.py
Normal file
BIN
api/__pycache__/__init__.cpython-39.pyc
Normal file
BIN
api/__pycache__/__init__.cpython-39.pyc
Normal file
Binary file not shown.
BIN
api/__pycache__/admin.cpython-39.pyc
Normal file
BIN
api/__pycache__/admin.cpython-39.pyc
Normal file
Binary file not shown.
BIN
api/__pycache__/apps.cpython-39.pyc
Normal file
BIN
api/__pycache__/apps.cpython-39.pyc
Normal file
Binary file not shown.
BIN
api/__pycache__/models.cpython-39.pyc
Normal file
BIN
api/__pycache__/models.cpython-39.pyc
Normal file
Binary file not shown.
BIN
api/__pycache__/urls.cpython-39.pyc
Normal file
BIN
api/__pycache__/urls.cpython-39.pyc
Normal file
Binary file not shown.
3
api/admin.py
Normal file
3
api/admin.py
Normal file
@ -0,0 +1,3 @@
|
||||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
6
api/apps.py
Normal file
6
api/apps.py
Normal file
@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class ApiConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'api'
|
0
api/migrations/__init__.py
Normal file
0
api/migrations/__init__.py
Normal file
BIN
api/migrations/__pycache__/__init__.cpython-39.pyc
Normal file
BIN
api/migrations/__pycache__/__init__.cpython-39.pyc
Normal file
Binary file not shown.
3
api/models.py
Normal file
3
api/models.py
Normal file
@ -0,0 +1,3 @@
|
||||
from django.db import models
|
||||
|
||||
# Create your models here.
|
3
api/tests.py
Normal file
3
api/tests.py
Normal file
@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
6
api/urls.py
Normal file
6
api/urls.py
Normal file
@ -0,0 +1,6 @@
|
||||
from django.contrib import admin
|
||||
from django.urls import path
|
||||
|
||||
urlpatterns = [
|
||||
|
||||
]
|
3
api/views.py
Normal file
3
api/views.py
Normal file
@ -0,0 +1,3 @@
|
||||
from django.shortcuts import render
|
||||
|
||||
# Create your views here.
|
BIN
db.sqlite3
BIN
db.sqlite3
Binary file not shown.
BIN
home/__pycache__/__init__.cpython-39.pyc
Normal file
BIN
home/__pycache__/__init__.cpython-39.pyc
Normal file
Binary file not shown.
BIN
home/__pycache__/admin.cpython-39.pyc
Normal file
BIN
home/__pycache__/admin.cpython-39.pyc
Normal file
Binary file not shown.
BIN
home/__pycache__/apps.cpython-39.pyc
Normal file
BIN
home/__pycache__/apps.cpython-39.pyc
Normal file
Binary file not shown.
BIN
home/__pycache__/models.cpython-39.pyc
Normal file
BIN
home/__pycache__/models.cpython-39.pyc
Normal file
Binary file not shown.
BIN
home/__pycache__/urls.cpython-39.pyc
Normal file
BIN
home/__pycache__/urls.cpython-39.pyc
Normal file
Binary file not shown.
BIN
home/__pycache__/views.cpython-39.pyc
Normal file
BIN
home/__pycache__/views.cpython-39.pyc
Normal file
Binary file not shown.
@ -1,3 +1,17 @@
|
||||
from django.contrib import admin
|
||||
|
||||
from home.models import articles
|
||||
|
||||
|
||||
# Register your models here.
|
||||
@admin.register(articles)
|
||||
class DepartmentAdmin(admin.ModelAdmin):
|
||||
# 要显示的字段
|
||||
list_display = ('title', 'abstract', 'created','stat')
|
||||
search_fields = ('title','abstract',)
|
||||
# 不可编辑字段
|
||||
readonly_fields = ('stat','read')
|
||||
# 分页显示,一页的数量
|
||||
list_per_page = 10
|
||||
|
||||
actions_on_top = True
|
@ -4,3 +4,4 @@ from django.apps import AppConfig
|
||||
class HomeConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'home'
|
||||
verbose_name = "文章管理"
|
||||
|
25
home/migrations/0001_initial.py
Normal file
25
home/migrations/0001_initial.py
Normal file
@ -0,0 +1,25 @@
|
||||
# Generated by Django 4.2.23 on 2025-06-19 03:17
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='articles',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('title', models.CharField(max_length=100, verbose_name='文章标题')),
|
||||
('content', models.TextField(verbose_name='文章内容')),
|
||||
('abstract', models.TextField(verbose_name='文章摘要')),
|
||||
('created', models.DateTimeField(auto_now_add=True, verbose_name='发布时间')),
|
||||
('stat', models.IntegerField(default=False, verbose_name='点赞数量')),
|
||||
],
|
||||
),
|
||||
]
|
18
home/migrations/0002_alter_articles_created.py
Normal file
18
home/migrations/0002_alter_articles_created.py
Normal file
@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.2.23 on 2025-06-19 03:20
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('home', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='articles',
|
||||
name='created',
|
||||
field=models.DateTimeField(verbose_name='发布时间'),
|
||||
),
|
||||
]
|
22
home/migrations/0003_alter_articles_options_articles_read.py
Normal file
22
home/migrations/0003_alter_articles_options_articles_read.py
Normal file
@ -0,0 +1,22 @@
|
||||
# Generated by Django 4.2.23 on 2025-06-19 07:24
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('home', '0002_alter_articles_created'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='articles',
|
||||
options={'verbose_name': '文章', 'verbose_name_plural': '文章管理'},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='articles',
|
||||
name='read',
|
||||
field=models.IntegerField(default=0, verbose_name='阅读数量'),
|
||||
),
|
||||
]
|
18
home/migrations/0004_articles_author.py
Normal file
18
home/migrations/0004_articles_author.py
Normal file
@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.2.23 on 2025-06-19 08:54
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('home', '0003_alter_articles_options_articles_read'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='articles',
|
||||
name='author',
|
||||
field=models.TextField(default='admin', verbose_name='文章作者'),
|
||||
),
|
||||
]
|
BIN
home/migrations/__pycache__/0001_initial.cpython-39.pyc
Normal file
BIN
home/migrations/__pycache__/0001_initial.cpython-39.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
home/migrations/__pycache__/0004_articles_author.cpython-39.pyc
Normal file
BIN
home/migrations/__pycache__/0004_articles_author.cpython-39.pyc
Normal file
Binary file not shown.
BIN
home/migrations/__pycache__/__init__.cpython-39.pyc
Normal file
BIN
home/migrations/__pycache__/__init__.cpython-39.pyc
Normal file
Binary file not shown.
@ -1,3 +1,22 @@
|
||||
from django.db import models
|
||||
|
||||
# Create your models here.
|
||||
|
||||
class articles(models.Model):
|
||||
title = models.CharField(max_length=100,verbose_name="文章标题")
|
||||
content = models.TextField(verbose_name="文章内容")
|
||||
abstract = models.TextField(verbose_name="文章摘要")
|
||||
author = models.TextField(default="admin", verbose_name="文章作者")
|
||||
# created = models.DateTimeField(auto_now_add=True,verbose_name="发布时间")
|
||||
created = models.DateTimeField(verbose_name="发布时间")
|
||||
stat = models.IntegerField(default=0,verbose_name="点赞数量")
|
||||
read = models.IntegerField(default=0,verbose_name="阅读数量")
|
||||
|
||||
|
||||
class Meta:
|
||||
verbose_name = "文章"
|
||||
verbose_name_plural = "文章管理"
|
||||
|
||||
def __str__(self):
|
||||
return self.title
|
||||
|
||||
|
453
home/static/archives.css
Normal file
453
home/static/archives.css
Normal file
@ -0,0 +1,453 @@
|
||||
/* 文章详情页样式表 */
|
||||
.article-detail-container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
.article-detail {
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
|
||||
padding: 40px;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
/* 文章头部 */
|
||||
.article-header {
|
||||
margin-bottom: 30px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.article-title {
|
||||
font-size: 32px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
line-height: 1.4;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.article-meta {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 15px;
|
||||
color: #999;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.article-meta i {
|
||||
margin-right: 5px;
|
||||
color: #bbb;
|
||||
}
|
||||
|
||||
/* 文章封面图 */
|
||||
.article-cover {
|
||||
margin: 30px 0;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.article-cover img {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* 文章内容 */
|
||||
.article-content {
|
||||
font-size: 16px;
|
||||
line-height: 1.8;
|
||||
color: #444;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
.article-content p {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.article-content h2,
|
||||
.article-content h3,
|
||||
.article-content h4 {
|
||||
margin: 30px 0 20px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.article-content h2 {
|
||||
font-size: 24px;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.article-content h3 {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.article-content h4 {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.article-content img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
margin: 20px 0;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.article-content pre {
|
||||
background-color: #f8f9fa;
|
||||
padding: 15px;
|
||||
border-radius: 6px;
|
||||
overflow-x: auto;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.article-content code {
|
||||
font-family: 'Courier New', monospace;
|
||||
background-color: #f8f9fa;
|
||||
padding: 2px 5px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.article-content blockquote {
|
||||
border-left: 4px solid #3498db;
|
||||
padding-left: 20px;
|
||||
margin: 20px 0;
|
||||
color: #666;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* 文章标签 */
|
||||
.article-tags {
|
||||
margin: 30px 0;
|
||||
padding: 15px 0;
|
||||
border-top: 1px solid #eee;
|
||||
border-bottom: 1px solid #eee;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.article-tags i {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.tag {
|
||||
display: inline-block;
|
||||
background-color: #f0f7ff;
|
||||
color: #3498db;
|
||||
padding: 4px 12px;
|
||||
border-radius: 20px;
|
||||
font-size: 14px;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.tag:hover {
|
||||
background-color: #3498db;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* 文章导航 */
|
||||
.article-nav {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin: 40px 0;
|
||||
padding: 20px 0;
|
||||
border-top: 1px solid #eee;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.article-nav a {
|
||||
max-width: 48%;
|
||||
color: #666;
|
||||
font-size: 15px;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.article-nav a:hover {
|
||||
color: #3498db;
|
||||
}
|
||||
|
||||
.article-nav i {
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
.prev {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.next {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* 相关文章 */
|
||||
.related-articles {
|
||||
margin: 40px 0;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 22px;
|
||||
color: #333;
|
||||
margin-bottom: 25px;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.related-list {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.related-card {
|
||||
background-color: #f9f9f9;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.related-card:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.related-image {
|
||||
height: 180px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.related-image img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
transition: transform 0.5s;
|
||||
}
|
||||
|
||||
.related-card:hover .related-image img {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.related-info {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.related-info h4 {
|
||||
font-size: 18px;
|
||||
margin-bottom: 10px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.related-info p {
|
||||
font-size: 14px;
|
||||
color: #777;
|
||||
line-height: 1.6;
|
||||
margin-bottom: 10px;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.related-date {
|
||||
font-size: 13px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
/* 评论区域 */
|
||||
.comment-section {
|
||||
margin-top: 50px;
|
||||
}
|
||||
|
||||
.comment-form {
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.comment-form textarea {
|
||||
width: 100%;
|
||||
padding: 15px;
|
||||
border: 1px solid #eee;
|
||||
border-radius: 6px;
|
||||
resize: vertical;
|
||||
min-height: 120px;
|
||||
font-size: 15px;
|
||||
transition: border 0.3s;
|
||||
}
|
||||
|
||||
.comment-form textarea:focus {
|
||||
border-color: #3498db;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.submit-btn {
|
||||
background-color: #3498db;
|
||||
color: #fff;
|
||||
border: none;
|
||||
padding: 12px 25px;
|
||||
border-radius: 6px;
|
||||
font-size: 15px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.submit-btn:hover {
|
||||
background-color: #2980b9;
|
||||
}
|
||||
|
||||
/* 评论列表 */
|
||||
.comment-list {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.comment-item {
|
||||
display: flex;
|
||||
padding: 20px 0;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.comment-avatar {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
margin-right: 15px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.comment-avatar img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 50%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.comment-content {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.comment-header {
|
||||
margin-bottom: 8px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.comment-user {
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
.comment-time {
|
||||
font-size: 13px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.comment-content p {
|
||||
color: #444;
|
||||
line-height: 1.7;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
/* 回复区域 */
|
||||
.comment-replies {
|
||||
margin-left: 50px;
|
||||
margin-top: 15px;
|
||||
padding-left: 15px;
|
||||
border-left: 2px solid #eee;
|
||||
}
|
||||
|
||||
.reply-item {
|
||||
display: flex;
|
||||
padding: 15px 0;
|
||||
border-bottom: 1px dashed #f0f0f0;
|
||||
}
|
||||
|
||||
.reply-avatar {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin-right: 12px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.reply-avatar img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 50%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.reply-content {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.reply-header {
|
||||
margin-bottom: 5px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.reply-user {
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-right: 10px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.reply-time {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.reply-content p {
|
||||
color: #555;
|
||||
line-height: 1.6;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.no-comments {
|
||||
text-align: center;
|
||||
padding: 30px 0;
|
||||
color: #999;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
/* 响应式设计 */
|
||||
@media (max-width: 768px) {
|
||||
.article-detail {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.article-title {
|
||||
font-size: 26px;
|
||||
}
|
||||
|
||||
.article-nav {
|
||||
flex-direction: column;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.article-nav a {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.related-list {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.comment-item {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.comment-avatar {
|
||||
margin-right: 0;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.comment-replies {
|
||||
margin-left: 20px;
|
||||
}
|
||||
}
|
198
home/static/bottom.css
Normal file
198
home/static/bottom.css
Normal file
@ -0,0 +1,198 @@
|
||||
/* 全局样式 */
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
font-family: 'Arial', sans-serif;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #f5f5f5;
|
||||
color: #333;
|
||||
line-height: 1.6;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.container {
|
||||
width: 100%;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
/* 头部样式 */
|
||||
header {
|
||||
background-color: #fff;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||||
padding: 15px 0;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.header-content {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.logo {
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
color: #2c3e50;
|
||||
}
|
||||
|
||||
.nav-links {
|
||||
display: flex;
|
||||
gap: 30px;
|
||||
}
|
||||
|
||||
.nav-links a {
|
||||
transition: color 0.3s;
|
||||
}
|
||||
|
||||
.nav-links a:hover {
|
||||
color: #3498db;
|
||||
}
|
||||
|
||||
.search-box {
|
||||
position: relative;
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
.search-box input {
|
||||
width: 100%;
|
||||
padding: 10px 15px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 20px;
|
||||
outline: none;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.search-box button {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.profile {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.profile-img {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
/* 主要内容区 */
|
||||
main {
|
||||
padding: 30px 0;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
/* 底部样式 */
|
||||
footer {
|
||||
background-color: #2c3e50;
|
||||
color: #fff;
|
||||
padding: 30px 0;
|
||||
margin-top: auto;
|
||||
}
|
||||
|
||||
.footer-content {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||
gap: 30px;
|
||||
}
|
||||
|
||||
.footer-section {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.footer-section h3 {
|
||||
margin-bottom: 15px;
|
||||
font-size: 18px;
|
||||
color: #ecf0f1;
|
||||
}
|
||||
|
||||
.footer-links a {
|
||||
display: block;
|
||||
margin-bottom: 10px;
|
||||
color: #bdc3c7;
|
||||
transition: color 0.3s;
|
||||
}
|
||||
|
||||
.footer-links a:hover {
|
||||
color: #ecf0f1;
|
||||
}
|
||||
|
||||
.copyright {
|
||||
text-align: center;
|
||||
margin-top: 30px;
|
||||
padding-top: 20px;
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
||||
color: #bdc3c7;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
/* 响应式设计 */
|
||||
@media (max-width: 768px) {
|
||||
.header-content {
|
||||
flex-direction: column;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.nav-links {
|
||||
order: 1;
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.search-box {
|
||||
width: 100%;
|
||||
order: 2;
|
||||
}
|
||||
|
||||
.profile {
|
||||
order: 3;
|
||||
}
|
||||
|
||||
.article-list {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.article-content {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.article-image {
|
||||
width: 100%;
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
.article-info {
|
||||
padding-left: 0;
|
||||
padding-top: 15px;
|
||||
}
|
||||
}
|
||||
|
73
home/static/index.css
Normal file
73
home/static/index.css
Normal file
@ -0,0 +1,73 @@
|
||||
/*首页文章列表样式表*/
|
||||
.article-list {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(600px, 1fr));
|
||||
gap: 30px;
|
||||
}
|
||||
|
||||
.article-card {
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
|
||||
transition: transform 0.3s, box-shadow 0.3s;
|
||||
}
|
||||
|
||||
.article-card:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.article-content {
|
||||
display: flex;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.article-image {
|
||||
width: 200px;
|
||||
height: 150px;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.article-image img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.article-info {
|
||||
flex-grow: 1;
|
||||
padding-left: 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.article-title {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 10px;
|
||||
color: #2c3e50;
|
||||
}
|
||||
|
||||
.article-title:hover {
|
||||
color: #3498db;
|
||||
}
|
||||
|
||||
.article-meta {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-top: 15px;
|
||||
color: #999;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.meta-data {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
}
|
44
home/templates/archives.html
Normal file
44
home/templates/archives.html
Normal file
@ -0,0 +1,44 @@
|
||||
{% extends "bottom.html" %}
|
||||
{% load static %}
|
||||
|
||||
{#文章详情#}
|
||||
{% block stylesheethref %}
|
||||
<link rel="stylesheet" href="{% static 'archives.css' %}">
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div class="article-detail-container">
|
||||
<article class="article-detail">
|
||||
<!-- 文章头部信息 -->
|
||||
<div class="article-header">
|
||||
<h1 class="article-title">{{ title }}</h1>
|
||||
<div class="article-meta">
|
||||
<span class="author">
|
||||
<i class="fas fa-user"></i>
|
||||
{{ author }}
|
||||
</span>
|
||||
<span class="date">
|
||||
<i class="fas fa-calendar-alt"></i>
|
||||
{{ created|date:"Y-m-d" }}
|
||||
</span>
|
||||
<span class="category">
|
||||
<i class="fas fa-folder"></i>
|
||||
{{ article.category }}
|
||||
分类
|
||||
</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>
|
||||
|
||||
<!-- 文章内容 -->
|
||||
<div class="article-content">
|
||||
{{ content|safe }}
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
{% endblock %}
|
131
home/templates/bottom.html
Normal file
131
home/templates/bottom.html
Normal file
@ -0,0 +1,131 @@
|
||||
{% load static %}
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>我的个人博客</title>
|
||||
<link rel="stylesheet" href="{% static 'bottom.css' %}">
|
||||
{% block stylesheethref %}
|
||||
{% endblock %}
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<!-- 头部 -->
|
||||
<header>
|
||||
<div class="container header-content">
|
||||
<div class="logo"><a href="/">我的博客</a></div>
|
||||
|
||||
<nav class="nav-links">
|
||||
<a href="#">前端技术</a>
|
||||
<a href="#">后端开发</a>
|
||||
<a href="#">生活随笔</a>
|
||||
<a href="#">关于我</a>
|
||||
<a href="#">关于我</a>
|
||||
</nav>
|
||||
|
||||
<div class="search-box">
|
||||
<input type="text" placeholder="搜索文章...">
|
||||
<button><i class="fas fa-search"></i></button>
|
||||
</div>
|
||||
|
||||
<div class="profile">
|
||||
<span>欢迎回来</span>
|
||||
<img src="http://iph.href.lu/50x50?text=正在开发中" alt="个人头像" class="profile-img">
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- 主要内容区 -->
|
||||
<main>
|
||||
{% block content %}
|
||||
{% endblock %}
|
||||
</main>
|
||||
|
||||
<!-- 底部 -->
|
||||
<footer>
|
||||
<div class="container">
|
||||
<div class="footer-content">
|
||||
<div class="footer-section">
|
||||
<h3>关于我们</h3>
|
||||
<p>这是一个专注于技术分享和个人成长的博客平台,记录我在前端开发、后端技术和生活感悟等方面的思考与实践。</p>
|
||||
</div>
|
||||
|
||||
<div class="footer-section">
|
||||
<h3>分类</h3>
|
||||
<div class="footer-links">
|
||||
<a href="#">前端技术</a>
|
||||
<a href="#">后端开发</a>
|
||||
<a href="#">数据库</a>
|
||||
<a href="#">生活随笔</a>
|
||||
<a href="#">读书笔记</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="footer-section">
|
||||
<h3>友情链接</h3>
|
||||
<div class="footer-links">
|
||||
<a href="#">GitHub</a>
|
||||
<a href="#">Stack Overflow</a>
|
||||
<a href="#">MDN Web Docs</a>
|
||||
<a href="#">掘金</a>
|
||||
<a href="#">知乎</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="footer-section">
|
||||
<h3>联系我们</h3>
|
||||
<div class="footer-links">
|
||||
<a href="mailto:example@example.com">email@example.com</a>
|
||||
<a href="#">GitHub</a>
|
||||
<a href="#">Twitter</a>
|
||||
<a href="#">微信公众号</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="copyright">
|
||||
<p>© 2023 我的个人博客 版权所有 | 粤ICP备12345678号</p>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<!-- 简单的交互功能 -->
|
||||
<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}`)
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
37
home/templates/index.html
Normal file
37
home/templates/index.html
Normal file
@ -0,0 +1,37 @@
|
||||
{% extends "bottom.html" %}
|
||||
{% load static %}
|
||||
|
||||
{% block stylesheethref %}
|
||||
<link rel="stylesheet" href="{% static 'index.css' %}">
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container">
|
||||
<!-- 文章容器 -->
|
||||
<div class="article-list">
|
||||
{% for artcle in artchles %}
|
||||
<article class="article-card">
|
||||
<div class="article-content">
|
||||
<div class="article-image">
|
||||
<img src="http://iph.href.lu/200x150?text=正在开发中" alt="文章图片">
|
||||
</div>
|
||||
<div class="article-info">
|
||||
<p class="article-id" style="display: none">{{ artcle.id }}</p>
|
||||
<h2 class="article-title">{{ artcle.title }}</h2>
|
||||
<p class="article-excerpt">
|
||||
{{ artcle.abstract }}
|
||||
</p>
|
||||
<div class="article-meta">
|
||||
<div class="meta-data">
|
||||
<span>发布时间:{{ artcle.created }}</span>
|
||||
<span>点赞:{{ artcle.stat }}</span>
|
||||
<span>阅读: {{ artcle.read }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
8
home/urls.py
Normal file
8
home/urls.py
Normal file
@ -0,0 +1,8 @@
|
||||
from django.contrib import admin
|
||||
from django.urls import path
|
||||
from home import views as v
|
||||
|
||||
urlpatterns = [
|
||||
path('',v.index),
|
||||
path('archives/<id>', v.archives)
|
||||
]
|
@ -1,3 +1,37 @@
|
||||
from django.shortcuts import render
|
||||
|
||||
from django.shortcuts import render, HttpResponse
|
||||
from . import models
|
||||
# Create your views here.
|
||||
|
||||
def index(request):
|
||||
artchle = models.articles.objects.all()
|
||||
artchles = {"artchles": []}
|
||||
print(artchle)
|
||||
for i in artchle:
|
||||
a = {
|
||||
"id":i.id,
|
||||
"title": i.title,
|
||||
"abstract": i.abstract,
|
||||
"created": i.created,
|
||||
"stat": i.stat,
|
||||
"read": i.read
|
||||
}
|
||||
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.read += 1
|
||||
i.save()
|
||||
a = {
|
||||
"id": i.id,
|
||||
"title": i.title,
|
||||
"abstract": i.abstract,
|
||||
"created": i.created,
|
||||
"stat": i.stat,
|
||||
"read": i.read,
|
||||
"content": i.content,
|
||||
"author": i.author
|
||||
}
|
||||
return render(request, 'archives.html', a)
|
Loading…
x
Reference in New Issue
Block a user