Reputation: 44
I am working on MDN Django tutorial on LocalLibrary. I am using get_absolute_url to render generic ListView and DetailView page. App is rendering page with else statement i.e. There are no books in the library. But when I add books in the library through admin portal in my models. Same pages are not rendering and reflecting below error
NoReverseMatch at /catalog/books/
Reverse for 'book-detail' not found. 'book-detail' is not a valid view function or pattern name.
Please find the models.py as follows
import uuid # Required for unique book instances
from django.db import models
# Create your models here.
# Used to generate URLs by reversing the URL patterns
from django.urls import reverse
class Genre(models.Model):
"""Model representing a book genre."""
name = models.CharField(
max_length=200, help_text='Enter a book genre (e.g. Science Fiction)')
def __str__(self):
"""String for representing the Model object."""
return self.name
class Language(models.Model):
name = models.CharField(max_length=200, help_text='Enter a book language(e.g. English)')
def __str__(self):
return self.name
class Book(models.Model):
"""Model representing a book (but not a specific copy of a book)."""
title = models.CharField(max_length=200)
# Foreign Key used because book can only have one author, but authors can have multiple books
# Author as a string rather than object because it hasn't been declared yet in the file
author = models.ForeignKey('Author', on_delete=models.SET_NULL, null=True)
summary = models.TextField(
max_length=1000, help_text='Enter a brief description of the book')
isbn = models.CharField('ISBN', max_length=13, unique=True,
help_text='13 Character <a href="https://www.isbn-international.org/content/what-isbn">ISBN number</a>')
# ManyToManyField used because genre can contain many books. Books can cover many genres.
# Genre class has already been defined so we can specify the object above.
genre = models.ManyToManyField(
Genre, help_text='Select a genre for this book')
language = models.ManyToManyField(
Language, help_text='Select Language for this book')
def __str__(self):
"""String for representing the Model object."""
return self.title
def get_absolute_url(self):
"""Returns the url to access a detail record for this book."""
return reverse('book-detail', kwargs= {'pk': str(self.id)})
def display_genre(self):
"""Create a string for the Genre. This is required to display genre in Admin."""
return ', '.join(genre.name for genre in self.genre.all()[:3])
display_genre.short_description = 'Genre'
def get_language(self):
"""Create a string for the Genre. This is required to display genre in Admin."""
return ', '.join(language.name for language in self.language.all()[:3])
get_language.short_description = 'Language'
class BookInstance(models.Model):
"""Model representing a specific copy of a book (i.e. that can be borrowed from the library)."""
id = models.UUIDField(primary_key=True, default=uuid.uuid4,
help_text='Unique ID for this particular book across whole library')
book = models.ForeignKey('Book', on_delete=models.RESTRICT, null=True)
imprint = models.IntegerField()
due_back = models.DateField(null=True, blank=True)
LOAN_STATUS = (
('m', 'Maintenance'),
('o', 'On loan'),
('a', 'Available'),
('r', 'Reserved'),
)
status = models.CharField(
max_length=1,
choices=LOAN_STATUS,
blank=True,
default='m',
help_text='Book availability',
)
class Meta:
ordering = ['due_back']
def __str__(self):
"""String for representing the Model object."""
return f'{self.id} ({self.book.title})'
class Author(models.Model):
"""Model representing an author."""
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
date_of_birth = models.DateField(null=True, blank=True)
date_of_death = models.DateField('Died', null=True, blank=True)
class Meta:
ordering = ['last_name', 'first_name']
def get_absolute_url(self):
from django.urls import reverse
"""Returns the url to access a particular author instance."""
return reverse('author-detail', args=[str(self.id)])
def __str__(self):
"""String for representing the Model object."""
return f'{self.last_name}, {self.first_name}'
Attached is the urls.py
from django.urls import path
from catalog import views
from catalog.views import BookListView, BookDetailView
app_name = 'catalog'
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'),
path('authors/', views.AuthorListView.as_view(), name='authors'),
path('author/<int:pk>', views.AuthorDetailView.as_view(), name='author-detail'),
]
from django.shortcuts import get_object_or_404
from django.views.generic.list import ListView
from django.views.generic.detail import DetailView
from django.http import HttpResponse
from django.shortcuts import render
from catalog.models import *
def index(request):
num_books = Book.objects.all().count()
num_instances = BookInstance.objects.all().count()
num_genre = Genre.objects.all()
num_instances_available = BookInstance.objects.filter(status__exact='avail').count()
num_authors = Author.objects.count()
context = {
'num_books': num_books,
'num_instances': num_instances,
'num_instances_available': num_instances_available,
'num_authors': num_authors,
'num_genre': num_genre,
}
return render(request, 'catalog/index.html', context=context)
class BookListView(ListView):
model = Book
paginate_by = 2
class BookDetailView(DetailView):
model = Book
class AuthorListView(ListView):
model = Author
class AuthorDetailView(DetailView):
model = Author
{% extends "catalog/base.html" %}
{% block title %}
<title>List of Books</title>
{% endblock %}
{% 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>
<a href="{{ author.get_absolute_url }}">({{ book.author }})</a>
</li>
{% endfor %}
</ul>
{% else %}
<p>There are no books in the library.</p>
{% endif %}
{% endblock %}
{% block content %}
<h1>Title: {{ book.title }}</h1>
<p><strong>Author:</strong> <a href="{{ book.author.get_absolute_url }}">{{ book.author }}</a></p>
<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> {{ book.genre.all|join:", " }}</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 == 'd' %}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 %}```
I also find error on the same page for bootstrap link which is getting extended from base file and working fine with index.html
whereas on books.html page
It is showing this error
In template /Users/rishipalsingh/Projects/notes/mdndjango/mdn/catalog/templates/catalog/base.html, error at line 7
base.html
```
Thank you
Upvotes: 0
Views: 72
Reputation: 21806
You have namespaced your urls by writing:
app_name = 'catalog'
Hence reverse('book-detail', ...)
will not work and you need to specify the namespace along with the url name, hence it should be:
reverse('catalog:book-detail', kwargs= {'pk': str(self.id)})
Similarly for the author:
reverse('catalog:author-detail', args=[str(self.id)])
Upvotes: 1