前言
通过伪代码的方式记录思路和实现流程。
请总以仓库最新代码为准:senjianlu/sync-onenav-from-excel
OneNav 一为导航主题版本为 V4.1810。
方案概述
仓库地址:senjianlu/sync-onenav-from-excel
网址的增删改查对应的实现:app/models/OneNavSite.py
注意点
- Excel 表中的
网址自定义 ID是网址的主键,它在代码中一般是site_id和sync_site_id;而 WordPress 的数据结构中,以wp_posts表的 ID 作为网址的主键,它在代码中一般是post_id。 - 通过在
wp_postmeta表中新增一条meta_key为_sync_site_id的数据,来标识哪些是由 Excel 同步来的数据。 - Python3 脚本中将以
site表示 OneNav 中的网址这一概念。 models/OneNavSite.py将作为网址的对象存在,其拥有增、删、改和查方法。但是非
models内部的模块,尽量不要直接调用对象的方法。- 对
网址进行增删改查操作前,需要视情况做事前判断,例如:是否存在指定的网址分类或网址标签。 onenav/site.py中包含了增删改查前中后的所有操作,它作为OneNavSite对象的接口存在,任何对OneNavSite的操作请走site.py。- 唯一区分
网址分类的favorite_id可以与 WordPress 中的term_id划等号。 - 要查询
wp_term_relationships表中的关系时,使用的是term_taxonomy_id,因此需要先通过term_id在wp_term_taxonomy中找到对应的term_taxonomy_id。
涉及的表
wp_posts:保存网址的基础数据。wp_postmeta:保存网址的其他数据,例如查看数等。wp_term_relationships:保存网址和网址分类的所属关系。wp_term_taxonomy:保存网址分类下网址的总数。新增和删除的时候需要修改该表数据。
伪代码编写
OneNavSite 类
class OneNavSite():
"""
类说明: OneNav 网址类
"""
def __init__(self,
favorite_ids: list,
tag_ids: list,
title: str,
content: str,
link: str,
spare_links: list,
sescribe: str,
language: str,
country: str,
order: int,
thumbnail_pic_url: str,
preview_pic_url: str,
wechat_qr_pic_url: str,
_sync_site_id: str,
_post_id: int = None):
"""
函数说明: 初始化
:param favorite_ids: 网址分类 ID 列表
:param tag_ids: 网址标签 ID 列表
:param title: 标题
:param content: 内容
:param link: 链接
:param spare_links: 备用链接地址(其他站点)
:param sescribe: 一句话描述(简介)
:param language: 站点语言
:param country: 站点所在国家或地区
:param order: 排序
:param thumbnail_pic_url: LOGO,标志的图片链接
:param preview_pic_url: 网站预览截图的图片链接
:param wechat_qr_pic_url: 公众号二维码的图片链接
:param _sync_site_id: 用来将 Excel 中属于与表中数据建立关系的字段
"""
self.favorite_ids = favorite_ids
self.tag_ids = tag_ids
self.title = title
self.content = content
self.link = link
self.spare_links = spare_links
self.sescribe = sescribe
self.language = language
self.country = country
self.order = order
self.thumbnail_pic_url = thumbnail_pic_url
self.preview_pic_url = preview_pic_url
self.wechat_qr_pic_url = wechat_qr_pic_url
# 用来将 Excel 中属于与表中数据建立关系的字段
self._sync_site_id = _sync_site_id
# 插入表后的 post_id
self._post_id = _post_id
备用链接地址(其他站点)类
class OneNavSpareSite(): """ 类说明: OneNav 备用网址类 """ def __init__(self, name: str, url: str, note: str): """ 函数说明: 初始化 :param name: 站点名称 :param url: 站点链接 :param note: 备注 """ self.name = name self.url = url self.note = note
查 (select)
- 通过 Excel 表中的
_sync_site_id查询wp_postmeta表,获取post_id - 通过
post_id查询wp_posts表中的数据 - 通过
post_id查询wp_postmeta表中的数据 - 通过
post_id查询wp_term_relationships表中的网址数据 - 通过
wp_term_relationships表中的term_taxonomy_id查询wp_term_taxonomy表中的数据
@staticmethod
def select(sync_site_id: str, session):
"""
函数说明: 查询网址
:param sync_site_id: 用来将 Excel 中属于与表中数据建立关系的字段
:param session: 数据库会话
"""
# 1. 通过 _sync_site_id 查询网址在 wp_postmeta 表中对应的 post_id
wp_postmeta_row = session.query(WpPostmeta).filter(
WpPostmeta.meta_key == "_sync_site_id",
WpPostmeta.meta_value == sync_site_id
).first()
if not wp_postmeta_row:
return None
post_id = wp_postmeta_row.post_id
# 2. 通过 post_id 查询 wp_posts 表中的网址数据
wp_post_row = session.query(WpPosts).filter(
WpPosts.ID == post_id
).first()
if not wp_post_row:
return None
# 3. 通过 post_id 查询 wp_postmeta 表中的网址数据
wp_postmeta_rows = session.query(WpPostmeta).filter(
WpPostmeta.post_id == post_id
).all()
# 4. 通过 post_id 查询 wp_term_relationships 表中的网址数据
wp_term_relationships_rows = session.query(WpTermRelationships).filter(
WpTermRelationships.object_id == post_id
).all()
# 5. 通过 wp_term_relationships_rows 的 term_taxonomy_id 查询网址分类
wp_term_taxonomy_rows = session.query(WpTermTaxonomy).filter(
WpTermTaxonomy.term_taxonomy_id.in_([wp_term_relationships_row.term_taxonomy_id for wp_term_relationships_row in wp_term_relationships_rows])
).all()
# 6. 生成网址对象
site = _generate_class_from_rows(
sync_site_id=sync_site_id,
wp_post_row=wp_post_row,
wp_postmeta_rows=wp_postmeta_rows,
wp_term_taxonomy_rows=wp_term_taxonomy_rows
)
# 7. 返回
return site
增 (insert)
- 新增
wp_posts的数据 - 新增
wp_postmeta的数据 - 通过
favorite_ids和tag_ids获取wp_term_taxonomy中term_id符合的数据,获取term_taxonomy_id - 新增
wp_term_relationships的数据 - 更新
wp_term_taxonomy中对应行的count+ 1
def insert(self, domain, session):
"""
函数说明: 添加网址
:param domain: 导航站点域名
:param session: 数据库会话
"""
# 1. 生成 wp_posts 表数据
new_wp_posts_row = _generate_new_wp_posts_row(self)
# 2. 提交 wp_posts 表数据并获取 post_id
session.add(new_wp_posts_row)
session.commit()
post_id = new_wp_posts_row.ID
# print("post_id: ", post_id)
# 3. 更新 wp_posts 表数据中的 guid
new_wp_posts_row.guid = "{}/sites/{}.html".format(domain, post_id)
session.commit()
# 4. 生成 wp_postmeta 表数据
new_wp_postmeta_rows = _generate_new_wp_postmeta_rows(post_id, self)
# 5. 获取 wp_term_taxonomy 表数据
wp_term_taxonomy_rows = session.query(WpTermTaxonomy).filter(
or_(
WpTermTaxonomy.term_id.in_(self.favorite_ids),
WpTermTaxonomy.term_id.in_(self.tag_ids)
)
).all()
# 6. 生成 wp_term_relationships 表数据
new_wp_term_relationships_rows = _generate_new_wp_term_relationships_rows(post_id, wp_term_taxonomy_rows)
# 7. 添加数据
for new_wp_postmeta_row in new_wp_postmeta_rows:
session.add(new_wp_postmeta_row)
for new_wp_term_relationships_row in new_wp_term_relationships_rows:
session.add(new_wp_term_relationships_row)
# 8. 提交
session.commit()
# 9. 更新 wp_term_taxonomy 表数据
for new_wp_term_relationships_row in new_wp_term_relationships_rows:
session.query(WpTermTaxonomy).filter(
WpTermTaxonomy.term_taxonomy_id == new_wp_term_relationships_row.term_taxonomy_id
).update({
"count": WpTermTaxonomy.count + 1
})
# 10. 提交
session.commit()
改 (update)
- 更新
wp_posts中的数据 - 更新
wp_postmeta中的数据 - 判断网址分类和网址标签是否发生了变更
- 没有变更的话,接下来不做任何事
- 发生了变更的话
- 筛选出新增或删除的
term_id - 通过
term_id获取wp_term_taxonomy中term_id符合的数据,获取term_taxonomy_id - 新增或删除
wp_term_relationships表中的网址数据 - 更新
wp_term_taxonomy中对应行的count+ 1 或count- 1
- 筛选出新增或删除的
def update(self, session):
"""
函数说明: 更新网址
:param session: 数据库会话
"""
post_id = self._post_id
# 1. 生成 wp_posts 表数据
new_wp_posts_row = _generate_new_wp_posts_row(self)
# 2. 生成 wp_postmeta 表数据
new_wp_postmeta_rows = _generate_new_wp_postmeta_rows(post_id, self)
# 3. 获取 wp_term_taxonomy 表数据
wp_term_taxonomy_rows = session.query(WpTermTaxonomy).filter(
or_(
WpTermTaxonomy.term_id.in_(self.favorite_ids),
WpTermTaxonomy.term_id.in_(self.tag_ids)
)
).all()
# 4. 生成 wp_term_relationships 表数据
new_wp_term_relationships_rows = _generate_new_wp_term_relationships_rows(post_id, wp_term_taxonomy_rows)
# 5. 更新数据
# 5.1 更新 wp_posts 表数据
session.query(WpPosts).filter(WpPosts.ID == post_id).update({
"post_title": new_wp_posts_row.post_title,
"post_content": new_wp_posts_row.post_content,
"post_name": new_wp_posts_row.post_name,
"post_modified": new_wp_posts_row.post_modified,
"post_modified_gmt": new_wp_posts_row.post_modified_gmt
})
# 5.2 更新 wp_postmeta 表数据
for new_wp_postmeta_row in new_wp_postmeta_rows:
session.query(WpPostmeta).filter(
WpPostmeta.post_id == post_id,
WpPostmeta.meta_key == new_wp_postmeta_row.meta_key
).update({
"meta_value": new_wp_postmeta_row.meta_value
})
# 5.3 判断需要新增或删除的网址分类
wp_term_relationships_rows = session.query(WpTermRelationships).filter(
WpTermRelationships.object_id == post_id
).all()
old_term_taxonomy_ids = [wp_term_relationships_row.term_taxonomy_id for wp_term_relationships_row in wp_term_relationships_rows]
new_term_taxonomy_ids = [wp_term_taxonomy_row.term_taxonomy_id for wp_term_taxonomy_row in wp_term_taxonomy_rows]
term_taxonomy_ids_2_add = list(set(new_term_taxonomy_ids) - set(old_term_taxonomy_ids))
term_taxonomy_ids_2_delete = list(set(old_term_taxonomy_ids) - set(new_term_taxonomy_ids))
# 5.4 添加新的网址分类
for add_term_taxonomy_id in term_taxonomy_ids_2_add:
new_wp_term_relationships_row = WpTermRelationships(
object_id=post_id,
term_taxonomy_id=add_term_taxonomy_id,
term_order=0
)
session.add(new_wp_term_relationships_row)
session.query(WpTermTaxonomy).filter(
WpTermTaxonomy.term_taxonomy_id == add_term_taxonomy_id
).update({
"count": WpTermTaxonomy.count + 1
})
# 5.5 删除不需要的网址分类
for delete_term_taxonomy_id in term_taxonomy_ids_2_delete:
session.query(WpTermRelationships).filter(
WpTermRelationships.object_id == post_id,
WpTermRelationships.term_taxonomy_id == delete_term_taxonomy_id
).delete()
session.query(WpTermTaxonomy).filter(
WpTermTaxonomy.term_taxonomy_id == delete_term_taxonomy_id
).update({
"count": WpTermTaxonomy.count - 1
})
# 6. 提交
session.commit()
删 (delete)
- 删除
wp_posts中的数据 - 删除
wp_postmeat中的数据 - 删除
wp_term_relationships中的数据 - 通过
wp_term_relationships中关联的term_taxonomy_id,将wp_term_taxonomy中对应行的count- 1
def delete(self, session):
"""
函数说明: 删除网址
:param session: 数据库会话
"""
post_id = self._post_id
# 1. 删除 wp_posts 表数据
session.query(WpPosts).filter(WpPosts.ID == post_id).delete()
# 2. 删除 wp_postmeta 表数据
session.query(WpPostmeta).filter(WpPostmeta.post_id == post_id).delete()
# 3. 删除和更新网址分类的关联数据
wp_term_relationships_rows = session.query(WpTermRelationships).filter(
WpTermRelationships.object_id == post_id
).all()
for wp_term_relationships_row in wp_term_relationships_rows:
session.query(WpTermTaxonomy).filter(
WpTermTaxonomy.term_taxonomy_id == wp_term_relationships_row.term_taxonomy_id
).update({
"count": WpTermTaxonomy.count - 1
})
session.query(WpTermRelationships).filter(
WpTermRelationships.object_id == post_id
).delete()
# 4. 提交
session.commit()