Markdown ファイルを Django DRF にアップロードし、JSON API に変換するプロセスについて詳しく解説します。
前回の記事では、Next.js と Markdown で運用していたブログを Django REST Framework (DRF) を用いて API 化する背景について解説しました。
今回は、その最初のステップとして、Markdown ファイルを Django にバルクアップロードし、JSON API に変換するプロセスについて詳しく説明します。
この機能を導入することで、記事データの管理が容易になり、フロントエンドは API からデータを取得するだけで動作できるようになります。
Markdown ファイルをアップロードし、API で取得できる形にすることで、フロントエンドの負担を軽減し、システムの柔軟性を向上させることが目的です。
Django 側で Markdown ファイルを受け取り、データベースに保存するまでの流れは次の通りです。
これを Django Admin のカスタムビューを作成することで実装しました。
Django の管理画面から Markdown ファイルをアップロードできるようにするため、カスタムビューを作成しました。
admin/upload_views.py
PYTHONimport frontmatter from django.shortcuts import render, redirect from django.db import transaction from django.contrib import messages from django.utils.text import slugify from base.forms import BulkUploadForm from base.models import Post, Category, Theme from base.embedding_utils import embed_full_text def upload_view(request): if request.method == "POST": form = BulkUploadForm(request.POST, request.FILES) if form.is_valid(): files = request.FILES.getlist("file") # ファイル数の上限チェック(例: 最大10個まで) if len(files) > 10: messages.error(request, "ファイルは最大10個までアップロード可能です。") return redirect("admin:base_post_changelist") for uploaded_file in files: # ファイルオブジェクトなら read() してバイト列を取得 if hasattr(uploaded_file, 'read'): file_data = uploaded_file.read() else: file_data = uploaded_file # ファイル名から拡張子を除いた部分を slug として取得 filename = uploaded_file.name # 例: "my-post.md" file_slug = slugify(filename.rsplit('.', 1)[0]) # "my-post" # バイト列をUTF-8でデコードして文字列に変換 text = file_data.decode("utf-8") parsed = frontmatter.loads(text) metadata = parsed.metadata content = parsed.content with transaction.atomic(): # 必須項目チェックなど省略 custom_id_val = metadata["id"] try: post = Post.objects.get(custom_id=custom_id_val) except Post.DoesNotExist: post = Post(custom_id=custom_id_val) post.title = metadata["title"] post.date = metadata["date"] post.description = metadata.get("description", "") post.content = content post.is_pinned = metadata.get("isPinned", False) # category の処理: 文字列から Category オブジェクトを取得または作成 category_name = metadata.get("category", "").strip() if category_name: category_obj, created = Category.objects.get_or_create(name=category_name) post.category = category_obj else: post.category = None # theme の処理も同様に theme_name = metadata.get("theme", "").strip() if theme_name: theme_obj, created = Theme.objects.get_or_create(name=theme_name) post.theme = theme_obj else: post.theme = None # 新しく生成した slug を post.slug にセット post.slug = file_slug post.save() # 埋め込み生成 embedding = embed_full_text(post.content) post.embedding = embedding post.save() messages.success(request, "Markdownファイルのアップロードが完了しました。") return redirect("admin:base_post_changelist") else: form = BulkUploadForm() context = { "form": form, "title": ".md ファイル アップロード(フロントマター解析&Embedding)", "opts": Post._meta, } return render(request, "admin/upload.html", context)
このコードでは、アップロードされた Markdown ファイルをパースし、フロントマターから必要な情報を抽出してデータベースに保存する仕組みを構築しています。
Django では、モデルのデータを JSON 形式で出力するために Serializer を定義します。
serializers.py
PYTHONfrom rest_framework import serializers from base.models import Post class PostSerializer(serializers.ModelSerializer): category_name = serializers.CharField(source="category.name", read_only=True) theme_name = serializers.CharField(source="theme.name", read_only=True) class Meta: model = Post fields = ("custom_id", "title", "date", "description", "content", "category_name", "theme_name", "slug")
API では、記事データを提供する PostListViewSet を定義し、以下の機能を実装しました。
PostListViewSet
の実装以下のように、Django REST Framework の viewsets.ReadOnlyModelViewSet
を利用して、記事データを取得できる API を作成しました。
PYTHONfrom rest_framework import viewsets, filters from rest_framework.pagination import PageNumberPagination from base.models import Post from base.serializers import PostListSerializer, PostDetailSerializer class StandardResultsSetPagination(PageNumberPagination): page_size = 50 page_size_query_param = 'page_size' max_page_size = 100 class PostListViewSet(viewsets.ReadOnlyModelViewSet): queryset = Post.objects.all().order_by("-custom_id", "-date") lookup_field = "slug" pagination_class = StandardResultsSetPagination # ページネーションの適用 filter_backends = [filters.SearchFilter] # 検索機能の有効化 search_fields = ['title', 'description', 'category__name', 'theme__name'] # 検索対象フィールド def get_serializer_class(self): if self.action == 'retrieve': return PostDetailSerializer return PostListSerializer
この API により、/api/posts/
から記事一覧を取得でき、検索やページネーションにも対応可能になりました。
今回は、Django DRF を用いて Markdown ファイルをアップロードし、API 化する仕組み について詳しく解説しました。
この機能により、フロントエンドでは Next.js からシンプルに API を呼び出すだけでデータを取得でき、システムのスケーラビリティが向上しました。
回 | タイトル | リンク |
---|---|---|
第 1 回 | ブログ設計図の概要 | 詳 細 |
第 2 回 | .md ファイルの取込みと JSON 化の概要 | この記事 |
第 3 回 | Embedding API を活用した類似記事推薦 | 詳 細 |
第 4 回 | Next.js による推薦記事 API の活用 | 詳 細 |
第 5 回 | Post モデルの設計と Markdownx の適用 | 詳 細 |
第 6 回 | Django 画像アップロード時の画像処理 | 詳 細 |
第 7 回 | Markdownx で画像をアップロード | 詳 細 |
第 8 回 | 多様な記事推薦システムの導入 | 詳 細 |
第 9 回 | 自動クラスタリング vs. 手動分類 | 詳 細 |
第 10 回 | 「公開・非公開」管理機能の実装 | 詳 細 |
当サイトの情報は、一般的な参考情報として提供しております。
正確な情報の掲載に努めておりますが、その内容の正確性・完全性・最新性を保証するものではありません。
記事の内容をご利用の際は、ご自身の責任において判断し、必要に応じて専門家にご相談ください。
当サイトの情報の利用により生じたいかなる損害についても、一切の責任を負いかねますのでご了承ください。
※ 本ページでは、著作権法に基づき、適正な引用の範囲内でコンテンツを紹介しています。
オリジナルの情報は発信元をご確認ください。
もし問題がありましたら、こちら からお問い合わせください。