Django Serializerを使用した関連モデルのリソースをネスト形式で取ってきたい
はじめまして。新米プログラマーのExaと申します。
今回、DjangoのREST_Framework・Serializerを利用し、関連先のモデル情報を含め、JSON化して
出力したいと思っております。
実装内容といたしまして、
Postモデルのauthorフィールドには、models.ForeignKeyを使用して、Userモデルを関連付けております。
実際にAPIを叩き、PostモデルからJSONを生成する際、authorフィールドには、Userモデルのuuid(PK)とJournalist_nameという2つの情報をネストした状態を付け加え、返却したいと考えております。
Postモデル
def get_delete_msg(): return User.objects.get_or_create(journalist_name='unknown')[0].pk class Post(models.Model): class Meta: db_table = "posts" id = models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True) title = models.CharField(_('タイトル'), max_length=255) content = models.TextField(_("コンテンツ")) author = models.ForeignKey(User, null=True, on_delete=models.SET(get_delete_msg())) post_create_day = models.DateField(_('作成日付'), default=now()) post_deadline_day = models.DateField(_('締切日付'), null=True, blank=True) evalution_count = models.FloatField(_('記事総合評価'), default=0) agree_count = models.FloatField(_('賛同評価'), default=0) opposite_count = models.FloatField(_('反論評価'), default=0) comment_count = models.IntegerField(_('コメント数'), default=0) thumbnail_img = models.ImageField(_("サムネイル画像"), upload_to='Thumbnail', null=True, blank=True) def __str__(self): return self.title
Userモデル
#関係ないフィールドは載せていません class User(AbstractBaseUser, PermissionsMixin): class Meta(AbstractBaseUser.Meta): db_table = 'wej_user' username_validator = UnicodeUsernameValidator() uuid = models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True) journalist_name = models.CharField(_('journalist_name'), max_length=150, default="Jornalist")
(現在)Postモデル単体から取得した場合
[ { "id": "26c39386-0900-4f50-adac-f6318d9eb363", "title": "テスト1", "content": "test", "author": "24dee3aa-3a39-49e7-8e0f-7918250f1aab", "post_deadline_day": null, "evalution_count": 0.0, "agree_count": 0.0, "opposite_count": 0.0, "comment_count": 0, "thumbnail_img": null } ]
Postモデル+Userモデルから必要な情報を付け加え実際に出力させたい内容
[ { "id": "26c39386-0900-4f50-adac-f6318d9eb363", "title": "テスト1", "content": "test", "author": { "uuid": "24dee3aa-3a39-49e7-8e0f-7918250f1aab", "journalist_name" : "journalist" }, "post_deadline_day": null, "evalution_count": 0.0, "agree_count": 0.0, "opposite_count": 0.0, "comment_count": 0, "thumbnail_img": null } ]
実現するために行ったこと
PostSerializerクラスのauthorフィールドに、AuthorListSerializerを指定しています。
# serializers.py class AuthorSerializer(serializers.ModelSerializer): class Meta: model = User fields = ['uuid', 'journalist_name'] class AuthorListSerializer(serializers.ListSerializer): child = AuthorSerializer() class PostSerializer(serializers.ModelSerializer): author = AuthorListSerializer() class Meta: model = Post fields = ('id', 'title', 'content', 'author', 'post_deadline_day', 'evalution_count', 'agree_count', \ 'opposite_count', 'comment_count', 'thumbnail_img')
■■すると、以下のエラーメッセージが発生しました。
発生している問題・エラーメッセージ
File "/code/venv/lib/python3.7/site-packages/rest_framework/serializers.py", line 760, in data ret = super().data File "/code/venv/lib/python3.7/site-packages/rest_framework/serializers.py", line 261, in data self._data = self.to_representation(self.instance) File "/code/venv/lib/python3.7/site-packages/rest_framework/serializers.py", line 678, in to_representation self.child.to_representation(item) for item in iterable File "/code/venv/lib/python3.7/site-packages/rest_framework/serializers.py", line 678, in <listcomp> self.child.to_representation(item) for item in iterable File "/code/venv/lib/python3.7/site-packages/rest_framework/serializers.py", line 526, in to_representation ret[field.field_name] = field.to_representation(attribute) File "/code/venv/lib/python3.7/site-packages/rest_framework/serializers.py", line 674, in to_representation self.child.to_representation(item) for item in iterable TypeError: 'User' object is not iterable
試したこと
rest_framework/serializers.pyのエラー箇所を確認すると、以下の場所で失敗していました。
def to_representation(self, data): """ List of object instances -> List of dicts of primitive datatypes. """ # Dealing with nested relationships, data can be a Manager, # so, first get a queryset from the Manager if needed # ここで失敗している様子 iterable = data.all() if isinstance(data, models.Manager) else data return [ self.child.to_representation(item) for item in iterable ]
イテレーターではない? このあたりがよくわかりません。
serializers.pyの書き方が悪いのでしょうか。
このiterable変数をコンソール出力してみると、PostモデルのQuerySetと、メールアドレスが返ってきました。
<QuerySet [<Post: テスト1>]> root@hogehoge.com
ちなみに、メールアドレスでログインさせる実装にしているので、UserモデルのUSERNAME_FIELDは以下のようにしています。
USERNAME_FIELD = 'email'
補足情報(FW/ツールのバージョンなど)
Python 3.7.4
Django==2.2.5
mysqlclient==1.4.4
djangorestframework==3.10.3
お力添えいただけますと幸いです。
あなたの回答
tips
プレビュー