Passing Pk or Slug to Generic DetailView in Django?

I am new to Django Class based views. I am trying to make a simple look to get the details of the message. My views.py:

from django.views.generic import ListView, View, DetailView class GenreDetail(DetailView): model = Post template_name = "post.html" 

My urls.py:

 urlpatterns = [ url(r'(?P<post_id>[^/]+)', GenreDetail.as_view(), name = 'post'), url(r'(?P<post_id>[^/]+)/(?P<slug>[-\w]+)$', GenreDetail.as_view()), ] 

The error I get is:

 AttributeError at /2/memoirs-of-a-geisha-by-arthur-golden Generic detail view GenreDetail must be called with either an object pk or a slug. 

Thus, pk or slug are not passed to the Generic Detailview. How to convey this? I guess it can pick from url, but it is not.

+9
python django django-class-based-views
source share
4 answers

url patterns are checked in the order they are defined

so that:

 urlpatterns = [ url(r'(?P<post_id>[^/]+)', GenreDetail.as_view(), name = 'post'), url(r'(?P<post_id>[^/]+)/(?P<slug>[-\w]+)$', GenreDetail.as_view()), ] 

... the first pattern gets matched (because it doesn't end with $ , so the extra segment is simply ignored)

... and this template passes only one arg keyword

This is generally a bad idea to have multiple URL patterns pointing to the same look. If possible, you should try to create one regular expression (for example, using optional groups ) that handles various cases of URLs for a particular kind. This is more explicit.

On the other hand, simply reordering your templates to give a more explicit first will also work and be correct (this is the Django rule for URLs!)

 urlpatterns = [ url(r'(?P<post_id>[^/]+)/(?P<slug>[-\w]+)$', GenreDetail.as_view()), url(r'(?P<post_id>[^/]+)', GenreDetail.as_view(), name = 'post'), ] 

Since @ozgur mentions that you also need to tell the view to use post_id instead of pk by setting pk_url_kwarg

+10
source share

If you want to get the details using post_id or slug, then your urls should be like this:

 url(r'post/(?P<post_id>\d+)/$', GenreDetail.as_view(), name = 'post_detail'), url(r'post/(?P<slug>[-\w]+)/$', GenreDetail.as_view(), name = 'post_detail_slug'), 

And your look should be like that

 from django.views.generic import DetailView class GenreDetail(DetailView): model = Post template_name = "post.html" pk_url_kwarg = "post_id" slug_url_kwarg = 'slug' query_pk_and_slug = True 

For more information, please read the documents .

+6
source share

The problem is that you must tell DetailView that instead of the pk or slug URL, the post_id keyword should be used instead of the post_id URL to get the object to be displayed.

This can be done by setting pk_url_kwarg :

(The definition of your URL is also incorrect; always end your URL definitions with $ . Below is the corrected version)

 url(r'(?P<post_id>\d+)$', GenreDetail.as_view(), name = 'post'), url(r'(?P<post_id>\d+)/(?P<slug>[-\w]+)$', GenreDetail.as_view()), 

The following URLs will match the given URL patterns:

  • / 2
  • / 2 / remembrance-o-a-geisha-on-arthur-golden

 from django.views.generic import DetailView class GenreDetail(DetailView): model = Post template_name = "post.html" pk_url_kwarg = "post_id" 

Alternatively, you can simply change the post_id to pk in your url, so you don't need to touch anything in your view:

 url(r'(?P<pk>\d+)$', GenreDetail.as_view(), name = 'post'), url(r'(?P<pk>\d+)/(?P<slug>[-\w]+)$', GenreDetail.as_view()), 
+4
source share

Using the path :

 from django.urls import path from . import views urlpatterns = [ path('<pk>/', views.GenreDetail.as_view(), name="post")] 

For slug :

 path('<slug:slug>/', views.GenreDetail.as_view(), name="post") 
0
source share

All Articles