<slug> path converter not working, but literal <slug> in URL works

Question:

When I try to visit this URL:

http://127.0.0.1:8000/slugtest/

I get 404 page. Here’s the message that I get:

Using the URLconf defined in scrap.urls, Django tried these URL patterns, in this order:

admin/
api-auth/
getpage/
^<slug>/$ [name='ArticleInfoViewSet-list']
^<slug>/(?P<slug>[^/.]+)/$ [name='ArticleInfoViewSet-detail']
__debug__/

The current path, slugtest/, didn’t match any of these.

However, if I use

http://127.0.0.1:8000/<slug>/

the page loads perfectly, but that’s not intended behavior.

models.py

class Article(models.Model):

    url = models.CharField(max_length=255,validators=[RegexValidator(regex=website_regex)])
    slug = models.CharField(max_length=255, null=True)
    unique_id = models.CharField(max_length=255, unique=True, null=True)

views.py

class ArticleInfoViewSet(ModelViewSet):
    serializer_class = ArticleInfoSerializer
    lookup_url_kwarg = 'slug'
    lookup_field = 'slug'

def get_queryset(self):
    queryset = Article.objects.prefetch_related('data')
    return queryset

serializer.py

class ArticleInfoSerializer(serializers.ModelSerializer):

    data = ArticleDataSerializer(many=True)

class Meta:
    model = Article
    fields = ['url', 'data', 'slug']
    lookup_field = ['slug']
    read_only_fields = ['url', 'data', 'slug']

urls.py

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

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api-auth/', include('rest_framework.urls')),
    path('getpage/', include('getpage.urls')),
    path('', include('getpage.urls2')),
    path('__debug__/', include('debug_toolbar.urls')),
]

urls2.py

from . import views
from rest_framework_nested import routers

router = routers.SimpleRouter()
router.register('<slug>', views.ArticleInfoViewSet, basename='ArticleInfoViewSet')
urlpatterns = router.urls

What am I doing wrong here?

Asked By: Mentalhead

||

Answers:

router.register('', views.ArticleInfoViewSet, basename='ArticleInfoViewSet')

Easy mistake.

You have set everything up perfectly from what I can see, but you registered the route as literally /<slug> hehe 🙂 whereas I’m guessing you wanted a little API at the root of the app which accepts a slug url parameter? To prove this, try accessing /<slug>/slugtest

Django rest framework will do lots of magical things when you register a viewset. Including considering the lookupfield kwarg and url kwarg attributes you have set. DRF will also automagically generate relevant url patterns based on your viewset configuration, hence why you need not specify and url parameters when using viewsets, there are however, ways to configure it and customise the paths.

I would not recommend putting an API with a slug parameter at the root of your app, it might be more appropriate to prefix the path somewhere with "api/" so it would become api/slugtest and even better still, for the article viewset, api/articles/slugtest

So you would change the url:

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api-auth/', include('rest_framework.urls')),
    path('getpage/', include('getpage.urls')),
    path('api', include('getpage.urls2')),
    path('__debug__/', include('debug_toolbar.urls')),
]

And finally register it as articles

router.register('articles', views.ArticleInfoViewSet, basename='ArticleInfoViewSet')
Answered By: Swift
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.