update. 完成前端页面展示、列表和详情页

update. 调整融合主菜单与板块
update. 分离新闻模块
This commit is contained in:
ngfchl
2026-04-01 14:17:03 +08:00
parent af9d7a676f
commit 777ca50328
55 changed files with 2190 additions and 567 deletions
+4 -1
View File
@@ -6,7 +6,9 @@ app_name = 'front' # 可选,用于命名空间(如 {% url 'main:index' %}
urlpatterns = [
path('', views.index, name='index'),
path('h/', views.index, name='h'),
path('<str:main>.html', views.info, name='menu'),
path('<str:main>/list.html', views.main_article_list, name='main_list'),
path('<str:main>/list/<str:sub>.html', views.sub_article_list, name='sub_list'),
path('about/', views.about, name='about'),
path('news/', views.news, name='news'),
path('info/', views.info, name='info'),
@@ -14,4 +16,5 @@ urlpatterns = [
path('party/', views.party, name='party'),
path('interaction/', views.interaction, name='interaction'),
path('science/', views.science, name='science'),
path('article/<int:pk>.html/', views.article_detail, name='article_detail'),
]
+184 -147
View File
@@ -1,14 +1,36 @@
import traceback
from typing import Dict, List
from unicodedata import category
from django.shortcuts import render
from django.db.models import Prefetch
from django.http import Http404, HttpResponse
from django.shortcuts import render, get_object_or_404
from loguru import logger
from article.models import Article
from base.models import MainMenu
from news.models import NewsSection
from utils.format import get_now_strftime_format
# Create your views here.
def h(request):
return render(request, 'front/h.html', )
# 2. 新增:文章详情视图函数
def article_detail(request, pk: int):
"""
根据主键 (pk) 获取文章详情
"""
try:
# 使用 get_object_or_404 简化代码:如果文章不存在,自动返回 404 页面
article = get_object_or_404(Article, pk=pk)
# 如果是渲染 HTML 模板
return render(request, 'front/details/article.html', {'article': article})
except (Article.DoesNotExist, Http404):
return render(request, 'front/error/404.html')
except Exception as e:
logger.error(e)
logger.error(traceback.format_exc())
return render(request, 'front/error/500.html')
def index(request):
@@ -37,64 +59,91 @@ def index(request):
]
}
}
section_data = [
{
"key": "info",
# section_data = [
# {
# "key": "info",
# "data": {
# '信息公开': [
# {'title': '习近平会见全国应急管理系统先进模范和消防忠诚卫士表彰...', 'date': '2021-11-06'},
# {'title': '北京市消防救援局挂牌', 'date': '2024-06-19'},
# {'title': '市消防救援局即日起开展专项行动,推出一揽子“便民利企”措施', 'date': '2025-07-01'},
# {'title': '北京开展石油化工生产装置灭火救援实战演练', 'date': '2025-09-30'},
# {'title': '北京市全面启动 2025 年度消防宣传月活动', 'date': '2025-11-11'},
# {'title': '逛庙会学消防!厂甸大观园庙会打造消防“打卡点”', 'date': '2026-02-25'},
# {'title': '“火焰蓝”守护年味!消防员坚守景区庙会护平安', 'date': '2026-02-21'},
# ],
# },
# },
# {
# "key": "party",
# "data": {
# '党建引领': [
# {'title': '习近平会见全国应急管理系统先进模范和消防忠诚卫士表彰...', 'date': '2021-11-06'},
# {'title': '北京市消防救援局挂牌', 'date': '2024-06-19'},
# {'title': '市消防救援局即日起开展专项行动,推出一揽子“便民利企”措施', 'date': '2025-07-01'},
# {'title': '北京开展石油化工生产装置灭火救援实战演练', 'date': '2025-09-30'},
# {'title': '北京市全面启动 2025 年度消防宣传月活动', 'date': '2025-11-11'},
# {'title': '逛庙会学消防!厂甸大观园庙会打造消防“打卡点”', 'date': '2026-02-25'},
# {'title': '“火焰蓝”守护年味!消防员坚守景区庙会护平安', 'date': '2026-02-21'},
# ],
# },
# },
# {
# "key": "interaction",
# "data": {
# '互动交流': [
# {'title': '习近平会见全国应急管理系统先进模范和消防忠诚卫士表彰...', 'date': '2021-11-06'},
# {'title': '北京市消防救援局挂牌', 'date': '2024-06-19'},
# {'title': '市消防救援局即日起开展专项行动,推出一揽子“便民利企”措施', 'date': '2025-07-01'},
# {'title': '北京开展石油化工生产装置灭火救援实战演练', 'date': '2025-09-30'},
# {'title': '北京市全面启动 2025 年度消防宣传月活动', 'date': '2025-11-11'},
# {'title': '逛庙会学消防!厂甸大观园庙会打造消防“打卡点”', 'date': '2026-02-25'},
# {'title': '“火焰蓝”守护年味!消防员坚守景区庙会护平安', 'date': '2026-02-21'},
# ],
# },
# },
# {
# "key": "science",
# "data": {
# '消防科普': [
# {'title': '习近平会见全国应急管理系统先进模范和消防忠诚卫士表彰...', 'date': '2021-11-06'},
# {'title': '北京市消防救援局挂牌', 'date': '2024-06-19'},
# {'title': '市消防救援局即日起开展专项行动,推出一揽子“便民利企”措施', 'date': '2025-07-01'},
# {'title': '北京开展石油化工生产装置灭火救援实战演练', 'date': '2025-09-30'},
# {'title': '北京市全面启动 2025 年度消防宣传月活动', 'date': '2025-11-11'},
# {'title': '逛庙会学消防!厂甸大观园庙会打造消防“打卡点”', 'date': '2026-02-25'},
# {'title': '“火焰蓝”守护年味!消防员坚守景区庙会护平安', 'date': '2026-02-21'},
# ],
# },
# }
# ]
articles_qs = Article.objects.filter(is_published=True).order_by('-created_at')
main_sections = MainMenu.objects.filter(parent__isnull=True, visible=True).order_by('order').prefetch_related(
# 预取可见的子板块
Prefetch('children', queryset=MainMenu.objects.filter(visible=True).order_by('order')),
# 预取子板块下的文章,并将结果存入 'latest_articles' 属性
# 注意:这个属性是属于 'children' (即下面的 sub) 的
Prefetch('children__article_set', queryset=articles_qs, to_attr='latest_articles')
)
# 3. 构建数据 (纯内存操作,速度极快)
section_data = []
for main in main_sections:
# 收集该主板块下所有子板块的文章
all_articles = []
for sub in main.children.all():
# 使用预取好的 children
# 使用预取好的 latest_articles,并取前7条
all_articles.extend(sub.latest_articles[:7])
all_articles.sort(key=lambda x: x.created_at, reverse=True)
# 截取总列表的前7条(如果需要限制总数)
section_data.append({
"key": main.code, # 建议使用 code 作为 key,比对象本身更安全
"data": {
'信息公开': [
{'title': '习近平会见全国应急管理系统先进模范和消防忠诚卫士表彰...', 'date': '2021-11-06'},
{'title': '北京市消防救援局挂牌', 'date': '2024-06-19'},
{'title': '市消防救援局即日起开展专项行动,推出一揽子“便民利企”措施', 'date': '2025-07-01'},
{'title': '北京开展石油化工生产装置灭火救援实战演练', 'date': '2025-09-30'},
{'title': '北京市全面启动 2025 年度消防宣传月活动', 'date': '2025-11-11'},
{'title': '逛庙会学消防!厂甸大观园庙会打造消防“打卡点”', 'date': '2026-02-25'},
{'title': '“火焰蓝”守护年味!消防员坚守景区庙会护平安', 'date': '2026-02-21'},
],
},
},
{
"key": "party",
"data": {
'党建引领': [
{'title': '习近平会见全国应急管理系统先进模范和消防忠诚卫士表彰...', 'date': '2021-11-06'},
{'title': '北京市消防救援局挂牌', 'date': '2024-06-19'},
{'title': '市消防救援局即日起开展专项行动,推出一揽子“便民利企”措施', 'date': '2025-07-01'},
{'title': '北京开展石油化工生产装置灭火救援实战演练', 'date': '2025-09-30'},
{'title': '北京市全面启动 2025 年度消防宣传月活动', 'date': '2025-11-11'},
{'title': '逛庙会学消防!厂甸大观园庙会打造消防“打卡点”', 'date': '2026-02-25'},
{'title': '“火焰蓝”守护年味!消防员坚守景区庙会护平安', 'date': '2026-02-21'},
],
},
},
{
"key": "interaction",
"data": {
'互动交流': [
{'title': '习近平会见全国应急管理系统先进模范和消防忠诚卫士表彰...', 'date': '2021-11-06'},
{'title': '北京市消防救援局挂牌', 'date': '2024-06-19'},
{'title': '市消防救援局即日起开展专项行动,推出一揽子“便民利企”措施', 'date': '2025-07-01'},
{'title': '北京开展石油化工生产装置灭火救援实战演练', 'date': '2025-09-30'},
{'title': '北京市全面启动 2025 年度消防宣传月活动', 'date': '2025-11-11'},
{'title': '逛庙会学消防!厂甸大观园庙会打造消防“打卡点”', 'date': '2026-02-25'},
{'title': '“火焰蓝”守护年味!消防员坚守景区庙会护平安', 'date': '2026-02-21'},
],
},
},
{
"key": "science",
"data": {
'消防科普': [
{'title': '习近平会见全国应急管理系统先进模范和消防忠诚卫士表彰...', 'date': '2021-11-06'},
{'title': '北京市消防救援局挂牌', 'date': '2024-06-19'},
{'title': '市消防救援局即日起开展专项行动,推出一揽子“便民利企”措施', 'date': '2025-07-01'},
{'title': '北京开展石油化工生产装置灭火救援实战演练', 'date': '2025-09-30'},
{'title': '北京市全面启动 2025 年度消防宣传月活动', 'date': '2025-11-11'},
{'title': '逛庙会学消防!厂甸大观园庙会打造消防“打卡点”', 'date': '2026-02-25'},
{'title': '“火焰蓝”守护年味!消防员坚守景区庙会护平安', 'date': '2026-02-21'},
],
},
}
]
main.title: all_articles[:7]
}
})
logger.info(section_data)
carousel = {
"key": "index",
"data": [
@@ -135,112 +184,100 @@ def about(request):
def news(request):
sections = [
sections = NewsSection.objects.filter(enabled=True).all().order_by('order')
section_data = [
{
"key": "fire_news",
"key": section.code,
"data": {
"消防要闻": [
{'title': '习近平会见全国应急管理系统先进模范和消防忠诚卫士表彰...', 'date': '2021-11-06'},
{'title': '北京市消防救援局挂牌', 'date': '2024-06-19'},
{'title': '市消防救援局即日起开展专项行动,推出一揽子“便民利企”措施', 'date': '2025-07-01'},
{'title': '北京开展石油化工生产装置灭火救援实战演练', 'date': '2025-09-30'},
{'title': '北京市全面启动 2025 年度消防宣传月活动', 'date': '2025-11-11'},
{'title': '逛庙会学消防!厂甸大观园庙会打造消防“打卡点”', 'date': '2026-02-25'},
{'title': '“火焰蓝”守护年味!消防员坚守景区庙会护平安', 'date': '2026-02-21'},
]
}
},
{
"key": "local_dynamic",
"data": {
"基层动态": [
{'title': '某支队开展冬季练兵比武活动', 'date': '2023-12-01'},
{'title': '社区微型消防站进行应急演练', 'date': '2023-12-05'},
{'title': '朝阳区举办消防安全知识讲座', 'date': '2024-01-15'},
]
}
},
{
"key": "state_council",
"data": {
"国务院新闻": [
{'title': '国务院安委会部署全国安全生产大检查', 'date': '2023-11-20'},
]
section.name: section.news_set.filter(is_published=True)[:7],
}
}
for section in sections
]
context = {
'sections': sections,
'sections': section_data,
}
logger.info(context)
return render(request, 'front/news.html', context)
def info(request):
def info(request, main):
"""信息公开"""
sections = [
logger.info(f"正在访问 {main}")
main_section = MainMenu.objects.filter(code=main).first()
if not main_section:
raise Http404("不存在的板块")
sections = MainMenu.objects.filter(parent__isnull=False, parent__code=main).order_by('order')
sections_data = [
{
"key": "notice",
"key": section.code,
"data": {
"通知通告": [
{'title': '关于第二轮中央生态环境保护督察第四十一项整改任务销号...', 'date': '2026-03-11'},
{'title': '关于第二轮中央生态环境保护督察第三十八项整改任务销号...', 'date': '2026-03-11'},
{'title': '公告送达通知', 'date': '2026-03-10'},
{'title': '吉林省长白山保护开发区管理委员会规划和自然资源局行政...', 'date': '2026-03-06'},
{'title': '吉林省长白山保护开发区管理委员会规划和自然资源局行政...', 'date': '2026-03-06'},
{'title': '吉林省长白山保护开发区管理委员会规划和自然资源局行政...', 'date': '2026-03-06'},
]
}
},
{
"key": "law",
"data": {
"法律法规": [
# ⚠️ 请替换为真实的法律法规数据
{'title': '关于第二轮中央生态环境保护督察第四十一项整改任务销号...', 'date': '2026-03-11'},
{'title': '关于第二轮中央生态环境保护督察第三十八项整改任务销号...', 'date': '2026-03-11'},
{'title': '公告送达通知', 'date': '2026-03-10'},
{'title': '吉林省长白山保护开发区管理委员会规划和自然资源局行政...', 'date': '2026-03-06'},
{'title': '吉林省长白山保护开发区管理委员会规划和自然资源局行政...', 'date': '2026-03-06'},
{'title': '吉林省长白山保护开发区管理委员会规划和自然资源局行政...', 'date': '2026-03-06'},
]
}
},
{
"key": "policy_doc",
"data": {
"政策文件": [
{'title': '中共长白山保护开发区工委办公室关于印发杨文慧同志在 2026...', 'date': '2026-03-05'},
{'title': '长白山管委会办公室关于印发《长白山保护开发区落实<吉林省...', 'date': '2026-02-28'},
{'title': '长白山保护开发区管理委员会 2025 年度行政执法工作报告', 'date': '2026-01-30'},
{'title': '长白山管委会办公室关于印发《美丽长白山建设行动方案(202...', 'date': '2025-12-31'},
{'title': '长白山管委会办公室关于印发《长白山保护开发区碳达峰实施...', 'date': '2025-12-31'},
{'title': '《长白山保护开发区防雷减灾管理办法》政策解读', 'date': '2025-12-12'},
]
}
},
{
"key": "policy_interp",
"data": {
"政策解读": [
{'title': '《长白山保护开发区防雷减灾管理办法》政策解读', 'date': '2025-12-12'},
{'title': '《长白山保护开发区旅游漂流活动管理规范》政策解读', 'date': '2025-07-23'},
{'title': '《长白山 40 米射电望远镜电磁波宁静区保护办法》政策解读', 'date': '2025-07-23'},
{'title': '《长白山保护开发区古树名木管理办法(试行)》政策解读', 'date': '2025-06-18'},
{'title': '《长白山保护开发区公共租赁住房管理办法》政策解读', 'date': '2025-04-08'},
{'title': '《长白山保护开发区旅游民宿管理与服务规范(试行)》政策解读', 'date': '2024-12-31'},
]
section.title: section.article_set.filter(is_published=True).order_by('-created_at')[:7],
}
}
]
for section in sections]
logger.info(sections_data)
context = {
'sections': sections,
'main_section': main_section,
'sections': sections_data,
}
return render(request, 'front/info.html', context=context)
def main_article_list(request, main):
"""信息公开"""
logger.info(f"正在访问 {main}")
main_section = MainMenu.objects.filter(code=main).first()
if not main_section:
raise Http404("不存在的板块")
articles_qs = Article.objects.filter(is_published=True).order_by('-created_at')
sections = main_section.active_children.order_by('order').prefetch_related(
Prefetch('article_set', queryset=articles_qs, to_attr='latest_articles')
)
section_data = {
"key": main_section,
"data": {
main_section.title: [
article
for section in sections
for article in section.latest_articles[:7]
],
}
}
logger.info(section_data)
context = {
'main_section': main_section,
'sections': sections,
'articles': [
article
for section in sections
for article in section.latest_articles[:7]
]
}
return render(request, 'front/list.html', context=context)
def sub_article_list(request, main: str, sub: str):
"""信息公开"""
logger.info(f"正在访问 {main}")
sections = MainMenu.objects.all().order_by('order')
main_section = sections.filter(code=main).first()
sub_section = sections.filter(code=sub, parent__code=main).first()
logger.info(f"主板块 {main_section} 子板块 {sub_section}")
if not sub_section or not main_section:
raise Http404("不存在的板块")
context = {
'main_section': main_section,
'sub_section': sub_section,
'sections': sections.filter(parent__code=main),
'articles': sub_section.article_set.filter(is_published=True).order_by('-created_at')[:21]
}
return render(request, 'front/list.html', context=context)
def service(request):
"""办事服务"""
q = request.GET.get('q') or "办事指南"
@@ -286,7 +323,7 @@ def service(request):
def party(request):
"""党建引领"""
sections = [
sections: List[Dict] = [
{
"key": "party_work",
"data": {
@@ -329,7 +366,7 @@ def party(request):
},
]
carousel = {
carousel: Dict = {
"key": "index",
"data": [
{