From 3be287532d0117b0bd863c0c8fc6bbe18f67ba63 Mon Sep 17 00:00:00 2001 From: giles Date: Wed, 25 Feb 2026 11:47:50 +0000 Subject: [PATCH] Fix post_authors duplicate key during Ghost sync Add explicit flush after DELETE and dedup authors/tags to prevent autoflush-triggered IntegrityError on composite PK. Co-Authored-By: Claude Opus 4.6 --- blog/bp/blog/ghost/ghost_sync.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/blog/bp/blog/ghost/ghost_sync.py b/blog/bp/blog/ghost/ghost_sync.py index f1bd6fd..6bcc458 100644 --- a/blog/bp/blog/ghost/ghost_sync.py +++ b/blog/bp/blog/ghost/ghost_sync.py @@ -185,17 +185,25 @@ async def _upsert_post(sess: AsyncSession, gp: Dict[str, Any], author_map: Dict[ obj.user_id = user_id await sess.flush() - # rebuild post_authors + # rebuild post_authors (dedup to avoid composite PK conflicts from Ghost dupes) await sess.execute(delete(PostAuthor).where(PostAuthor.post_id == obj.id)) + await sess.flush() + seen_authors: set[int] = set() for idx, a in enumerate(gp.get("authors") or []): aa = author_map[a["id"]] - sess.add(PostAuthor(post_id=obj.id, author_id=aa.id, sort_order=idx)) + if aa.id not in seen_authors: + seen_authors.add(aa.id) + sess.add(PostAuthor(post_id=obj.id, author_id=aa.id, sort_order=idx)) - # rebuild post_tags + # rebuild post_tags (dedup similarly) await sess.execute(delete(PostTag).where(PostTag.post_id == obj.id)) + await sess.flush() + seen_tags: set[int] = set() for idx, t in enumerate(gp.get("tags") or []): tt = tag_map[t["id"]] - sess.add(PostTag(post_id=obj.id, tag_id=tt.id, sort_order=idx)) + if tt.id not in seen_tags: + seen_tags.add(tt.id) + sess.add(PostTag(post_id=obj.id, tag_id=tt.id, sort_order=idx)) # Auto-create PageConfig for pages if obj.is_page: