Skip to content

feat: logging替换print/N+1优化/站内搜索/主题过渡一致/404-500页/评分UI/空状态/评论回显/PostListView排序 - #45

Open
xiokuai wants to merge 3 commits into
aba2222:mainfrom
xiokuai:fix/theme-scope-bug
Open

feat: logging替换print/N+1优化/站内搜索/主题过渡一致/404-500页/评分UI/空状态/评论回显/PostListView排序#45
xiokuai wants to merge 3 commits into
aba2222:mainfrom
xiokuai:fix/theme-scope-bug

Conversation

@xiokuai

@xiokuai xiokuai commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

本次 PR 包含以下修复和优化(共 9 项用户需求 + 附带修复)

1. print(forms.errors) → Django logging 替换

  • lean_forum/settings.py 新增 LOGGING 配置:root WARNING 级 + forum logger DEBUG/INFO 级 + django logger INFO 级,统一 {asctime} {levelname} {name} {message} 格式
  • forum/views.py 全部原先的 print(forms.errors) 统一改为:
    • logger.warning("xxx 表单校验失败: user=%s errors=%s", ...) 用于表单类失败
    • logger.exception("xxx 失败") 用于 webpush / 注册 等异常捕获块
    • UserRegistrationView API 校验失败也走 logger.warning

2. N+1 查询优化(高命中页面)

  • 首页 index
    • Item.objects.annotate(avg_score=Avg('rating__score'), rating_count=Count('rating')),模板直接用 item.avg_score / item.rating_count,不再调用方法触发额外查询
    • Post.objects.select_related('author').order_by('-created_at')[:6],避免循环里 post.author 再查
  • 站内搜索 search_view
    • Collection.objects.select_related('owner').annotate(post_count=Count('collection_posts'))
    • Item.objects.annotate(avg_score + rating_count) 同上
  • 合集列表 collection_list
    • Collection.objects.select_related('owner').annotate(post_count)
    • 模板 {{ collection.collection_posts.count }}{{ collection.post_count }},消灭列表 N+1
  • 合集详情 collection_detail
    • collection.collection_posts.select_related('post', 'post__author') 合辑内帖子 + 作者一次取出

3. 页面 404 / 空状态体验

  • 自定义 404 页 templates/404.html
    • 404 大数字 + 清晰文案 + 三个快捷按钮(返回首页 / 浏览文章 / 站内搜索)
    • 底部卡片列出「您可以尝试」排查建议
  • 自定义 500 页 templates/500.html
    • 500 大数字 + 管理员通知语义 + 刷新重试按钮(window.location.reload)
  • lean_forum/urls.py 配置 handler404 = 'forum.views.custom_404_view' / handler500,views.py 新增两个对应 view
  • 各列表页空状态统一
    • index:items 空 → alert-info "暂时没有可打分项目";posts 空 → alert-info 引导点击发新帖
    • post_list:无搜索结果时 alert-light 提示换关键词 / 看全部;无帖子时引导发新帖
    • collection_list:空状态 alert-light,登录用户引导创建第一个合集,访客提示登录后创建
    • search:三区块(帖子/合集/打分项目)各自独立空状态 alert,未输入关键词时提示「请输入关键词开始搜索」

4. 评论表单显示 / 未保存内容丢失

  • PostDetailView.post() 原先校验失败用 redirect → 丢失用户输入:改为把校验失败的 forms 对象传入 _post_detail_context(comment_form=forms),直接 render(request, 'forum/post_detail.html', ctx),模板 {{ forms.as_p }} 自然回显
  • collection_post_detail() POST 评论分支同样改为 render 回显
  • post_create / post_edit / comment_edit / collection_create / collection_edit 原本就保留 form 实例,本次再确认 + messages 补齐「已保留您当前的输入」
  • 所有校验失败统一 messages.error 提示,同时 for field, errs in forms.errors.items(): messages.warning(...) 列出字段级错误

5. PostListView 无排序

  • get_queryset() 显式 .order_by('-created_at'),不再依赖表的默认顺序
  • 叠加 ?q= 搜索过滤后仍保持倒序
  • get_context_data 注入 qpost_count(= 当前过滤条件下 count),模板头部正确显示搜索词与数量 / 清除按钮

6. Item 相关:评分页 & 首页区块没对应 UI

  • rate_item.html 评分页重写
    • header 展示「为 XXX 打分」+ 说明文案
    • 信息卡:左侧「平均评分」→ 5 颗 star + floatformat:1 + (X 人已评);如有 user_rating,右侧「我的评分」同样星星 + 数值
    • 表单 select 1-5 星附中文描述(1 星很差 / 2 较差 / 3 一般 / 4 不错 / 5 很棒),用户已有评分时预选
    • 按钮根据是否已评分切换「更新评分 / 提交评分」,附返回首页按钮
  • 首页 index Item 卡片
    • h5 card-title 下方新增 card-subtitle:5 颗星星(根据 avg_score 切换 is-muted)
    • 下方显示 平均分 X.X (X 人评)
  • 搜索页 search.html Item 区块:与首页卡片一致的星星 + 人数 UI
  • base.css .star { color:#d4a017 } / .star.is-muted { color: var(--bs-border-color) } 统一样式

7. messages 未全部覆盖 {info, success, warning, error}

完整覆盖四类:

  • info:登录欢迎回来、登出「已安全登出」、账户删除「再见」、合集中移除帖子 / 上移下移顺序、没有新帖子被添加、重复添加到合集时「已在合集中」
  • success:注册、发帖、删帖、更新评分 / 新增评分、评论发布、帖子编辑、评论更新 / 删除、合集创建 / 修改 / 删除、添加帖子到合集、添加 N 篇到合集
  • warning:未登录尝试发表评论、所有字段级表单校验错误([{field}] {err} 格式)
  • error:登录失败、注册失败、评分非法、帖子校验失败、评论校验失败、删除确认标题不匹配、评论删除算术题答案错误、账户删除双因子验证失败

8. 搜索(站内检索)

  • 后端 views.search_view
    • Post.objects.select_related('author') / Collection.objects.select_related('owner').annotate(post_count) / Item.objects.annotate(avg_score, rating_count)
    • q 非空时分别对三模型用 Q(...) | Q(...) icontains 过滤
    • 帖子 Paginator 20 条分页;合集与项目各取前 10 条一并展示
  • forum/urls.py 新增 path('search/', views.search_view, name='search')
  • search.html 模板
    • 大号搜索框(form-control-lg autofocus)
    • 三区块结果:帖子(分页) / 合集结果(list-group 列表,附创建者与时间) / 打分项目(卡片网格 + 星星)
    • 每区块独立空状态 alert
    • 未输入关键词时单独 alert-info 引导
  • base.html 导航栏:右侧新增站内搜索入口(input-group + submit 按钮,action=search,method=get,role=search aria-label)
  • post_list.html 页头:专属帖子范围搜索框,搜索后有「清除」链接回全部

9. 主题圆圈扩散 + body 背景色过渡不一致

原先切换主题时,圆圈扩散和 body 背景色不同步,要么先切要么后切,有明显视觉割裂。

base CSS 统一

  • body { transition: background-color 280ms cubic-bezier(0.4, 0, 0.2, 1), color 280ms ... } 过渡与缓动固定
  • .theme-reveal 固定层:position:fixed; inset:0; z-index:9999; pointer-events:noneclip-path: circle(0 at var(--reveal-x/y)),背景色 --theme-reveal-color
  • .theme-reveal.is-playing 触发动画:520ms cubic-bezier(0.4,0,0.2,1) forwards
  • keyframes theme-reveal-expand:0% circle(0) opacity 1 → 55% 仍 opacity 1 → 100% circle(150vmax) opacity 0。刻意让 55% 时刻圆圈已盖过主体但还未淡出

JS playThemeReveal(next, originEl)

  1. _revealLock 防抖,防止连点
  2. 降级条件:prefers-reduced-motion: reduce / 无 originEl → 直接 syncTheme,不播动画
  3. getBoundingClientRect 取按钮中心 cx/cy → setProperty('--reveal-x', cx+'px') / --reveal-y / --theme-reveal-color(= getThemeBg(next) 读 CSS 变量)
  4. 强制 reflow 后加 is-playing 启动动画
  5. 286ms 后(520 × 0.55 = 286ms)setTimeout 调用 syncTheme(next)——此时动画正好走到 55% 圆圈盖住屏幕,body 280ms 的 background-color transition 结束点 ≈ 圆圈淡出开始点,视觉完全同步
  6. animationend 清理层 + 释放锁;额外 1100ms 保险清理避免动画不触发时锁死

同步辅助函数 syncTheme:统一切换 data-bs-theme + 更新太阳/月亮图标 + markdown CSS disabled + highlight.js CSS disabled(head 内 IIFE 已先处理避免 FOUC,body 末尾初始调用一次再建立事件)

主题按钮点击 → playThemeReveal 传入 themeToggle 元素 → 圆圈从按钮中心扩散。


额外附带修复

  • rate_item created 判断逻辑反转 bug
    之前 created = Rating.objects.update_or_create(...)[1] is False 把 update_or_create 返回的 created 反过来用了,导致每次提示语都是「已更新 / 已创建」错位。改为:_obj, created = Rating.objects.update_or_create(...) 直接取原生 created 语义 → if created 提示「已为 XX 打 X 星」else 提示「已更新评分为 X 星」。
  • 新增 3 个 Bootstrap Icons SVG:house(首页按钮)/ search(搜索按钮)/ arrow-clockwise(500 页刷新按钮),补齐 404/500 和搜索页引用
  • Python语法自检通过,15 files changed, 1091 insertions(+), 176 deletions(-)

P1 将 getTheme 移入 head 的 IIFE 内, 导致 body 末尾脚本
调用 getTheme() 时抛出 ReferenceError, 整个脚本块崩溃,
主题切换按钮/图标更新/返回顶部按钮全部失效。

修复:
- head 中 getTheme 提升为全局函数, body 末尾可正常访问
- markdown/hljs 的 disabled 切换从 DOMContentLoaded 改为
  在 link 元素之后立即执行, 进一步消除 FOUC 窗口

基于 fix/p1-bugs 分支, 依赖 PR aba2222#43
@aba2222 aba2222 added the fix fix some bug label Aug 13, 2026
- Resolve base.html conflict with origin/main: keep minimal FOUC init pattern
- Promote getTheme to window.getTheme inside head IIFE, so the markdown/hljs stylesheet disabled switcher (also in head) can access it without ReferenceError
- Remove duplicate getTheme declaration at end of body (uses window global now)
- settings.py: SECRET_KEY one-liner, CORS_ALLOWED_ORIGINS list comprehension (per aba2222#43 review)
- md_editor.html: remove manual theme sync script (md_editor follows data-bs-theme natively, per aba2222#43 review)
- Test suite: 12/12 passing
1. print(forms.errors) → Django logging: 新增LOGGING配置,统一使用logger.warning/exception
2. N+1查询优化:index/search/collection_list使用annotate+select_related,避免循环内查询
3. 空状态体验:所有列表页(index/post_list/collection_list/search)统一Bootstrap alert空状态UI
4. 评论表单未保存内容丢失:校验失败时返回原form对象回显用户输入,同时messages提示保留
5. PostListView排序:默认按created_at倒序,支持q搜索参数
6. Item评分页&首页区块UI:rate_item.html星级展示+平均/用户评分,index.html&search.html Item卡片带星星
7. messages覆盖{info,success,warning,error}:登录/注册/发帖/删帖/评分/评论等全流程补齐
8. 站内搜索:search_view支持Post/Collection/Item多模型Q查询,search.html结果页,导航栏搜索入口
9. 主题圆圈扩散+body背景色过渡一致:theme-reveal动画520ms,55%处(286ms)切换主题配合body 280ms transition
10. 404/500自定义错误页:友好提示+快捷导航按钮+handler404/500配置
@xiokuai xiokuai changed the title fix: 修复主题切换功能失效(P1 IIFE 作用域导致 ReferenceError) feat: logging替换print/N+1优化/站内搜索/主题过渡一致/404-500页/评分UI/空状态/评论回显/PostListView排序 Aug 16, 2026
@aba2222

aba2222 commented Aug 18, 2026

Copy link
Copy Markdown
Owner

感谢你的贡献!为方便代码审查和维护,请将这些改动按照主要内容拆分成多个独立的 PR。每个 PR 应尽量只关注一个变更。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fix fix some bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants