Could not resolve URL for hyperlinked relationship using view name "rest:campaign-detail"

383 Views Asked by At

A newbie here in the world of Django. I am struggling with creating a hyperlink for a nested route.

The error I am getting is:

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.

Some project setup notes

  • Using django rest framework

  • using DRF-extensions to create the routes

  • Using ModelViewSet

  • Expected end points:

    • /accounts/

    • /accounts/< pk >/

    • /accounts/< pk >/campaigns/

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

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

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

  • Set a namespace of rest in urls.py

  • Using HyperlinkedIdentityField to create the hyperlink. It only works with the parent object i.e.

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

However fails with any nested object i.e.

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

The model is quiet simple, an Account can have many Campaigns, and a campaign can have many AdGroups. See code below:

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

views.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__'


I have 2 URL files. The project is named Vanilla and an app named rest where the DRF logic sits.

Vanilla 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)
]

Rest 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'])

Thank You!

1

There are 1 best solutions below

3
On

use hyperlinkedModelSerializer in all of your related serializer. that should work