3

I'm trying to setup the lookup field between two entities, but I can't fix this error.

I've already tried these solutions but none of them worked for me(What am I doing wrong?):

Django Rest Framework, improperly configured lookup field

Django Rest Framework - Could not resolve URL for hyperlinked relationship using view name "user-detail"

DRF Could not resolve URL for hyperlinked relationship using view name on PrimaryKeyRelatedField

here's my code Models:

class Category(models.Model):
    title = models.CharField(max_length=50, unique=True)
    slug = models.SlugField(max_length=80, default='')

    def __str__(self):
        return self.title

class Option(models.Model):
    title = models.CharField(max_length=80)
    slug = models.SlugField(max_length=80, unique=True)
    description = models.CharField(max_length=250)
    price = models.DecimalField(max_digits=7,  decimal_places=2)
    category = models.ForeignKey(Category, related_name='options', on_delete=models.CASCADE)
    photo = models.ImageField(upload_to='options', null=True)

    class Meta:
        ordering = ['title']
    
    def __str__(self):
        return self.title

Serializers:

class CategorySerializer(serializers.HyperlinkedModelSerializer):
    options = serializers.HyperlinkedRelatedField(many=True, view_name='option-detail', read_only=True)
    class Meta:
        model = Category
        fields = ('url', 'slug', 'title', 'options')
        lookup_field = 'slug'
        extra_kwargs = {
            'url': {'lookup_field': 'slug'}
        }

class OptionSerializer(serializers.HyperlinkedModelSerializer):
    category = serializers.ReadOnlyField(source='category.title')
    class Meta:
        model = Option
        fields = ('url', 'slug', 'title', 'description', 'price', 'category')
        lookup_field = 'slug'
        extra_kwargs = {
            'url': {'lookup_field': 'slug'},
            'category': {'lookup_field': 'slug'}
        }

Views:

class CategoryViewSet(viewsets.ReadOnlyModelViewSet):
    """
    Returns the Category list or the requested one
    """
    queryset = Category.objects.all()
    serializer_class = CategorySerializer
    lookup_field = 'slug'

class OptionViewSet(viewsets.ReadOnlyModelViewSet):
    """
    Returns the Option list or the requested one
    """
    queryset = Option.objects.all()
    serializer_class = OptionSerializer
    lookup_field = 'slug'

urls:

router = DefaultRouter()
router.register(r'options', views.OptionViewSet)
router.register(r'categories', views.CategoryViewSet)

urlpatterns = [
    path('', include(router.urls)),
]

This works for the Option model. When I hit the '[localhost]/options/' url, it correctly lists the options and when hitting '[localhost]/options/some-option-slug' it returns the correct option.

But none of that works for the Category model. Calls to '[localhost]/categories/' retuns "Could not resolve URL for hyperlinked relationship using view name "option-detail". You may have failed to include the related model in your API, or incorrectly configured the lookup_field attribute on this field.". While calls to '[localhost]/categories/category-slug/' returns 404 Not Found.

My django version is 4.0.1 and my Django Rest Framework version is 3.13.1

EDIT As suggestted by @code-apprendice, here's the output of print('router'): [<URLPattern '^options/$' [name='option-list']>, <URLPattern '^options.(?P[a-z0-9]+)/?$' [name='option-list']>, <URLPattern '^options/(?P[^/.]+)/$' [name='option-detail']>, <URLPattern '^options/(?P[^/.]+).(?P[a-z0-9]+)/?$' [name='option-detail']>, <URLPattern '^categories/$' [name='category-list']>, <URLPattern '^categories.(?P[a-z0-9]+)/?$' [name='category-list']>, <URLPattern '^categories/(?P[^/.]+)/$' [name='category-detail']>, <URLPattern '^categories/(?P[^/.]+).(?P[a-z0-9]+)/?$' [name='category-detail']>, <URLPattern '^$' [name='api-root']>, <URLPattern '^.(?P[a-z0-9]+)/?$' [name='api-root']>]

The DRF correctly generated the views option-list, option-detail, category-list and category-detail

Daniel Costa
  • 137
  • 2
  • 10
  • Show us what happened when you tried [these suggestions](https://stackoverflow.com/a/20553926/1440565). Specifically, create a `UserViewSet` and register it with your router. – Code-Apprentice Mar 01 '22 at 17:53
  • I already have the ViewSets for both Option and Category defined and registered in the router. – Daniel Costa Mar 01 '22 at 18:02
  • Yes, but the error is about a missing `user-detail` route, not option or category routes. – Code-Apprentice Mar 01 '22 at 18:25
  • Does this answer your question? [Django Rest Framework - Could not resolve URL for hyperlinked relationship using view name "user-detail"](https://stackoverflow.com/questions/20550598/django-rest-framework-could-not-resolve-url-for-hyperlinked-relationship-using) – Code-Apprentice Mar 01 '22 at 18:26
  • @Code-Apprentice sorry, but I don't get it, I have no reference to User in none of my models, and also, the displayed error says 'option_detail'. In the answer that you suggested, there's a relationship between Bottle and User. Please could you explain why the user_detail is a problem in my code? – Daniel Costa Mar 01 '22 at 18:34
  • My mistake. I confused your question with a very similar one from yesterday. And now that I look closer. I'm even more confused. I see `router.register(r'options', views.OptionViewSet)` which should generate a route with the name `option-detail`. – Code-Apprentice Mar 01 '22 at 23:40
  • Will you add `print(router.urls)` to your `urls.py` file? What does it output? – Code-Apprentice Mar 01 '22 at 23:44
  • Sorry for not answering yesterday, heres the output of print(router.urls) in the app router (formatted): , [a-z0-9]+)/?$' [name='option-list']>, [^/.]+)/$' [name='option-detail']>, [^/.]+)\.(?P[a-z0-9]+)/?$' [name='option-detail']>, – Daniel Costa Mar 02 '22 at 15:27
  • , [a-z0-9]+)/?$' [name='category-list']>, [^/.]+)/$' [name='category-detail']>, [^/.]+)\.(?P[a-z0-9]+)/?$' [name='category-detail']>, , [a-z0-9]+)/?$' [name='api-root']> ] had to split the result in two comments – Daniel Costa Mar 02 '22 at 15:27
  • Please [edit] your question to include these details – Code-Apprentice Mar 02 '22 at 18:05

1 Answers1

5

Defining the lookup_field attribute for the options in the CategorySerializer solved the problem.

Here's the CategorySerializer class:

class CategorySerializer(serializers.HyperlinkedModelSerializer):
    options = serializers.HyperlinkedRelatedField(
    view_name='option-detail',
    lookup_field = 'slug',
    many=True,
    read_only=True)

    class Meta:
        model = Category
        fields = ('url', 'slug', 'title', 'options')
        lookup_field = 'slug'
        extra_kwargs = {
            'url': {'lookup_field': 'slug'}
        }

The problem was that the CategorySerializer set an explict options HyperlinkedRelatedField and it's lookup_field needs to be configured too.

Feel free to edit this answer to add a deeper explanation.

John R Perry
  • 3,916
  • 2
  • 38
  • 62
Daniel Costa
  • 137
  • 2
  • 10