0
votes

Newbie in Django REST framework and seems I'm missing some basics. Have read back and forth hundreds of questions here and on the web, yet can't find where the issue is.

The aim is to have well linked and easy to explore REST api (clickable), like an example demonstrated as part of https://github.com/encode/rest-framework-tutorial.

Any hints are more than welcome, as I'm pulling my hairs and can't find a working solution.

class GroupManager(models.Manager):
    use_in_migrations = True
    def get_by_natural_key(self, name):
        return self.get(name=name)

class Group(models.Model):
    name = models.CharField(_('name'), max_length=80, unique=True)
    permissions = models.ManyToManyField(
        Permission,
        verbose_name=_('permissions'),
        blank=True,
    )

    objects = GroupManager()

    class Meta:
        verbose_name = _('group')
        verbose_name_plural = _('groups')

    def __str__(self):
        return self.name

    def natural_key(self):
        return (self.name,)


class GroupSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Group
        fields = ('url', 'name')

class GroupViewSet(viewsets.ModelViewSet):
    queryset = Group.objects.all()
    serializer_class = GroupSerializer

Above results in very nice linked REST api with automatically generated URL which is clickable and takes to instance details:

enter image description here

enter image description here

Trying to replicate it with my very simple model defined as below fails misreably:

class Author(models.Model):
    name = models.CharField("Authorist", max_length=20)

    def get_by_natural_key(self,name):
        return self.get(name=name)

    def __str__(self):
        return self.name

    def natural_key(self):
        return (self.name,)

class Book(models.Model):
    title = models.CharField("Tytuł",max_length=100)
    autorek = models.ForeignKey(Author,related_name='knicha',on_delete=models.CASCADE)



class AuthorSerializer(serializers.ModelSerializer):
    # id = serializers.HyperlinkedRelatedField(many=True, read_only=True, view_name='author-detail')
    class Meta:
        model = Author
        # fields = ('__all__')
        fields = ('url','name')
        # depth = 2

class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = ('__all__')
        depth = 2


class AuthorVS(viewsets.ModelViewSet):
    queryset = Author.objects.all()
    serializer_class = AuthorSerializer

class BookVS(viewsets.ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer


router.register('author',AuthorVS)
router.register('book',BookVS)

Error produced is:

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

If anyone can explain what and why needs to be done for my example model, that would be grant. I did read through HyperLinkedModels, etc. but can't get this working. I'm pretty sure I'm missing some silly bit to get it working.

1
What are you Django and DRF versions? Which action lead to the error?Hai Lang
I could not reproduce the error with Django 2.0 and DRF 3.7. I can get the links { "author": "http://localhost:8000/test/author/", "book": "http://localhost:8000/test/book/" }. All of them works: [ { "url": "http://localhost:8000/test/author/1/", "name": "abcd" } ] and [ { "id": 1, "title": "efg", "autorek": { "id": 1, "name": "abcd" } } ]Hai Lang
I'm on Django 2.0.1 and DRF 3.7.7 I'll post example code which leads to failure for easy import/test for anyone. I'm sure I'm making some silly mistake :(nohtyp
Silly mistake: me too :). We are all learning. Could you please describe the action right before error? Also copy all the error stack and put into your question.Hai Lang
I found author-detail in the line # id = serializers.... Why did you comment it out? When I uncommented it, I received different error than yours. Could you please update your question with the version that has the error?Hai Lang

1 Answers

1
votes

Big thanks to @Hai Lang.

I've managed to get it working with below. Original question was based on add-ons within my real app. When same testing done today on vanilla app created with django-admin it just worked.

Reviewing details, I've had addition elements configured in my real app which were causing the issue. The elements were:

in mainapp/urls.py

app_name = 'mainapp_rest'

in project/urls.py

in urlpatterns = [
...
    path('api/', include('upload_rest.urls', namespace='api')),

The problematic part was "namespace='api'. After removing this and "app_name" it all just started to work.

models.py

from django.db import models

class Author(models.Model):
    name = models.CharField("Authorist", max_length=20)
    def __str__(self):
        return self.name

class Book(models.Model):
    title = models.CharField("Tytuł",max_length=100)
    autorek = models.ForeignKey(Author,related_name='knicha',on_delete=models.CASCADE)

    def __str__(self):
        return self.title

serializers.py

from rest_framework import serializers
from test1.models import Author, Book

class AuthorSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Author
        fields = ('url','name','knicha')
        depth = 1

class BookSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Book
        fields = ('url','title','autorek')
        depth = 1

views.py

from test1.serializers import AuthorSerializer, BookSerializer
from test1.models import Author, Book
from rest_framework import viewsets

class AuthorVS(viewsets.ModelViewSet):
    queryset = Author.objects.all()
    serializer_class = AuthorSerializer

class BookVS(viewsets.ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

test1/urls.py

from django.conf.urls import url, include
from rest_framework import routers
from rest_framework.schemas import get_schema_view

from test1.views import AuthorVS, BookVS

schema_view = get_schema_view(title='Test API')

router = routers.DefaultRouter()
router.register('author',AuthorVS)
router.register('book',BookVS)


urlpatterns = [
    url(r'^', include(router.urls)),
    url(r'^schema/$', schema_view),
]

main/urls.py
    path('api/', include('test1.urls')),

What happen to be the key was setting HyperlinkedModelSerializer and url entry. For whatever reason it was not working earlier.

Thanks again to Hai Lang for assistance provided.