Create a class based detail view with DetailView in Django

| Tag python  django  views  class-based 

View

# views.py
from django.views.generic import DetailView
from .models import Book

class BookDetailView(DetailView):
    model = Book
	context_object_name = 'book'
    template_name = 'books/book_detail.html'

In the sub-class of generic.ListView, specify model, template_name.

In template, the default variable name for the object list is object, to change it, set a value for context_object_name in view class.

Template

<!-- templates/books/book_list.html -->
{% extends "_base.html" %}

{% block title %}{{ book.title }}{% endblock title %}

{% block content %}
    <div class="book-detail">
        <h2><a href="">{{ book.title }}</a></h2>
        <p>Author: {{ book.author }}</p>
        <p>Price: {{ book.price }}</p>
    </div>
{% endblock content %}

URLs

# urls.py
from django.urls import path
from .views import BookListView, BookDetailView

urlpatterns = [
    path('', BookListView.as_view(), name="book_list"),
    path("<int:pk>/", BookDetailView.as_view(), name="book_detail")
]

Right now the path for each object are their auto-incrementing primary key, which is predictable, for instances: /books/1/, /books/2,…

get_absolute_url()

We can reference the object’s URL in template file using: {% url 'book_detail', object.pk %}.

To make it not so verbose, let’s add a get_absolute_url() method which returns a canonical URL for the model:

# models.py
from django.db import models
from django.urls import reverse

class Book(models.Model):
    title = models.CharField(max_length=200)
    author = models.CharField(max_length=200)
    price = models.DecimalField(max_digits=6, decimal_places=2)

    def __str__(self):
        return self.title

    # canonical URL for the model
    def get_absolute_url(self):
        return reverse('book_detail', args=[str(self.pk)])

With this update, there’s no need to use the url template tag for the link. Instead there is one canonical reference in the model.

<a href="{{ book.get_absolute_url }}">{{ book.title }}</a></h2>

This is a cleaner approach and should be used whenever we need individual pages for an object.

Replace pk with UUID

see [[Primary Keys, IDs, Slugs, UUIDs of model object in Django]].


Prev     Next