96SEO 2026-08-14 15:20 32
这不是一篇通用的技术教程,而是一次真实 Debug 的完整复盘。说起来,
问题本身很简单——“博客分类筛选不工作”——但往下挖了四层才发现。表象各异的四个 Bug 其实指向同一个设计缺陷。这个缺陷从项目的第一行代码就埋下了后续每次加功能都在上面打补丁,直到补丁本身变成了问题的一部分。老实说,

我想通过这个案例说清楚三件事:
在动手之前。先看清项目的三个主要数据实体和它们的存储方式:
Tag Category
───────────────────────────── ─────────────────────────────
Tag 表 Article.category
↑ ↑ _get_or_create_tags
后来需要侧边栏展示 → ↑
SiteSetting.blog_categories article_tags
再后来需要多入口编辑 → 没有重构,继续打补丁
关键对比:
使用者痛点:开发者经常因为「看似小改动」而引入多个隐藏的数据入口,导致后期排查成本指数级上升。
同一个语义数据存在两条以上写入方法。各方法指向不同存储位置,最终导致数据漂移。
正常情况:
编辑器 → _get_or_create_tags → Tag 表 → 所有读取方
↑ 唯一来源,永不漂移
再看问题情况。编辑器 → Article.category
管理台 → SiteSetting.blog_categories
↑ 两个写入目标,天然不一致
问题从表面到底层一共四层。每一层发现一个不同的 Bug,但最终都指向同一个根因。
现象:点击博客页的标签链接。URL 不变,页面刷新,
排查:打开浏览器开发者工具 → Elements → 查看标签 的 。
↑ 空的!话说回来,
原因:Kinja2 模板中运算符优先级错误导致空 。
修复:
{% set tag_url = '/blog?tag=' + tag_info.name %}
{% if current_category %}
{% set tag_url = tag_url + '&category=' + current_category %}
{% endif %}
现象:创建文章时选了新分类名,保存后博客侧边栏找不到该分类。
排查:
Article.category = "深度学习" → SiteSetting.blog_categories →
根因:两端存储位置不同——A=Article.category ,B=SiteSetting.blog_categories . 新分类从未同步到列表 B。
修复: 添加事后同步函数 .
def _ensure_category_in_list:
if not category:
return
cats = _get_category_list
if category not in cats:
cats.append
_save_category_list
现象: 修改文章分类后刷新页面仍显示旧分类。
排查: 查看 API 接收模型。
class ArticleUpdate:
至于title,Optional = None
content: Optional = None
summary: Optional = None
cover_image: Optional = None
is_published: Optional = None
# ❌ category 在哪里?
Pydantic 丢弃未声明字段,导致更新逻辑永远不会触发。
修复: 为模型添加 `category: Optional = None`.
现象: 侧边栏显示“文章:”,实际数量远大于显示值。不过,
排查: 模板变量仅使用 {{ articles|length }}。而后台已经计算出完整总数却未传递。
articles = query.order_by.limit.all
total = query.count # 已计算
return _ctx(request。articles=articles,# total=total ← 漏传!)
Fix: 将 total 作为上下文变量传递给模板即可。
: 前两类直接影响功能可用性。后两类虽表面无害,却都源自同一根本设计缺陷——缺乏对「数据完整链路」的把控。
从 Git 历史看功能演进时间线:
第1天:Article.category = Column // 简单字符串字段
再看第N天。SiteSetting.blog_categories // 为侧边栏新增平行 JSON 列表
至于第N+M天,文章编辑器自由输入分类 // 未建立制
第N+M+K天:管理台 分类 CRUD //
操作平行列表,无归一化
每一次决策在当时都合理,却在累计后形成「每个入口各自为政」 的架构。
通过 _ensure_category_in_list 实现「事后同步」,暂时消除「新建分类不出现」的问题,但仍保留双重存储结构。
# 新增 Category 表
class Category:
__tablename__ = "categories"
id = Column
name = Column,unique=True,nullable=False)
# Article 改为外键引用
class Article:
category_id = Column)
category_rel = relationship
def _get_or_create_category:
if not name:
return None
cat = db.query.filter).first
if not cat:
cat = Category)
db.add
db.flush
return cat.id
_save_category_list,etc.) | 字段 | 判断 | 选择 | 结果 |
|---|---|---|---|
/article.tags/ | > 复用 + 筛选 + 管理 | /Tag/ | ✓ 从不出错 |
/article.category/ | > 复用 + 筛选 + 管理 | /String/ | × 四处补丁 |
/article.cover_image/ | > 仅展示 | /String/ | ✓ 正常使用 |
Add article categories.
Design constraints:
· Must use an independent table .
· Provide `_get_or_create_category` helper.
· List all write/read paths.
Why it works: Once you spell out constraints,model generates correct schema instead of a quick‑and‑dirty string field.
What consistency risks does this design have?List every possible write path to “category” field.
Do y all point to same storage?
Result: AI will enumerate risks enabling you to catch m early.
Create a CONSISTENCY_GUIDELINES.md:
• Shared entities must use separate tables with FK links.
• Prohibit plain‑string fields plus parallel list caches.
• Every new entity requires a write‑path & read‑path audit.
• Follow Tag’s `_get_or_create_*` pattern.
When model loads this file each session it automatically respects those rules.
When reviewing generated snippets scan for:
✅ Good signals: categoryid = Column) _getorcreatecategory db.query.all
❌ Warning signals: category = Column) settings.xxxlist / xxxcache ensurexxx / syncxxx
If any warning appears。ask follow‑up questions before committing code.
Bad prompt:
I need a category field for articles.
AI: adds category = Column). Six months later you face drift.
Good prompt:
Add a category feature. Design must:
· Use an independent table with FK.
· Provide `_get_or_create_category` helper.
· Enumerate all read/write paths.
AI: creates Category table,foreign key category_id,unified read/write routes—no hidden drift.
Takeaway: The model’s capability is unchanged;success depends on how much structural guidance you give it.
// No furr lines needed
作为专业的SEO优化服务提供商,我们致力于通过科学、系统的搜索引擎优化策略,帮助企业在百度、Google等搜索引擎中获得更高的排名和流量。我们的服务涵盖网站结构优化、内容优化、技术SEO和链接建设等多个维度。
| 服务项目 | 基础套餐 | 标准套餐 | 高级定制 |
|---|---|---|---|
| 关键词优化数量 | 10-20个核心词 | 30-50个核心词+长尾词 | 80-150个全方位覆盖 |
| 内容优化 | 基础页面优化 | 全站内容优化+每月5篇原创 | 个性化内容策略+每月15篇原创 |
| 技术SEO | 基本技术检查 | 全面技术优化+移动适配 | 深度技术重构+性能优化 |
| 外链建设 | 每月5-10条 | 每月20-30条高质量外链 | 每月50+条多渠道外链 |
| 数据报告 | 月度基础报告 | 双周详细报告+分析 | 每周深度报告+策略调整 |
| 效果保障 | 3-6个月见效 | 2-4个月见效 | 1-3个月快速见效 |
我们的SEO优化服务遵循科学严谨的流程,确保每一步都基于数据分析和行业最佳实践:
全面检测网站技术问题、内容质量、竞争对手情况,制定个性化优化方案。
基于用户搜索意图和商业目标,制定全面的关键词矩阵和布局策略。
解决网站技术问题,优化网站结构,提升页面速度和移动端体验。
创作高质量原创内容,优化现有页面,建立内容更新机制。
获取高质量外部链接,建立品牌在线影响力,提升网站权威度。
持续监控排名、流量和转化数据,根据效果调整优化策略。
基于我们服务的客户数据统计,平均优化效果如下:
我们坚信,真正的SEO优化不仅仅是追求排名,而是通过提供优质内容、优化用户体验、建立网站权威,最终实现可持续的业务增长。我们的目标是与客户建立长期合作关系,共同成长。
Demand feedback