Results

What this note produces is not a fantasy WordPress clone. It produces a realistic Django CMS baseline with clear boundaries. Shared abstract models keep publication and deletion logic consistent. Site and SiteSetting create a stable configuration layer. A unified taxonomy path remains open. Media, comments, navigation, SEO, and revisions are all given explicit places in the model graph instead of being treated as undefined future additions.

Just as importantly, the document defines what not to do yet. That makes the design implementable. The system can become useful early through Django admin without needing full theme support, plugin parity, or a complex visual editor.

The source also includes a full English restatement of the Japanese specification. That means the design is already positioned for bilingual team sharing, which is a practical benefit in its own right.

Prerequisites

I wanted a blog/CMS foundation that keeps the parts of WordPress that matter in day-to-day operation without inheriting the full complexity of WordPress compatibility. The source note lays out that foundation in a disciplined way: posts, pages, categories, tags, comments, media, menus, revision history, drafts, scheduled publishing, and visibility control, all implemented with Django as the core framework.

This is not a code dump. It is a design document for deciding what should exist, how responsibilities should be separated, where constraints should live, and in what order the system should be built. The most important choice is that Django admin is treated as the first operational UI. That keeps the initial scope realistic, because content editing and publishing workflows can start working before a custom frontend or API layer is finished.

Scope

The document starts by being clear about purpose and non-goals, and that matters. The goal is to cover the practical WordPress concepts people actually use: posts, pages, taxonomy, comments, media, navigation, drafts, scheduling, and revisions. The goal is not to recreate multisite parity, plugin compatibility, theme compatibility, Gutenberg parity, or a full WYSIWYG experience in the first phase.

That constraint is what keeps the architecture sane. If I try to mimic WordPress too literally, I end up designing for every extension point before the core content model is even stable. The note instead takes a more sustainable approach: define a clean Django-native core first, then leave room for APIs, richer editors, search, redirects, audit logs, and multilingual support later.

Design Decisions

Overall Architecture

Direction

The architectural direction is straightforward: split concerns by app, keep public URLs slug-based, centralize publish logic, and design with PostgreSQL in mind. That means JSONField, full-text search readiness, and indexes are part of the baseline instead of afterthoughts.

I also like the decision to keep publish state explicit. A content system becomes fragile when drafts, scheduled content, and private visibility are scattered across ad hoc flags. Here, the document pulls those concerns into common fields so the rules can stay consistent across admin views, public pages, and future APIs.

The proposed project layout is this:

  project/
├── config/
│   ├── settings/
│   │   ├── base.py
│   │   ├── dev.py
│   │   └── prod.py
│   ├── urls.py
│   ├── asgi.py
│   └── wsgi.py
├── apps/
│   ├── accounts/
│   ├── core/
│   ├── content/
│   ├── taxonomy/
│   ├── media/
│   ├── comments/
│   ├── navigation/
│   └── seo/
├── templates/
├── static/
└── locale/
  

This separation matters because it prevents content logic, navigation logic, media concerns, and SEO metadata from collapsing into one oversized app. WordPress may present a unified editorial surface, but the implementation does not need to become monolithic to achieve that experience.

Naming and Design Rules

Public URLs are based on slugs rather than exposed numeric IDs. Public models share publish state and publication time. Deletion is soft by default through deleted_at, and primary images are modeled explicitly through featured_media. None of those choices are flashy, but each one removes ambiguity that would otherwise leak into templates, admin logic, and publishing queries.

WordPress Concept Mapping

The note defines a clean conceptual mapping from WordPress concepts into Django models:

WordPress conceptDjango-side mapping
Post / Pagecontent.Post / content.Page
Category / Tagtaxonomy.Term or Category / Tag
Post Metacontent.PostMeta
Mediamedia.MediaAsset
Commentcomments.Comment
Menunavigation.Menu / MenuItem
Revisioncontent.Revision
Site Optionscore.SiteSetting

What I find useful here is that the mapping is familiar enough for WordPress-style thinking, but the implementation is still clearly Django-oriented. It keeps the mental model approachable without copying the internals too literally.

Implementation Details

Model Design

Shared Abstract Models

The shared abstract models are the real backbone of the design:

  • TimeStampedModel
  • SoftDeleteModel
  • PublishableModel
  • SluggedModel

That set gives every public content model the same language for timestamps, deletion safety, publication state, and URL identity. In practice, that is what keeps the system coherent. If Post, Page, and future content types all answer publication and visibility questions differently, the CMS becomes inconsistent almost immediately.

core

Site is introduced even though the initial scope is single-site. I think that is the right tradeoff. Adding site early keeps the entire model graph ready for domain-specific settings, locale handling, and eventual multi-site expansion without forcing a rewrite later.

SiteSetting plays the role of a lightweight options store. Using JSONField for value is a pragmatic choice because settings often stop being plain strings once a real system starts evolving.

accounts

The user model stays simple by default. The note only suggests optional fields like display_name and avatar_media, and keeps roles conceptually small: Editor and Admin. That is consistent with the rest of the document. It avoids premature complexity and spends design effort where the publishing workflow actually depends on it.

taxonomy

The taxonomy section is one of the more important design choices. The recommended model is a unified Term with kind distinguishing category, tag, and future custom taxonomies. That gives the system room to grow into series, author groupings, region tags, or other taxonomies without multiplying table patterns.

There is still room for separate Category and Tag models, but the note explicitly points out that a single Term model is easier in the long run. I agree with that direction. It is the cleaner tradeoff unless there is a very strong reason to optimize for short-term simplicity.

media

MediaAsset is designed as more than a file pointer. It includes metadata such as MIME type, dimensions, alt text, caption, credit, and a sha256 hash for deduplication. That detail matters because media management becomes painful very quickly if accessibility and deduplication are left outside the model.

The note also leaves room for a separate image rendition model if thumbnails or derived assets become necessary. That is a good boundary. It avoids overloading the base media table while still planning for future needs.

content

The content layer is split into Post, Page, PostMeta, and Revision.

Post carries the fields that matter for a real publishing system: author, slug, excerpt, body, body format, featured media, publish state, password protection, comment toggle, comment count cache, SEO linkage, and taxonomy relations. Page stays structurally similar but does not assume categories or tags by default.

That separation is worth calling out. A single polymorphic content model would be more WordPress-like, but for an initial Django implementation, keeping Post and Page separate is usually easier to reason about in admin, queries, and templates.

PostMeta is the escape hatch for flexible extension. The note even states the tradeoff directly: WordPress-style multiple values per key are possible, but unique(post, key) is safer operationally. That is a good example of the document favoring maintainability over imitation.

Revision captures snapshots for rollback. That is one of those features that feels optional until editors actually need it. Putting it into the initial design prevents it from becoming a bolted-on afterthought.

comments

The comment model includes moderation states, parent-child threading, author identity fields, ip_hash, and user_agent. I think the ip_hash note is especially practical. The document is not merely copying WordPress-style comments; it is also choosing a safer data-handling posture from the start.

The rule is intentionally simple: only approved comments are public. Thread depth limits belong in display logic, not in the model.

Navigation is modeled through Menu and MenuItem. The most important rule is that a menu item should represent either a raw URL or a linked Post/Page, but not both. When a Post or Page is linked, get_absolute_url() takes precedence. That single rule makes navigation more resilient when slugs or paths change.

SEO

SEOEntry is kept separate from core content tables. I prefer that choice because SEO metadata tends to grow in scope over time: canonical URLs, OGP, robots directives, structured data references, and more. Keeping it isolated helps preserve clarity in the base content models.

Public URL Design

The public URL structure is intentionally simple:

  • Blog index: /blog/
  • Post detail: /blog/<slug>/
  • Monthly archive: /blog/YYYY/MM/
  • Page: /<slug>/ or /pages/<slug>/
  • Category: /category/<slug>/
  • Tag: /tag/<slug>/

This is the kind of structure that both editors and developers can understand without explanation. The option to place pages directly under the root is especially useful for corporate site pages or landing-page-style content.

Publishing Workflow

The workflow states are:

  • draft
  • pending
  • private
  • scheduled
  • published

The public visibility condition is spelled out explicitly:

  status == published
AND published_at <= now
AND visibility == public
AND deleted_at IS NULL
  

That is exactly the kind of rule worth centralizing early. Once this logic is stable, it can be reused in querysets, managers, templates, feeds, and APIs without subtle divergence.

Admin Requirements

The Django admin requirements are practical rather than decorative:

  • list filters for status, author, and publication time
  • automatic slug generation plus slug_lock
  • autocomplete for taxonomy relations
  • media preview and alt-text editing
  • comment moderation
  • revision browsing and restore

This section reinforces the main design stance of the note. The admin experience is not secondary. It is the initial product surface for operating the CMS.

The search section is small but useful. It allows a minimal icontains implementation while recommending PostgreSQL full-text search with SearchVector and GIN indexes as the real target. It also notes filtering by taxonomy, author, and date range. That keeps the design grounded in a plausible migration path instead of forcing a heavyweight search implementation from day one.

Implementation Order

The recommended build order is:

  1. Site, User, Post, Page
  2. Taxonomy (Term) and M2M relations
  3. MediaAsset
  4. Comments
  5. Navigation
  6. Revisions
  7. SEO

I think this sequence is one of the strongest parts of the document. It prioritizes the smallest slice that produces a believable WordPress-like authoring experience, then layers in organization, media, moderation, navigation, rollback, and metadata.

Caveats

The final section keeps future work visible without forcing it into the first milestone. Audit logs, redirect management, RSS/Atom feeds, sitemap.xml, PostgreSQL full-text search, and multilingual support are all called out explicitly. That kind of note is useful because it prevents the initial architecture from accidentally blocking the next round of features.

Next Actions

If I were turning this directly into implementation, I would start with core, content, and taxonomy, and I would codify the publication condition in managers or querysets immediately. That would give the rest of the system a stable base for admin screens, public views, and tests.

The note also makes several disciplined tradeoffs that are worth preserving during implementation: keep Post and Page separate at first, keep SEO metadata separate, keep PostMeta as a controlled escape hatch, and keep Term available as the future-facing taxonomy model. None of these choices are accidental. They all reduce the chance of repainting the architecture later.

At this point, the remaining work is mostly translational rather than conceptual. The specification is already detailed enough to become Django models, migrations, admin classes, URL patterns, queryset helpers, and starter templates. The main question is no longer what the platform should be. It is how quickly and carefully to convert this specification into code.