1

Django の世界の初心者です。ネストされたルートのハイパーリンクの作成に苦労しています。

私が得ているエラーは次のとおりです。

Could not resolve URL for hyperlinked relationship using view name "rest:campaign-detail". You may have failed to include the related model in your API, or incorrectly configured the `lookup_field` attribute on this field.

プロジェクトの設定に関する注意事項

  • ジャンゴレストフレームワークの使用

  • DRF-extensionsルートの作成に使用

  • ModelViewSet の使用

  • 予想されるエンドポイント:

    • /アカウント/

    • /accounts/< pk >/

    • /accounts/< pk >/campaigns/

    • /accounts/< pk >/campaigns/< pk >/

    • /accounts/<pk>/campaigns/adgroup/

    • /accounts/< pk >/campaigns/adgroup/< pk >/

  • resturls.pyに名前空間を設定する

  • を使用HyperlinkedIdentityFieldしてハイパーリンクを作成します。親オブジェクトでのみ機能します。

    • url = serializers.HyperlinkedIdentityField(view_name='rest:account-detail')

ただし、ネストされたオブジェクトでは失敗します。

  • url = serializers.HyperlinkedIdentityField(view_name='rest:campaign-detail')

モデルは非常にシンプルで、1 つのアカウントに複数のCampaignsを設定でき、1 つのキャンペーンに複数のAdGroupsを設定できます。以下のコードを参照してください。

models.py

from django.db import models
from django.db.models import Q
from model_utils import Choices

ORDER_COLUMN_CHOICES = Choices(
    ('0', 'id'),
    ('1', 'keyword'),
    ('2', 'status'),
    ('3', 'match_type'),
)


# Account
class Account(models.Model):
    account_name = models.CharField(max_length=128)

    def __str__(self):
        return self.account_name


# Campaign
class Campaign(models.Model):
    class Status(models.TextChoices):
        Enabled = "Enabled"
        Paused = "Paused"

    account = models.ForeignKey(
        to=Account, on_delete=models.CASCADE, related_name='campaigns'
    )
    campaign_name = models.CharField(max_length=128)
    status = models.CharField(max_length=21, choices=Status.choices, default=Status.Paused)

    def __str__(self):
        return self.campaign_name


# AdGroup
class AdGroup(models.Model):
    class Status(models.TextChoices):
        Enabled = "Enabled"
        Paused = "Paused"

    campaign = models.ForeignKey(
        to=Campaign, on_delete=models.CASCADE, related_name='adgroups'
    )
    adgroup_name = models.CharField(max_length=128)
    status = models.CharField(max_length=21, choices=Status.choices, default=Status.Enabled)

    def __str__(self):
        return self.adgroup_name

ビュー.py

from rest_framework import viewsets
from .serializers import *
from . import models
from rest_framework_extensions.mixins import NestedViewSetMixin


class AccountViewSet(NestedViewSetMixin, viewsets.ModelViewSet):
    serializer_class = AccountSerializer
    queryset = models.Account.objects.all()


class CampaignViewSet(NestedViewSetMixin, viewsets.ModelViewSet):
    serializer_class = CampaignSerializer
    queryset = models.Campaign.objects.all()


class AdGroupViewSet(NestedViewSetMixin, viewsets.ModelViewSet):
    serializer_class = AdGroupSerializer
    queryset = models.AdGroup.objects.all()

serializers.py

from rest_framework import serializers
from . import models


class CampaignSerializer(serializers.ModelSerializer):

    url = serializers.HyperlinkedIdentityField(view_name="rest:campaign-detail")

    class Meta:
        model = models.Campaign
        fields = '__all__'


class AccountSerializer(serializers.HyperlinkedModelSerializer):
    url = serializers.HyperlinkedIdentityField(view_name='rest:account-detail')

    class Meta:
        model = models.Account
        fields = '__all__'


class AdGroupSerializer(serializers.ModelSerializer):
    url = serializers.HyperlinkedIdentityField(view_name='rest:adgroup-detail')

    class Meta:
        model = models.AdGroup
        fields = '__all__'


2 つの URL ファイルがあります。プロジェクトの名前はVanillaで、DRF ロジックが配置されているアプリの名前はrestです。

バニラurls.py

from django.contrib import admin
from django.urls import path, include


urlpatterns = [
    path('', include('rest.urls', namespace='rest')),
    path('api-auth/', include('rest_framework.urls', namespace='rest_framework')),
    path('admin/', admin.site.urls)
]

残りの urls.py

from django.urls import include, path
from . import views
from rest_framework_extensions.routers import ExtendedSimpleRouter

app_name = 'rest'

router = ExtendedSimpleRouter()
(
    router.register(r'accounts',
                    views.AccountViewSet,
                    basename='account')

    .register(r'campaigns',
              views.CampaignViewSet,
              basename='campaign',
              parents_query_lookups=['account__id'])

    .register(r'adgroups',
              views.AdGroupViewSet,
              basename='adgroup',
              parents_query_lookups=['campaign__account', 'campaign'])

ありがとう!

4

1 に答える 1