Django: generic detail view must be called with either an object pk or a slug in the URLconf
April 23, 2021 ‐ 2 min read
There is great magic involved in Django its class-based views, the good kind of magic. The kind of magic that saves me lots of time and lines of code. However, using them requires you to follow some conventions.
Such a conventions in Django is using properly named url variables when using detail views. View classes like DetailView
, DeleteView
, UpdateView
rely on the presence of either a url variable with the name pk
or slug
. These classes inherit a method called get_object
from the SingleObjectMixin
class. This get_object
method is used to find the right model instance to be displayed in the view.
So lets consider the following example: a detail view for a blog post model.
# blog/views.py
from django.views import generic
from blog.models import Post
class DetailView(generic.DetailView):
model = Post
template_name = 'blog/detail.html'
In order to comply with the requirements from the get_object
method we should add a url containing a variable named either pk
or slug
. Otherwise we would get an AttributeError
from Django with the message: Generic detail view DetailView must be called with either an object pk or a slug in the URLconf
.
When using the path()
function you should keep the following format in mind when adding url variables: <variable type:variable name>
.
If you prefer to use the primary key for you DetailView you should add it in the urlpatterns
like:
# urls.py
from django.urls import path
from blog import views
urlpatterns = [
path('<int:pk>/', views.DetailView.as_view()),
]
If you prefer to use a slug for your DetailView you should first make sure your model implements a SlugField. Then add the slug as <slug:slug>
, bit confusing maybe but both the variable type and name are supposed to be named slug
:
# urls.py
from django.urls import path
from blog import views
urlpatterns = [
path('<slug:slug>/', views.DetailView.as_view()),
]