Skip to content
Go back

OneNav 一为导航通过 Python3 脚本实现网址的增删改查

| 0 Views Edit page

前言

通过伪代码的方式记录思路和实现流程。
请总以仓库最新代码为准:senjianlu/sync-onenav-from-excel
OneNav 一为导航主题版本为 V4.1810


方案概述

仓库地址:senjianlu/sync-onenav-from-excel
网址的增删改查对应的实现:app/models/OneNavSite.py

注意点

  • Excel 表中的 网址自定义 ID网址 的主键,它在代码中一般是 site_idsync_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_idwp_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)

  1. 通过 Excel 表中的 _sync_site_id 查询 wp_postmeta 表,获取 post_id
  2. 通过 post_id 查询 wp_posts 表中的数据
  3. 通过 post_id 查询 wp_postmeta 表中的数据
  4. 通过 post_id 查询 wp_term_relationships 表中的网址数据
  5. 通过 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)

  1. 新增 wp_posts 的数据
  2. 新增 wp_postmeta 的数据
  3. 通过 favorite_idstag_ids 获取 wp_term_taxonomyterm_id 符合的数据,获取 term_taxonomy_id
  4. 新增 wp_term_relationships 的数据
  5. 更新 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)

  1. 更新 wp_posts 中的数据
  2. 更新 wp_postmeta 中的数据
  3. 判断网址分类和网址标签是否发生了变更
    • 没有变更的话,接下来不做任何事
    • 发生了变更的话
      1. 筛选出新增或删除的 term_id
      2. 通过 term_id 获取 wp_term_taxonomyterm_id 符合的数据,获取 term_taxonomy_id
      3. 新增或删除 wp_term_relationships 表中的网址数据
      4. 更新 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)

  1. 删除 wp_posts 中的数据
  2. 删除 wp_postmeat 中的数据
  3. 删除 wp_term_relationships 中的数据
  4. 通过 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()

Edit page