Compare commits

..

12 Commits

Author SHA256 Message Date
5cf22beafa Merge feature/tempfile into develop 2025-08-01 14:39:52 +08:00
f0674c29da Add tempfile 2025-08-01 14:39:26 +08:00
c1918b45b3 Merge bugfix/init_code into develop 2025-07-28 02:04:25 +08:00
a9389042d9 Init All Code 2025-07-28 01:58:12 +08:00
0f24bc5ec9 Merge feature/rss into develop 2025-07-28 00:54:18 +08:00
7ab9ed8e17 Add rss && Change web_view 2025-07-28 00:53:46 +08:00
127c101c70 Merge feature/link_me into develop 2025-07-28 00:33:14 +08:00
57531f8cdf Add link_me in the view 2025-07-28 00:32:48 +08:00
8cd9eecdc8 Merge bugfix into develop 2025-07-27 23:42:02 +08:00
9e4daa6dcf Add button with title 2025-07-27 23:40:35 +08:00
1f608c33ba Add change detail_view long in admin 2025-07-27 23:28:22 +08:00
4d0ea1a55b Change index_view 200 into 20 2025-07-27 23:23:08 +08:00
13 changed files with 1050 additions and 31 deletions

View File

@@ -1,5 +1,5 @@
from django.contrib import admin from django.contrib import admin
from .models import Post, Category from .models import Post, Category, SiteSettings
from django.db import models from django.db import models
from mdeditor.widgets import MDEditorWidget from mdeditor.widgets import MDEditorWidget
@@ -16,6 +16,21 @@ class PostAdmin(admin.ModelAdmin):
search_fields = ('title', 'content') search_fields = ('title', 'content')
class SiteSettingsAdmin(admin.ModelAdmin):
# 保持所有字段在列表中显示,方便直接编辑
list_display = ('id', 'summary_length', 'contact_email', 'contact_wechat', 'contact_linkedin', 'contact_github')
list_display_links = ('id',)
def has_add_permission(self, request):
# 限制只能有一个站点设置实例
return not SiteSettings.objects.exists()
def has_delete_permission(self, request, obj=None):
# 禁止删除站点设置
return False
# 注册自定义的PostAdmin # 注册自定义的PostAdmin
admin.site.register(Post, PostAdmin) admin.site.register(Post, PostAdmin)
admin.site.register(Category) admin.site.register(Category)
admin.site.register(SiteSettings, SiteSettingsAdmin)

96
myblog/blog/feeds.py Normal file
View File

@@ -0,0 +1,96 @@
from django.contrib.syndication.views import Feed
from django.urls import reverse
from django.shortcuts import get_object_or_404
from .models import Post, Category
class LatestPostsFeed(Feed):
title = "六桂流芳的com"
link = "/rss/"
description = "最新博客文章"
# 添加content_type使浏览器能正确显示RSS内容
content_type = 'application/xml; charset=utf-8'
def items(self):
return Post.objects.order_by('-publish_date')[:10]
def item_title(self, item):
return item.title
def item_description(self, item):
return item.get_markdown_content()
def item_link(self, item):
return reverse('detail', args=[item.pk])
# 添加分类RSS Feed
class CategoryPostsFeed(Feed):
# 添加content_type使浏览器能正确显示RSS内容
content_type = 'application/xml; charset=utf-8'
def get_object(self, request, category_id):
return get_object_or_404(Category, pk=category_id)
def title(self, obj):
return f"六桂流芳的com - {obj.name}分类"
def link(self, obj):
return reverse('category_feed', args=[obj.pk])
def description(self, obj):
return f"{obj.name}分类的最新博客文章"
def items(self, obj):
return Post.objects.filter(category=obj).order_by('-publish_date')[:10]
def item_title(self, item):
return item.title
def item_description(self, item):
return item.get_markdown_content()
def item_link(self, item):
return reverse('detail', args=[item.pk])
# 添加最新RSS Feed (与全部的区别在于数量限制)
class RecentPostsFeed(Feed):
title = "六桂流芳的com - 最新文章"
link = "/rss/recent/"
description = "最新的博客文章"
# 添加content_type使浏览器能正确显示RSS内容
content_type = 'application/xml; charset=utf-8'
def items(self):
return Post.objects.order_by('-publish_date')[:20]
def item_title(self, item):
return item.title
def item_description(self, item):
return item.get_markdown_content()
def item_link(self, item):
return reverse('detail', args=[item.pk])
# 添加全部RSS Feed
class AllPostsFeed(Feed):
title = "六桂流芳的com - 全部文章"
link = "/rss/all/"
description = "全部博客文章"
# 添加content_type使浏览器能正确显示RSS内容
content_type = 'application/xml; charset=utf-8'
def items(self):
return Post.objects.order_by('-publish_date')
def item_title(self, item):
return item.title
def item_description(self, item):
return item.get_markdown_content()
def item_link(self, item):
return reverse('detail', args=[item.pk])

View File

@@ -0,0 +1,24 @@
# Generated by Django 5.1 on 2025-07-27 15:27
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('blog', '0007_post_category'),
]
operations = [
migrations.CreateModel(
name='SiteSettings',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('summary_length', models.IntegerField(default=50, help_text='文章摘要字符长度')),
],
options={
'verbose_name': '站点设置',
'verbose_name_plural': '站点设置',
},
),
]

View File

@@ -0,0 +1,33 @@
# Generated by Django 5.1 on 2025-07-27 15:53
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('blog', '0008_sitesettings'),
]
operations = [
migrations.AddField(
model_name='sitesettings',
name='contact_email',
field=models.EmailField(blank=True, help_text='联系邮箱', max_length=254, null=True),
),
migrations.AddField(
model_name='sitesettings',
name='contact_github',
field=models.URLField(blank=True, help_text='GitHub链接', null=True),
),
migrations.AddField(
model_name='sitesettings',
name='contact_linkedin',
field=models.URLField(blank=True, help_text='LinkedIn链接', null=True),
),
migrations.AddField(
model_name='sitesettings',
name='contact_wechat',
field=models.CharField(blank=True, help_text='微信号', max_length=100, null=True),
),
]

View File

@@ -0,0 +1,18 @@
# Generated by Django 5.1 on 2025-07-31 15:06
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('blog', '0009_sitesettings_contact_email_and_more'),
]
operations = [
migrations.AddField(
model_name='post',
name='status',
field=models.CharField(choices=[('draft', '草稿'), ('published', '已发布')], default='draft', max_length=10),
),
]

View File

@@ -19,14 +19,40 @@ class Category(models.Model):
verbose_name_plural = "Categories" verbose_name_plural = "Categories"
# 添加站点设置模型
class SiteSettings(models.Model):
summary_length = models.IntegerField(default=50, help_text="文章摘要字符长度")
contact_email = models.EmailField(blank=True, null=True, help_text="联系邮箱")
contact_wechat = models.CharField(max_length=100, blank=True, null=True, help_text="微信号")
contact_linkedin = models.URLField(blank=True, null=True, help_text="LinkedIn链接")
contact_github = models.URLField(blank=True, null=True, help_text="GitHub链接")
class Meta:
verbose_name = "站点设置"
verbose_name_plural = "站点设置"
def __str__(self):
return "站点设置"
class Post(models.Model): class Post(models.Model):
# 添加状态选项
DRAFT = 'draft'
PUBLISHED = 'published'
STATUS_CHOICES = [
(DRAFT, '草稿'),
(PUBLISHED, '已发布'),
]
title = models.CharField(max_length=100) title = models.CharField(max_length=100)
content = MDTextField() # ✅ 改成这里 content = MDTextField()
created_at = models.DateTimeField(auto_now_add=True) created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True) updated_at = models.DateTimeField(auto_now=True)
publish_date = models.DateTimeField(default=timezone.now) publish_date = models.DateTimeField(default=timezone.now)
# 添加分类字段,建立外键关系 # 添加分类字段,建立外键关系
category = models.ForeignKey(Category, on_delete=models.SET_NULL, null=True, blank=True, related_name='posts') category = models.ForeignKey(Category, on_delete=models.SET_NULL, null=True, blank=True, related_name='posts')
# 添加状态字段
status = models.CharField(max_length=10, choices=STATUS_CHOICES, default=DRAFT)
def __str__(self): def __str__(self):
return f"{self.title}" return f"{self.title}"

View File

@@ -0,0 +1,325 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>联系我 - 六桂流芳的com</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
}
.container {
display: flex;
max-width: 1200px;
margin: 0 auto;
padding: 20px;
min-height: 100vh;
}
.sidebar {
width: 250px;
padding-right: 20px;
border-right: 1px solid #eee;
position: -webkit-sticky;
position: sticky;
top: 20px;
align-self: flex-start;
height: fit-content;
}
.sidebar h3 {
color: #333;
border-bottom: 2px solid #007cba;
padding-bottom: 10px;
}
.sidebar ul {
list-style: none;
padding: 0;
}
.sidebar ul li {
margin: 10px 0;
}
.sidebar ul li a {
text-decoration: none;
color: #666;
display: block;
padding: 8px 12px;
border-radius: 4px;
transition: all 0.3s;
}
.sidebar ul li a:hover,
.sidebar ul li a.active {
background-color: #007cba;
color: white;
}
.search-box {
margin-bottom: 20px;
}
.search-box input[type="text"] {
width: 100%;
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
box-sizing: border-box;
}
.search-box input[type="submit"] {
width: 100%;
padding: 8px;
background-color: #007cba;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
margin-top: 5px;
}
.search-box input[type="submit"]:hover {
background-color: #005a87;
}
.search-type {
margin: 10px 0;
}
.search-type label {
display: block;
margin: 5px 0;
font-size: 14px;
color: #666;
}
.search-type input[type="radio"] {
margin-right: 5px;
}
.main-content {
flex: 1;
padding-left: 20px;
}
.main-content h1 {
color: #333;
border-bottom: 2px solid #eee;
padding-bottom: 10px;
}
footer {
position: fixed;
bottom: 0;
width: 100%;
text-align: center;
font-size: 12px;
color: #999;
background-color: white;
padding: 5px 0;
}
.contact-info {
background-color: #f9f9f9;
padding: 15px;
border-radius: 5px;
margin-top: 20px;
border: 1px solid #eee;
}
.contact-info h3 {
margin-top: 0;
color: #333;
border-bottom: 2px solid #007cba;
padding-bottom: 10px;
}
.contact-info ul {
padding-left: 20px;
}
.contact-info li {
margin: 10px 0;
color: #666;
}
/* 添加联系我主内容区域样式 */
.contact-main {
background-color: #f9f9f9;
padding: 20px;
border-radius: 5px;
border: 1px solid #eee;
}
.contact-main h2 {
color: #333;
border-bottom: 2px solid #007cba;
padding-bottom: 10px;
}
.contact-description {
margin: 15px 0;
line-height: 1.6;
color: #666;
}
.contact-details {
list-style: none;
padding: 0;
}
.contact-details li {
padding: 10px 0;
border-bottom: 1px solid #eee;
}
.contact-details li:last-child {
border-bottom: none;
}
.contact-label {
font-weight: bold;
color: #333;
display: inline-block;
width: 80px;
}
.contact-value {
color: #666;
}
/* 添加导航栏样式 */
.top-nav {
background-color: #007cba;
padding: 10px 0;
margin-bottom: 20px;
}
.nav-container {
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
}
.nav-links {
list-style: none;
padding: 0;
margin: 0;
display: flex;
}
.nav-links li {
margin-right: 20px;
}
.nav-links li a {
color: white;
text-decoration: none;
padding: 8px 12px;
border-radius: 4px;
transition: background-color 0.3s;
}
.nav-links li a:hover {
background-color: rgba(255, 255, 255, 0.2);
}
</style>
</head>
<body>
<!-- 添加网站标题和导航栏 -->
<div class="top-nav">
<div class="nav-container">
<h1 style="text-align: left; margin: 0; padding: 0;">
<a href="{% url 'index' %}" style="text-decoration: none; color: white;">六桂流芳的com</a>
</h1>
<ul class="nav-links">
<li><a href="{% url 'index' %}">首页</a></li>
<li><a href="{% url 'rss_page' %}">RSS订阅</a></li>
<li><a href="{% url 'contact_page' %}">联系我</a></li>
</ul>
</div>
</div>
<div class="container">
<div class="sidebar">
<div class="search-box">
<form method="get" action="{% url 'index' %}">
<input type="text" name="q" placeholder="搜索文章..." value="{{ query|default:'' }}">
<div class="search-type">
<label>
<input type="radio" name="search_type" value="all" checked>
全文搜索
</label>
<label>
<input type="radio" name="search_type" value="title">
标题搜索
</label>
<label>
<input type="radio" name="search_type" value="content">
内容搜索
</label>
</div>
<input type="submit" value="搜索">
</form>
</div>
<h3>文章分类</h3>
<ul>
<li><a href="{% url 'index' %}">全部文章</a></li>
{% for category in categories %}
<li>
<a href="{% url 'index' %}?category={{ category.id }}">
{{ category.name }}
</a>
</li>
{% endfor %}
</ul>
</div>
<div class="main-content">
<div class="contact-main">
<h2>联系我</h2>
<div class="contact-description">
如果您有任何问题或想与我交流,可以通过以下方式联系我:
</div>
<ul class="contact-details">
{% if site_settings.contact_email %}
<li>
<span class="contact-label">邮箱:</span>
<span class="contact-value">{{ site_settings.contact_email }}</span>
</li>
{% endif %}
{% if site_settings.contact_wechat %}
<li>
<span class="contact-label">微信:</span>
<span class="contact-value">{{ site_settings.contact_wechat }}</span>
</li>
{% endif %}
{% if site_settings.contact_linkedin %}
<li>
<span class="contact-label">LinkedIn:</span>
<span class="contact-value">{{ site_settings.contact_linkedin }}</span>
</li>
{% endif %}
{% if site_settings.contact_github %}
<li>
<span class="contact-label">GitHub:</span>
<span class="contact-value">{{ site_settings.contact_github }}</span>
</li>
{% endif %}
</ul>
</div>
</div>
</div>
<footer>
<a href="https://beian.miit.gov.cn/" target="_blank">闽ICP备2023010767号-2</a>
</footer>
</body>
</html>

View File

@@ -15,14 +15,14 @@
max-width: 1200px; max-width: 1200px;
margin: 0 auto; margin: 0 auto;
padding: 20px; padding: 20px;
/ / : sticky min-height: 100 vh; min-height: 100vh;
} }
.sidebar { .sidebar {
width: 250px; width: 250px;
padding-right: 20px; padding-right: 20px;
border-right: 1px solid #eee; border-right: 1px solid #eee;
/ / : position: -webkit-sticky; position: -webkit-sticky;
position: sticky; position: sticky;
top: 20px; top: 20px;
align-self: flex-start; align-self: flex-start;
@@ -159,12 +159,57 @@
background-color: white; background-color: white;
padding: 5px 0; padding: 5px 0;
} }
/* 添加导航栏样式 */
.top-nav {
background-color: #007cba;
padding: 10px 0;
margin-bottom: 20px;
}
.nav-container {
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
}
.nav-links {
list-style: none;
padding: 0;
margin: 0;
display: flex;
}
.nav-links li {
margin-right: 20px;
}
.nav-links li a {
color: white;
text-decoration: none;
padding: 8px 12px;
border-radius: 4px;
transition: background-color 0.3s;
}
.nav-links li a:hover {
background-color: rgba(255, 255, 255, 0.2);
}
</style> </style>
</head> </head>
<body> <body>
<!-- 添加网站标题 --> <!-- 添加网站标题和导航栏 -->
<div style="max-width: 1200px; margin: 0 auto; padding: 0 20px;"> <div class="top-nav">
<h1 style="text-align: left;">六桂流芳的com</h1> <div class="nav-container">
<h1 style="text-align: left; margin: 0; padding: 0;">
<a href="{% url 'index' %}" style="text-decoration: none; color: white;">六桂流芳的com</a>
</h1>
<ul class="nav-links">
<li><a href="{% url 'index' %}">首页</a></li>
<li><a href="{% url 'rss_page' %}">RSS订阅</a></li>
<li><a href="{% url 'contact_page' %}">联系我</a></li>
</ul>
</div>
</div> </div>
<div class="container"> <div class="container">

View File

@@ -159,12 +159,57 @@
footer { footer {
} }
/* 添加导航栏样式 */
.top-nav {
background-color: #007cba;
padding: 10px 0;
margin-bottom: 20px;
}
.nav-container {
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
}
.nav-links {
list-style: none;
padding: 0;
margin: 0;
display: flex;
}
.nav-links li {
margin-right: 20px;
}
.nav-links li a {
color: white;
text-decoration: none;
padding: 8px 12px;
border-radius: 4px;
transition: background-color 0.3s;
}
.nav-links li a:hover {
background-color: rgba(255, 255, 255, 0.2);
}
</style> </style>
</head> </head>
<body> <body>
<!-- 添加网站标题 --> <!-- 添加网站标题和导航栏 -->
<div style="max-width: 1200px; margin: 0 auto; padding: 0 20px;"> <div class="top-nav">
<h1 style="text-align: left;">六桂流芳的com</h1> <div class="nav-container">
<h1 style="text-align: left; margin: 0; padding: 0;">
<a href="{% url 'index' %}" style="text-decoration: none; color: white;">六桂流芳的com</a>
</h1>
<ul class="nav-links">
<li><a href="{% url 'index' %}">首页</a></li>
<li><a href="{% url 'rss_page' %}">RSS订阅</a></li>
<li><a href="{% url 'contact_page' %}">联系我</a></li>
</ul>
</div>
</div> </div>
<div class="container"> <div class="container">

View File

@@ -0,0 +1,303 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>RSS订阅 - 六桂流芳的com</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
}
.container {
display: flex;
max-width: 1200px;
margin: 0 auto;
padding: 20px;
min-height: 100vh;
}
.sidebar {
width: 250px;
padding-right: 20px;
border-right: 1px solid #eee;
position: -webkit-sticky;
position: sticky;
top: 20px;
align-self: flex-start;
height: fit-content;
}
.sidebar h3 {
color: #333;
border-bottom: 2px solid #007cba;
padding-bottom: 10px;
}
.sidebar ul {
list-style: none;
padding: 0;
}
.sidebar ul li {
margin: 10px 0;
}
.sidebar ul li a {
text-decoration: none;
color: #666;
display: block;
padding: 8px 12px;
border-radius: 4px;
transition: all 0.3s;
}
.sidebar ul li a:hover,
.sidebar ul li a.active {
background-color: #007cba;
color: white;
}
.search-box {
margin-bottom: 20px;
}
.search-box input[type="text"] {
width: 100%;
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
box-sizing: border-box;
}
.search-box input[type="submit"] {
width: 100%;
padding: 8px;
background-color: #007cba;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
margin-top: 5px;
}
.search-box input[type="submit"]:hover {
background-color: #005a87;
}
.search-type {
margin: 10px 0;
}
.search-type label {
display: block;
margin: 5px 0;
font-size: 14px;
color: #666;
}
.search-type input[type="radio"] {
margin-right: 5px;
}
.main-content {
flex: 1;
padding-left: 20px;
}
.main-content h1 {
color: #333;
border-bottom: 2px solid #eee;
padding-bottom: 10px;
}
footer {
position: fixed;
bottom: 0;
width: 100%;
text-align: center;
font-size: 12px;
color: #999;
background-color: white;
padding: 5px 0;
}
/* 添加导航栏样式 */
.top-nav {
background-color: #007cba;
padding: 10px 0;
margin-bottom: 20px;
}
.nav-container {
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
}
.nav-links {
list-style: none;
padding: 0;
margin: 0;
display: flex;
}
.nav-links li {
margin-right: 20px;
}
.nav-links li a {
color: white;
text-decoration: none;
padding: 8px 12px;
border-radius: 4px;
transition: background-color 0.3s;
}
.nav-links li a:hover {
background-color: rgba(255, 255, 255, 0.2);
}
/* RSS主内容区域样式 */
.rss-main {
background-color: #f9f9f9;
padding: 20px;
border-radius: 5px;
border: 1px solid #eee;
}
.rss-main h2 {
color: #333;
border-bottom: 2px solid #ff6600;
padding-bottom: 10px;
}
.rss-description {
margin: 15px 0;
line-height: 1.6;
color: #666;
}
.rss-feed-list {
list-style: none;
padding: 0;
}
.rss-feed-list li {
padding: 10px 0;
border-bottom: 1px solid #eee;
}
.rss-feed-list li:last-child {
border-bottom: none;
}
.rss-feed-link {
font-size: 16px;
font-weight: bold;
color: #007cba;
text-decoration: none;
}
.rss-feed-link:hover {
text-decoration: underline;
}
.rss-feed-description {
font-size: 14px;
color: #999;
margin-top: 5px;
}
</style>
</head>
<body>
<!-- 添加网站标题和导航栏 -->
<div class="top-nav">
<div class="nav-container">
<h1 style="text-align: left; margin: 0; padding: 0;">
<a href="{% url 'index' %}" style="text-decoration: none; color: white;">六桂流芳的com</a>
</h1>
<ul class="nav-links">
<li><a href="{% url 'index' %}">首页</a></li>
<li><a href="{% url 'rss_page' %}">RSS订阅</a></li>
<li><a href="{% url 'contact_page' %}">联系我</a></li>
</ul>
</div>
</div>
<div class="container">
<div class="sidebar">
<div class="search-box">
<form method="get" action="{% url 'index' %}">
<input type="text" name="q" placeholder="搜索文章..." value="{{ query|default:'' }}">
<div class="search-type">
<label>
<input type="radio" name="search_type" value="all" checked>
全文搜索
</label>
<label>
<input type="radio" name="search_type" value="title">
标题搜索
</label>
<label>
<input type="radio" name="search_type" value="content">
内容搜索
</label>
</div>
<input type="submit" value="搜索">
</form>
</div>
<h3>文章分类</h3>
<ul>
<li><a href="{% url 'index' %}">全部文章</a></li>
{% for category in categories %}
<li>
<a href="{% url 'index' %}?category={{ category.id }}">
{{ category.name }}
</a>
</li>
{% endfor %}
</ul>
</div>
<div class="main-content">
<div class="rss-main">
<h2>RSS订阅</h2>
<div class="rss-description">
RSS是一种用于发布经常更新的内容的网页格式。通过RSS阅读器您可以订阅我们的内容及时获取最新文章更新。
点击下面的链接可以在浏览器中查看RSS内容使用RSS阅读器订阅时请复制链接地址。
</div>
<ul class="rss-feed-list">
<li>
<a href="{% url 'rss_feed' %}" class="rss-feed-link" target="_blank">最新文章</a>
<div class="rss-feed-description">包含最新的10篇博客文章</div>
</li>
<li>
<a href="{% url 'recent_feed' %}" class="rss-feed-link" target="_blank">最近更新</a>
<div class="rss-feed-description">包含最新的20篇博客文章</div>
</li>
<li>
<a href="{% url 'all_feed' %}" class="rss-feed-link" target="_blank">全部文章</a>
<div class="rss-feed-description">包含所有博客文章</div>
</li>
{% for category in categories %}
<li>
<a href="{% url 'category_feed' category.id %}" class="rss-feed-link"
target="_blank">{{ category.name }}分类</a>
<div class="rss-feed-description">{{ category.name }}分类下的最新博客文章</div>
</li>
{% endfor %}
</ul>
</div>
</div>
</div>
<footer>
<a href="https://beian.miit.gov.cn/" target="_blank">闽ICP备2023010767号-2</a>
</footer>
</body>
</html>

View File

@@ -1,7 +1,16 @@
from django.urls import path from django.urls import path
from . import views from . import views
from .feeds import LatestPostsFeed, CategoryPostsFeed, RecentPostsFeed, AllPostsFeed
urlpatterns = [ urlpatterns = [
path('', views.index, name='index'), path('', views.index, name='index'),
path('post/<int:post_id>/', views.detail, name='detail'), path('post/<int:post_id>/', views.detail, name='detail'),
# 添加RSS页面路由
path('rss/page/', views.rss_page, name='rss_page'),
# 添加联系我页面路由
path('contact/', views.contact_page, name='contact_page'),
path('rss/', LatestPostsFeed(), name='rss_feed'),
path('rss/category/<int:category_id>/', CategoryPostsFeed(), name='category_feed'),
path('rss/recent/', RecentPostsFeed(), name='recent_feed'),
path('rss/all/', AllPostsFeed(), name='all_feed'),
] ]

View File

@@ -1,5 +1,47 @@
from django.shortcuts import render, get_object_or_404 from django.shortcuts import render, get_object_or_404
from .models import Post, Category from .models import Post, Category, SiteSettings
def post_list(request):
# 只显示已发布的文章
posts = Post.objects.filter(status=Post.PUBLISHED).order_by('-publish_date')
categories = Category.objects.all()
# 获取站点设置
site_settings = SiteSettings.objects.first()
summary_length = site_settings.summary_length if site_settings else 50
return render(request, 'blog/post_list.html', {
'posts': posts,
'categories': categories,
'summary_length': summary_length
})
def post_detail(request, pk):
# 只允许查看已发布的文章
post = get_object_or_404(Post, pk=pk, status=Post.PUBLISHED)
categories = Category.objects.all()
return render(request, 'blog/post_detail.html', {
'post': post,
'categories': categories
})
def category_posts(request, category_id):
category = get_object_or_404(Category, id=category_id)
# 只显示该分类下已发布的文章
posts = Post.objects.filter(category=category, status=Post.PUBLISHED).order_by('-publish_date')
categories = Category.objects.all()
# 获取站点设置
site_settings = SiteSettings.objects.first()
summary_length = site_settings.summary_length if site_settings else 50
return render(request, 'blog/post_list.html', {
'posts': posts,
'categories': categories,
'current_category': category,
'summary_length': summary_length
})
# Create your views here. # Create your views here.
@@ -7,50 +49,89 @@ from .models import Post, Category
def index(request): def index(request):
# 获取所有分类 # 获取所有分类
categories = Category.objects.all() categories = Category.objects.all()
# 获取查询参数中的分类ID # 获取查询参数中的分类ID
category_id = request.GET.get('category') category_id = request.GET.get('category')
# 获取搜索关键词 # 获取搜索关键词
query = request.GET.get('q') query = request.GET.get('q')
# 获取搜索类型参数 # 获取搜索类型参数
search_type = request.GET.get('search_type', 'all') search_type = request.GET.get('search_type', 'all')
# 获取站点设置,如果不存在则使用默认值
try:
site_settings = SiteSettings.objects.first()
summary_length = site_settings.summary_length if site_settings else 50
except SiteSettings.DoesNotExist:
site_settings = None
summary_length = 50
# 根据分类和搜索关键词筛选文章 # 根据分类和搜索关键词筛选文章
if query: if query:
# 根据搜索类型执行不同的搜索 # 根据搜索类型执行不同的搜索
if search_type == 'title': if search_type == 'title':
posts = Post.objects.filter(title__icontains=query) posts = Post.objects.filter(title__icontains=query, status=Post.PUBLISHED)
elif search_type == 'content': elif search_type == 'content':
posts = Post.objects.filter(content__icontains=query) posts = Post.objects.filter(content__icontains=query, status=Post.PUBLISHED)
else: else:
# 默认按标题和内容搜索 # 默认按标题和内容搜索
posts = Post.objects.filter(title__icontains=query) | Post.objects.filter(content__icontains=query) posts = Post.objects.filter(title__icontains=query, status=Post.PUBLISHED) | Post.objects.filter(content__icontains=query, status=Post.PUBLISHED)
elif category_id: elif category_id:
posts = Post.objects.filter(category_id=category_id) posts = Post.objects.filter(category_id=category_id, status=Post.PUBLISHED)
else: else:
posts = Post.objects.all() posts = Post.objects.filter(status=Post.PUBLISHED)
posts = posts.order_by('-publish_date').distinct() posts = posts.order_by('-publish_date').distinct()
# 为每篇文章添加摘要(前200个字符 # 为每篇文章添加摘要(根据设置的字符长度
for post in posts: for post in posts:
# 移除HTML标签并截取前200个字符作为摘要
import re import re
clean_content = re.sub(r'<[^>]+>', '', post.get_markdown_content()) clean_content = re.sub(r'<[^>]+>', '', post.get_markdown_content())
post.summary = clean_content[:200] + '...' if len(clean_content) > 200 else clean_content post.summary = clean_content[:summary_length] + '...' if len(clean_content) > summary_length else clean_content
return render(request, 'blog/index.html', { return render(request, 'blog/index.html', {
'posts': posts, 'posts': posts,
'categories': categories, 'categories': categories,
'selected_category': category_id, 'selected_category': category_id,
'query': query, 'query': query,
'search_type': search_type 'search_type': search_type,
'site_settings': site_settings
}) })
def detail(request, post_id): def detail(request, post_id):
post = get_object_or_404(Post, pk=post_id) post = get_object_or_404(Post, pk=post_id, status=Post.PUBLISHED)
categories = Category.objects.all() # 获取所有分类用于侧边栏 categories = Category.objects.all() # 获取所有分类用于侧边栏
return render(request, 'blog/detail.html', {'post': post, 'categories': categories}) try:
site_settings = SiteSettings.objects.first()
except SiteSettings.DoesNotExist:
site_settings = None
return render(request, 'blog/detail.html', {
'post': post,
'categories': categories,
'site_settings': site_settings})
# 添加RSS页面视图
def rss_page(request):
categories = Category.objects.all()
try:
site_settings = SiteSettings.objects.first()
except SiteSettings.DoesNotExist:
site_settings = None
return render(request, 'blog/rss.html', {
'categories': categories,
'site_settings': site_settings
})
# 添加联系我页面视图
def contact_page(request):
try:
site_settings = SiteSettings.objects.first()
except SiteSettings.DoesNotExist:
site_settings = None
return render(request, 'blog/contact.html', {
'site_settings': site_settings
})

View File

@@ -163,4 +163,3 @@ try:
from .local_settings import * from .local_settings import *
except ImportError: except ImportError:
pass pass