「公開・非公開」管理機能の実装

ウェブアプリの設計図

日付:2025年3月2日

Djangoブログに「公開・非公開」管理機能を追加する方法を解説。管理画面での制御、APIのフィルタリング、カテゴリ一覧の制限、推薦記事の調整など、既存のシステムに最小限の変更でスムーズに導入する手順を紹介します。

目 次

はじめに

Django を使ったブログシステムでは、「記事を非公開にしたい」「下書きとして保存したい」 というニーズが生じることがあります。

今回は、既存のシステムに大きな変更を加えずに「公開・非公開」の選択肢を導入 する方法について解説します。

1. is_published フィールドの追加

まず、記事を公開するかどうかを管理する BooleanField (is_published)Post モデルに追加しました。

PYTHON
class Post(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) title = models.CharField(max_length=255, verbose_name="タイトル") content = MarkdownxField(null=True, verbose_name="本文") is_pinned = models.BooleanField(default=False, verbose_name="ピン留め") # 公開・非公開を管理 is_published = models.BooleanField(default=False, verbose_name="公開する")

シンプルな is_published=True / False のブール値を持たせるだけで管理が可能になります。

これにより、新たな status フィールドを作ることなく、API や Django の admin 管理画面での実装が簡潔になりました。

2. 既存の記事を「公開済み」にするマイグレーション

新たに is_published を追加した場合、既存の記事は「非公開」扱いになってしまいます。
そのため、マイグレーション時に既存の記事をすべて「公開済み」に設定する ことで、既存データをスムーズに移行しました。

PYTHON
from django.db import migrations, models def set_is_published_true_for_existing_posts(apps, schema_editor): Post = apps.get_model('base', 'Post') Post.objects.all().update(is_published=True) class Migration(migrations.Migration): dependencies = [ ('base', '0011_alter_post_options_post_order'), ] operations = [ migrations.AddField( model_name='post', name='is_published', field=models.BooleanField(default=False, verbose_name='公開する'), ), migrations.RunPython(set_is_published_true_for_existing_posts, reverse_code=migrations.RunPython.noop), ]

これにより、既存のデータに影響を与えず、すべての記事を自動的に公開するように処理 ができました。

3. Django 管理画面で公開・非公開を制御

Django の管理画面から 公開・非公開を簡単に切り替えられるようにする ため、list_displayis_published を追加し、一覧で状態を確認できるようにしました。

PYTHON
@admin.register(Post) class PostAdmin(admin.ModelAdmin): list_display = ("title", "is_published", "is_pinned", "created_at") list_filter = ("is_published", "is_pinned") search_fields = ("title", "content") ordering = ("-created_at",)

これにより、管理者が チェックボックスで「公開」状態を切り替えたり、一括変更 したりできるようになりました。

4. API を「公開済みの記事のみ表示」に変更

Django REST Framework (DRF) で提供している API に対し、非公開の記事を除外しました。

PYTHON
class PostListViewSet(viewsets.ReadOnlyModelViewSet): queryset = Post.objects.filter(is_published=True).order_by("-custom_id", "-date") serializer_class = PostListSerializer

この修正により、API から 「公開されている記事のみ」 を取得できるようになり、フロントエンド側で不必要なフィルタリングをする必要がなくなりました。

5. カテゴリー一覧も「公開済みの記事があるもの」のみに制限

通常、Category モデルはすべてのカテゴリを返しますが、「非公開記事しかないカテゴリは取得されない」 ように変更しました。

PYTHON
class CategoryViewSet(viewsets.ReadOnlyModelViewSet): queryset = Category.objects.filter(post__is_published=True).distinct() serializer_class = CategorySerializer

6. 記事推薦・類似記事 API でも「公開済みのみ」適用

類似記事を提案する機能にも 「非公開の記事を除外」 するフィルタを適用しました。

PYTHON
@api_view(["GET"]) def recommend_and_opposite(request, slug, mode="both", **kwargs): try: target_post = Post.objects.get(slug=slug, is_published=True) # 非公開記事は 404 except Post.DoesNotExist: return Response({"error": "Article not found or not published"}, status=404)

この修正により、非公開記事が推薦リストに表示されることなく、安全に類似記事を表示できるようになりました。

まとめ

今回の対応により、以下の点がスムーズに実装できました:

  • シンプルな is_published フィールドで制御
  • Django 管理画面で簡単に公開・非公開を管理
  • API・検索・推薦機能でも「公開済みの記事のみ」を対象に変更
  • 非公開の記事を含むカテゴリは取得されないように制限

この方法なら、既存のブログシステムに大きな変更を加えず、スムーズに「公開・非公開」管理を導入 できます。