こんにちは。KOUKIです。
前回は、ModelSerializerクラスについて学びました。
今回は、外部キーとシリアライズについて学びます。
<目次>
前回
外部キーとJournalistモデル
外部キー(FOREIGN KEY)とは、関連したテーブル間を結ぶために設定する列を指し、「データの整合性をデータベースに保証させるため」に設定します。
DjangoのModelにもその設定が可能です。
例えば、これまで作成してきたArticleモデルの外部キーとして持たせるJournalistモデルを作成しましょう.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
# news/models.py from django.db import models class Journalist(models.Model): first_name = models.CharField(max_length=60) last_name = models.CharField(max_length=60) biography = models.TextField(blank=True) def __str__(self): return f"{ self.first_name } {self.last_name }" class Article(models.Model): author = models.ForeignKey(Journalist, on_delete=models.CASCADE, related_name="articles") # author = models.CharField(max_length=50) title = models.CharField(max_length=120) description = models.CharField(max_length=200) body = models.TextField() location = models.CharField(max_length=120) publication_date = models.DateField() active = models.BooleanField(default=True) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) def __str__(self): return f"{self.author} {self.title}" |
Journalistクラスを設定して、それをArticleクラスのauthor変数にForeignKeyで関連付けています。
マイグレーションを実行しましょう。
1 2 3 |
python manage.py makemigrations news rm db.sqlite3 python manage.py migrate |
Foreign Keyで関連データをつなぐ処理を入れたので、既存のデータが入っている場合は、マイグレーションが失敗します。そのため、sqliteを削除しました。
Djangoでは、データ保存場所としてsqliteをデフォルトにしています。
ログインユーザーも作成します。
1 |
python manage.py createsupaeruser |
続いて、作成したJournalistクラスを管理画面に表示できるようにします。
1 2 3 4 5 6 7 8 |
# news/admin.py from django.contrib import admin from news.models import Article, Journalist admin.site.register(Article) admin.site.register(Journalist) |
下記のコマンドで、開発用サーバーを立ち上げましょう。
1 |
python manage.py runserver |

Journalistが追加されてますね。
ArticleとJournalisには、適当にデータを入れていてください。
「http://localhost:8000/api/articles/」にアクセスして、データを確認します。

現時点だと、authorのデータは、「1」になっています。おそらく、Djangoが自動的に生成するid番号が表示されているのだと思います。
外部キーとシリアライズ
Articleモデルのauthorフィールドが外部キーであるため、ArticleSerializerクラスにauthor変数を定義します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
# news/api/serializers.py from datetime import datetime from django.utils.timesince import timesince from rest_framework import serializers from news.models import Article class ArticleSerializer(serializers.ModelSerializer): time_since_publication = serializers.SerializerMethodField() # new author = serializers.StringRelatedField() def get_time_since_publication(self, object): ... def validate(self, data): ... def validate_title(self, value): ... class Meta: ... |
ブラウザを確認します。

authorのデータが「Harry Potter」に変わりました。
Journalistのシリアライズクラスを作成してみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
# news/api/serializers.py from datetime import datetime from django.utils.timesince import timesince from rest_framework import serializers from news.models import Article, Journalist class JournalistSerializer(serializers.ModelSerializer): class Meta: model = Journalist fields = "__all__" class ArticleSerializer(serializers.ModelSerializer): time_since_publication = serializers.SerializerMethodField() author = JournalistSerializer(read_only=True)) ... |
作成したJournalistSerializerクラスをArticleSerializerクラスのauthor変数に代入しています。
画面をリロードしてください。

すごい!簡単ですね!!
しかし、これには問題があります。
以下のデータをContentに入力後、POSTを押下してください。
1 2 3 4 5 6 7 8 |
{ "title": "Update Enter the heigh school############################### ", "description": "How to enter the height school", "body": "Wow, It is difficlut to enter theh high school by 30 years old.", "location": "Earth", "publication_date": "2020-05-31", "active": true } |

Articleモデルを更新するには、authorが必須のため、エラーになってしまいます。
リファクタリング
JournalistSerializerを以下のように修正します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
# news/api/serializers.py from datetime import datetime from django.utils.timesince import timesince from rest_framework import serializers from news.models import Article, Journalist class ArticleSerializer(serializers.ModelSerializer): time_since_publication = serializers.SerializerMethodField() def get_time_since_publication(self, object): ... def validate(self, data): ... def validate_title(self, value): ... class Meta: ... class JournalistSerializer(serializers.ModelSerializer): articles = ArticleSerializer(many=True, read_only=True) class Meta: model = Journalist fields = "__all__" |
先ほどとは逆で、JournalistSerializerから、ArticleSerializerを読み込んでいます。
api/views.pyにJournalistのviewを追加しましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
# news/api/views.py from rest_framework import status from rest_framework.decorators import api_view from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.generics import get_object_or_404 from news.models import Article, Journalist from news.api.serializers import ArticleSerializer, JournalistSerializer class JournalistListCreateAPIView(APIView): def get(self, request): journalists = Journalist.objects.all() serializer = JournalistSerializer(journalists, many=True) return Response(serializer.data) def post(self, request): serializer = JournalistSerializer(data=request.data) if serializer.is_valid(): serializer.save() return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) |
urls.pyに以下を追加しましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
# news/api/urls.py from django.urls import path from news.api.views import ( ArticleListCreateAPIView, ArticleDetailAPIView, JournalistListCreateAPIView, # new ) urlpatterns = [ path("articles/", ArticleListCreateAPIView.as_view(), name="article-list"), path("articles/<int:pk>", ArticleDetailAPIView.as_view(), name="article-detail"), # new path("journalists/", JournalistListCreateAPIView.as_view(), name="journalist-list") ] |
ここまで実装できたら「http://localhost:8000/api/journalists/」にアクセスしましょう。

OKですね。
Contentの中身に以下を入力してPOSTを押下してください。
1 2 3 4 5 |
{ "first_name": "Harry", "last_name": "Potter", "biography": "Update Article" } |

新規ユーザー(id=2)が作成されました。

ハイパーリンクを設置しておきましょう。
1 2 3 4 5 6 7 8 9 10 11 |
# news/api/serializers.py class JournalistSerializer(serializers.ModelSerializer): articles = serializers.HyperlinkedRelatedField(many=True, read_only=True, view_name="article-detail") # urls.pyのnameに設定されている名前 class Meta: model = Journalist fields = "__all__" |
HyperlinkedRelatedFieldを使うとハイパーリンクが生成されるようになります。
また、JournalistSerializerの呼び出し時にcontextを設定します。
1 2 3 4 5 6 7 |
class JournalistListCreateAPIView(APIView): def get(self, request): journalists = Journalist.objects.all() serializer = JournalistSerializer(journalists, many=True, context={'request': request}) # 変更 |
ブラウザをリロードします。

articlesに「”http://localhost:8000/api/articles/1“」が貼られました。
これをクリックします。

Articleの詳細ページに飛びました。かなり便利ですよね。
おわりに
ここまでに、様々なDjango REST Frameworkの基本的な使い方を見てきました。
しかし、まだまだ氷山の一角です。
公式サイトを見ながら、色々な機能を試していきましょう!
それでは、また!
関連記事
こちらもどうぞ
Djangoおすすめ書籍
Djangoを学ぶなら以下の書籍がオススメです。
緑 -> 赤 -> 紫の順でやればOKです。読みやすい英語で書かれているので、英語力もついでに上がるかもしれません^^
コメントを残す
コメントを投稿するにはログインしてください。