5. Generic list and detail views - LiVanych/locallibrary GitHub Wiki
Read full version of this artictle
Open /catalog/urls.py
and copy in the line shown below.
urlpatterns = [
path('', views.index, name='index'),
path('books/', views.BookListView.as_view(), name='books'),
]
Open catalog/views.py
, and copy the following code into the bottom of the file:
from django.views import generic
class BookListView(generic.ListView):
model = Book
vim catalog/templates/catalog/book_list.html
{% extends "base_generic.html" %}
{% block content %}
<h1>Book List</h1>
{% if book_list %}
<ul>
{% for book in book_list %}
<li>
<a href="{{ book.get_absolute_url }}">
{{ book.title }}
</a> ({{book.author}})
</li>
{% endfor %}
</ul>
{% else %}
<p>There are no books in the library.</p>
{% endif %}
{% endblock %}
vim catalog/templates/base_generic.html
...
<li><a href="{% url 'index' %}">Home</a></li>
<li><a href="{% url 'books' %}">All books</a></li>
<li><a href="">All authors</a></li>
...
Open /catalog/urls.py
and add the 'book-detail'
URL mapper shown in bold below. This
path()
function defines a pattern, associated generic class-based detail view, and a name.
urlpatterns = [
path('', views.index, name='index'),
path('books/', views.BookListView.as_view(), name='books'),
path('book/<int:pk>', views.BookDetailView.as_view(), name='book-detail'),
]
Open catalog/views.py
, and copy the following code into the bottom of the file:
class BookDetailView(generic.DetailView):
model = Book
vim catalog/templates/catalog/book_detail.html
{% extends "base_generic.html" %}
{% block content %}
<h1>Title: {{ book.title }}</h1>
<p><strong>Author:</strong>
<a href="">{{ book.author }}</a>
</p> <!-- author detail link not yet defined -->
<p><strong>Summary:</strong> {{ book.summary }}</p>
<p><strong>ISBN:</strong> {{ book.isbn }}</p>
<p><strong>Language:</strong> {{ book.language }}</p>
<p><strong>Genre:</strong>
{% for genre in book.genre.all %}
{{ genre }}
{% if not forloop.last %},
{% endif %}
{% endfor %}
</p>
<div style="margin-left:20px;margin-top:20px">
<h4>Copies</h4>
{% for copy in book.bookinstance_set.all %}
<hr>
<p class="
{% if copy.status == 'a' %}text-success
{% elif copy.status == 'm' %}text-danger
{% else %}text-warning
{% endif %}">{{ copy.get_status_display }}</p>
{% if copy.status != 'a' %}
<p><strong>Due to be returned:</strong>
{{copy.due_back}}
</p>
{% endif %}
<p><strong>Imprint:</strong> {{copy.imprint}}</p>
<p class="text-muted"><strong>Id:</strong> {{copy.id}}</p>
{% endfor %}
</div>
{% endblock %}
Open catalog/views.py
, and add the paginate_by
line shown in bold below.
class BookListView(generic.ListView):
model = Book
paginate_by = 10
Open /locallibrary/catalog/templates/base_generic.html
and copy in the following pagination
block below our content block (highlighted below in bold). The code first checks if pagination
is enabled on the current page. If so then it adds next and previous links as appropriate (and
the current page number).
{% block content %}{% endblock %}
{% block pagination %}
{% if is_paginated %}
<div class="pagination">
<span class="page-links">
{% if page_obj.has_previous %}
<a href="
{{ request.path }}?page={{ page_obj.previous_page_number }}">
previous
</a>
{% endif %}
<span class="page-current">
<p>Page {{ page_obj.number }}
of {{ page_obj.paginator.num_pages }}.
</p>
</span>
{% if page_obj.has_next %}
<a href="
{{ request.path }}?page={{ page_obj.next_page_number }}">
next
</a>
{% endif %}
</span>
</div>
{% endif %}
{% endblock %}
The page_obj
is a Paginator object that will exist if pagination is being used on the current
page. It allows you to get all the information about the current page, previous pages, how
many pages there are, etc.
We use to get the current page URL for creating the pagination links. This
is useful, because it is independent of the object that we're paginating.
Thats it!
Built-in class-based generic views (Django docs)
Generic display views (Django docs)
Introduction to class-based views (Django docs)
Built-in template tags and filters (Django docs).
Pagination (Django docs)