質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.37%

django rest framework で drf-nested-routes を用いて、ネストされたルートを持つAPIを作りたいが、うまくいかない。

受付中

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 735

popokobe

score 4

現在Django及びdjango-rest-frameworkを用いて、REST APIを作成しています。目標は以下のようなURL構造を持つAPIを作ることです。

users(全ユーザ取得)
users/1(ユーザ詳細取得)
users/1/posts(投稿全件取得)
users/1/posts/1(投稿詳細取得)

現在のところ、usersは全ユーザ、users/1はユーザ詳細の情報をしっかり返してくれます。一方、users/1/postsやusers/1/post1/1はエラーが返ってきてしまいます。

具体的なエラー内容としては、
ーusers/1/postsにアクセス
name 'Response' is not defined
Exception Location:    /Users/*/Desktop/*/django_project/api/views.py in list, line 26

ーusers/1/posts/1にアクセス
name 'Response' is not defined
Exception Location:    /Users/*/Desktop/*/django_project/api/views.py in retrieve, line 31

【serializers.pyを変更後(こちらの解決方法の提示をよろしくおねがいします。)】
Could not resolve URL for hyperlinked relationship using view name "post-detail". You may have failed to include the related model in your API, or incorrectly configured the lookup_field attribute on this field.

どうやらapi/views.py のPostView内で発生しているようです。
公式のdjango rest frameworkのサイトを見る限り、Responseはimportせずとも使えるようですが、エラーが出てしまいます。
どなたか分かる方、ぜひお力添えをお願いいたします。

[作成の際に参考にさせていただいた記事一覧]
ーREST APIを作る際
https://qiita.com/kimihiro_n/items/86e0a9e619720e57ecd8

ーネストされたルート作成の際
https://qiita.com/hfujima/items/fe8d4470a05895a70748
https://github.com/alanjds/drf-nested-routers/blob/master/README.md

#api/views.py

from django.shortcuts import render
from rest_framework import viewsets
from .models import User, Friend, Post
from .serializers import UserSerializer, FriendSerializer, PostSerializer

from rest_framework.generics import get_object_or_404


class UserView(viewsets.ModelViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer


class FriendView(viewsets.ModelViewSet):
    queryset = Friend.objects.all()
    serializer_class = FriendSerializer


class PostView(viewsets.ModelViewSet):
    queryset = Post.objects.all()
    serializer_class = PostSerializer

    def list(self, request, user_pk=None):
        posts = self.queryset.filter(author=user_pk)
        serializer = self.get_serializer(posts, many=True)
        return Response(serializer.data)

    def retrieve(self, request, pk=None, user_pk=None):
        post = self.queryset.get(pk=pk, author=user_pk)
        serilaizer = self.get_serializer(post, many=True)
        return Response(serializer.data)
#api/models.py

from django.db import models 
from django.core.validators import MaxValueValidator, MinValueValidator

class User(models.Model):
    username = models.CharField(max_length=20)
    email = models.EmailField()
    password = models.CharField(max_length=20)

    def __str__(self):
        return self.username

class Friend(models.Model):
    owner = models.ForeignKey(User, on_delete=models.CASCADE, related_name='owner')
    friend = models.ForeignKey(User, on_delete=models.CASCADE, related_name='friend')

    def __str__(self):
        return self.friend


class Post(models.Model):
    CATEGORY_CHOICES = [
        ('JPN', '和食'),
        ('LOCAL', '郷土料理'),
        ('SUSHI', '寿司'),
        ('RAMEN', 'ラーメン類'),
        ('CURRY', 'カレー'),
        ('FA', 'ファミレス・ファストフード'),
        ('MEAT', '焼肉・ステーキ等の肉関連'),
        ('BAR', '居酒屋・バー'),
        ('CHN', '中華'),
        ('WES', '洋食'),
        ('ITA', 'イタリアン'),
        ('FRA', 'フレンチ'),
        ('ASIA', 'アジア・エスニック'),
        ('CAFE', 'カフェ'),
        ('SWEETS', 'スイーツ'),
        ('OTHER', 'その他'),
    ]

    author = models.ForeignKey(User, on_delete=models.CASCADE)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    name = models.CharField(max_length=50)
    area = models.CharField(max_length=50)
    address = models.CharField(max_length=50, blank=True)
    dish = models.CharField(max_length=100, blank=True)
    category = models.CharField(
        max_length=20,
        choices=CATEGORY_CHOICES
    )
    expense = models.IntegerField(blank=True)
    note = models.TextField(blank=True)
    img = models.ImageField(
        blank=True,
        upload_to='post_image'
    )
    rating = models.IntegerField(
        validators=[
            MinValueValidator(1),
            MaxValueValidator(5)
        ]
    )

    def __str__(self):
        return self.name
#api/serializers.py

from rest_framework import serializers
from .models import User, Friend, Post

class UserSerializer(serializers.HyperlinkedModelSerializer):
    posts = serializers.HyperlinkedRelatedField(
        many=True, read_only=True, view_name="post-detail", lookup_url_kwarg="post_id"
    )

    class Meta:
        model = User
        fields = (
            'id',
            'url',
            'username',
            'email',
            'password',
        )
        read_only_fields = "posts"


class FriendSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Friend
        fields = (
            'owner',
            'friend'
        )

class PostSerializer(serializers.HyperlinkedModelSerializer):
    category = serializers.CharField(source='get_category_display')
    author = UserSerializer()
    class Meta:
        model = Post
        fields = (
            'id',
            'url',
            'author',
            'created_at',
            'updated_at',
            'name',
            'area',
            'address',
            'dish',
            'category',
            'expense',
            'note',
            'img',
            'rating'
        )
#api/urls.py

from django.urls import path, include
from .views import UserView, FriendView, PostView
from rest_framework_nested import routers

router = routers.SimpleRouter()
router.register("users", UserView)

users_router = routers.NestedSimpleRouter(router, "users", lookup="user")
users_router.register("posts", PostView)

router.register("friends", FriendView)


urlpatterns = [path("", include(router.urls)), path("", include(users_router.urls))]
#django_project/urls.py

from django.conf import settings
from django.conf.urls.static import static
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/', include('comida_api.urls'))
]

urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • yuokada

    2020/02/08 03:12

    "Responseはimportせずとも使えるようですが、エラーが出てしまいます。"
    明示的にImportすればエラーも解決すると思います。

    キャンセル

回答 1

+2

公式のdjango rest frameworkのサイトを見る限り、Responseはimportせずとも使えるようですが、エラーが出てしまいます。

どのページを見たのかはわかりませんが、チュートリアルを見る限り普通にimportして使うべきもののようです。

from rest_framework.response import Response


2 - Requests and responses - Django REST framework

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.37%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • トップ
  • Pythonに関する質問
  • django rest framework で drf-nested-routes を用いて、ネストされたルートを持つAPIを作りたいが、うまくいかない。