Coverage for catalog/views.py: 96.91%

93 statements  

« prev     ^ index     » next       coverage.py v7.17.0, created at 2026-10-29 10:34 -0700

1import datetime 1a

2from typing import ClassVar 1a

3 

4from django.contrib.auth.decorators import login_required, permission_required 1a

5from django.contrib.auth.mixins import ( 1a

6 LoginRequiredMixin, 

7 PermissionRequiredMixin, 

8) 

9from django.db.models import Q 1a

10from django.http import HttpResponseRedirect 1a

11from django.shortcuts import get_object_or_404, render 1a

12from django.urls import reverse, reverse_lazy 1a

13from django.views.generic import ( 1a

14 CreateView, 

15 DeleteView, 

16 DetailView, 

17 ListView, 

18 UpdateView, 

19) 

20 

21from .forms import RenewBookForm 1a

22from .models import Author, Book, BookInstance 1a

23 

24 

25def index(request): 1a

26 num_books = Book.objects.all().count() 1a

27 num_instances = BookInstance.objects.all().count() 1a

28 num_instances_available = BookInstance.objects.filter(status__exact="a").count() 1a

29 num_authors = Author.objects.count() 1a

30 num_visits = request.session.get("num_visits", 0) 1a

31 request.session["num_visits"] = num_visits + 1 1a

32 context = { 1a

33 "num_books": num_books, 

34 "num_instances": num_instances, 

35 "num_instances_available": num_instances_available, 

36 "num_authors": num_authors, 

37 "num_visits": num_visits, 

38 } 

39 

40 return render(request, "index.html", context=context) 1a

41 

42 

43class BookListView(ListView): 1a

44 """Generic class-based view for a list of books.""" 

45 

46 model = Book 1a

47 paginate_by = 10 1a

48 

49 

50class BookDetailView(DetailView): 1a

51 """Generic class-based detail view for a book.""" 

52 

53 model = Book 1a

54 

55 

56class AuthorListView(ListView): 1a

57 """Generic class-based list view for a list of authors.""" 

58 

59 model = Author 1a

60 paginate_by = 10 1a

61 

62 

63class AuthorDetailView(DetailView): 1a

64 """Generic class-based detail view for an author.""" 

65 

66 model = Author 1a

67 

68 

69class LoanedBooksByUserListView(LoginRequiredMixin, ListView): 1a

70 model = BookInstance 1a

71 template_name = "catalog/bookinstance_list_borrowed_user.html" 1a

72 paginate_by = 10 1a

73 

74 def get_queryset(self): 1a

75 return ( 1a

76 BookInstance.objects.filter(borrower=self.request.user) 

77 .filter(status__exact="o") 

78 .order_by("due_back") 

79 ) 

80 

81 

82class LoanedBooksAllListView(PermissionRequiredMixin, ListView): 1a

83 model = BookInstance 1a

84 permission_required = "catalog.can_mark_returned" 1a

85 template_name = "catalog/bookinstance_list_borrowed_all.html" 1a

86 paginate_by = 10 1a

87 

88 def get_queryset(self): 1a

89 return BookInstance.objects.filter(status__exact="o").order_by("due_back") 1a

90 

91 

92@login_required 1a

93@permission_required("catalog.can_mark_returned", raise_exception=True) 1a

94def renew_book_librarian(request, pk): 1a

95 """View function for renewing a specific BookInstance by librarian.""" 

96 book_instance = get_object_or_404(BookInstance, pk=pk) 1a

97 

98 # If this is a POST request then process the Form data 

99 if request.method == "POST": 1a

100 # Create a form instance and populate it with data 

101 # from the request (binding): 

102 form = RenewBookForm(request.POST) 1a

103 

104 # Check if the form is valid: 

105 if form.is_valid(): 105 ↛ 119line 105 didn't jump to line 119 because the condition on line 105 was always true1a

106 # process the data in form.cleaned_data as required (here we 

107 # just write it to the model due_back field) 

108 book_instance.due_back = form.cleaned_data["renewal_date"] 1a

109 book_instance.save() 1a

110 

111 # redirect to a new URL: 

112 return HttpResponseRedirect(reverse("all-borrowed")) 1a

113 

114 # If this is a GET (or any other method) create the default form 

115 else: 

116 proposed_renewal_date = datetime.date.today() + datetime.timedelta(weeks=3) 1a

117 form = RenewBookForm(initial={"renewal_date": proposed_renewal_date}) 1a

118 

119 context = { 1a

120 "form": form, 

121 "book_instance": book_instance, 

122 } 

123 

124 return render(request, "catalog/book_renew_librarian.html", context) 1a

125 

126 

127class AuthorCreate(PermissionRequiredMixin, CreateView): 1a

128 model = Author 1a

129 fields: ClassVar[list[str]] = ["first_name", "last_name", "date_of_birth", "date_of_death"] 1a

130 initial: ClassVar[dict[str]] = {"date_of_birth": "02/02/1882"} 1a

131 permission_required = "catalog.can_mark_returned" 1a

132 template_name = "catalog/author_create.html" 1a

133 

134 

135class AuthorUpdate(PermissionRequiredMixin, UpdateView): 1a

136 model = Author 1a

137 fields: ClassVar[list[str]] = [ 1a

138 "first_name", 

139 "last_name", 

140 "middle_name", 

141 "date_of_birth", 

142 "date_of_death", 

143 ] 

144 permission_required = "catalog.can_mark_returned" 1a

145 template_name = "catalog/author_update.html" 1a

146 

147 

148class AuthorDelete(PermissionRequiredMixin, DeleteView): 1a

149 model = Author 1a

150 permission_required = "catalog.can_mark_returned" 1a

151 success_url = reverse_lazy("authors") 1a

152 

153 

154class BookCreate(PermissionRequiredMixin, CreateView): 1a

155 model = Book 1a

156 fields: ClassVar[list[str]] = [ 1a

157 "title", 

158 "author", 

159 "pages", 

160 "publisher", 

161 "pubdate", 

162 "summary", 

163 "isbn", 

164 "genre", 

165 "language", 

166 ] 

167 permission_required = "catalog.can_mark_returned" 1a

168 template_name = "catalog/book_create.html" 1a

169 

170 

171class BookUpdate(PermissionRequiredMixin, UpdateView): 1a

172 model = Book 1a

173 fields: ClassVar[list[str]] = [ 1a

174 "title", 

175 "author", 

176 "pages", 

177 "publisher", 

178 "pubdate", 

179 "summary", 

180 "isbn", 

181 "genre", 

182 "language", 

183 ] 

184 permission_required = "catalog.can_mark_returned" 1a

185 template_name = "catalog/book_update.html" 1a

186 

187 

188class BookDelete(PermissionRequiredMixin, DeleteView): 1a

189 model = Book 1a

190 success_url = reverse_lazy("books") 1a

191 permission_required = "catalog.can_mark_returned" 1a

192 

193 

194class SearchResultsListView(ListView): 1a

195 model = Book 1a

196 context_object_name = "books" 1a

197 template_name = "catalog/search_results.html" 1a

198 

199 def get_queryset(self): 1a

200 query = self.request.GET.get("q") 

201 return Book.objects.filter( 

202 Q(title__icontains=query) 

203 | Q(author__first_name__icontains=query) 

204 | Q(author__middle_name__icontains=query) 

205 | Q(author__last_name__icontains=query) 

206 | Q(language__name__icontains=query) 

207 | Q(publisher__icontains=query) 

208 | Q(pubdate__icontains=query) 

209 | Q(genre__name=query) 

210 ).distinct()