前言 ´・ᴗ・`
- 上一節我們建立了主頁 這裏我們來創建一些別的網頁 比如關於books author等等
- 本篇內容將會幫助你學習…
- 1 ListView的應用
- 2 DetailView的應用
Listview
就是 “列表視圖” 別被名字嚇到了 這是最簡單的視圖構建“套路”
就是在指定的數據庫(類)中取出所有數據 然後列表顯示出來
比如像百度那種就是典型的
還記得上節 我們是編輯過view的
像這樣從數據庫取數據:
num_books = Book.objects.all().count()
num_instances = BookInstance.objects.all().count()
num_instances_available = BookInstance.objects.filter(status__exact='a').count()
num_authors = Author.objects.count() # The 'all()' is implied by default.
然後 context打包 通過render送到template那邊去填空:
context = {
'num_books': num_books,
'num_instances': num_instances,
'num_instances_available': num_instances_available,
'num_authors': num_authors,
'num_visits': num_visits,
}
# Render the HTML template index.html with the data in the context variable.
return render(request, 'index.html', context=context)
不過上次有點不同 需要統計數據(多少本書什麼的) 用了count()
這裏 我們更加傻瓜化——直接把數據庫所有書倒出來 然後一列顯示就ok了
django給我們封裝了這種傻瓜化的view處理 就是Listview
而且用as_view() 函數來執行
具體操作很簡單
1.catalog/view.py 添加:
from django.views import generic
class BookListView(generic.ListView):
model = Book
BookListView 針對數據庫Book模型的ListView
- 模板編輯:
創建: /locallibrary/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.title }}</a> ({{book.author}})
</li>
{% endfor %}
</ul>
{% else %}
<p>There are no books in the library.</p>
{% endif %}
{% endblock %}
當然 URL映射別忘了:
urlpatterns = [
path('', views.index, name='index'),
path('books/', views.BookListView.as_view(), name='books'),
path('authors/', views.AuthorListView.as_view(), name='authors'),
]
我們可以發現
- 模板的名字 book_list.html
- 模板變量 就是那個{% for book in book_list %} 引用的book_list 這個變量
奇怪不?我們從來沒定義過 怎麼就能用了呢?
這就是ListView幫我們乾的事 當然也約定 模板名字與模板變量都採用model那個類的名字+list
class book ->book_list
ListView 的細節修改
事實上 是一個函數爲get queryset 做了 從數據庫拿數據到view的工作
因此 我們通過修改這個函數 自然也可以控制輸出的結果‘
實現這點 ’
- 可以從前端搞定 前端js當然可以限制 動態輸出
- 也可以後端限制 通過django支持的模板的一些分支語句(if else)
- 還可以源頭上 數據庫調用的時候就減少數據傳輸
這裏更改get queryset算是第三種方式 舉例:
class BookListView(generic.ListView):
model = Book
paginate_by = 4
def get_queryset(self):
return Book.objects.filter(title__icontains='ryan')[:5] # Get 5 books containing the title war
篩選所有title包含ryan的數據記錄 然後返回給render
另外 paginate_by = 4
限制了一頁中顯示最大的記錄條數
類似sql的LIMIT BY
然後這裏我們就可以runserver一下啦:
編輯每本書的詳情頁
我們只是作了個書的清單 但是詳情頁還沒弄
這裏 先把book_list.html 修改一下
{% for book in book_list %}
<li>
<a href="{{ book.get_absolute_url }}">{{ book.title }}</a> ({{book.author}})
</li>
{% endfor %}
主要是超鏈接的內容加上了
然後我們大膽的添加書本的詳情頁 url映射
urlpatterns = [
path('', views.index, name='index'),
path('books/', views.BookListView.as_view(), name='books'),
path('authors/', views.AuthorListView.as_view(), name='authors'),
path('book/<int:pk>', views.BookDetailView.as_view(), name='book-detail'),
path('author/<int:pk>', views.AuthorDetailView.as_view(), name='author-detail'),
]
author的套路相同 一併添加了:)
這裏 <> 就類似正則表達式 捕獲url地址中 author/
後面所有的數字 並且存到pk
這個變量裏面
如果url捕獲參數的模式(pattern) 很複雜 歡迎使用re_path() 函數代替path() 並且使用re正則表達式
這裏限於篇幅不講了 網上有關教程很多
我們應用repath 可以這麼寫:
re_path(r'^book/(?P<pk>\d+)$', views.BookDetailView.as_view(), name='book-detail'),
注意path()不採用·正則 其語法規則很簡單 功能很弱
re_path()是完全用正則表達式的 功能無敵強
detailView
ListView特別適合 大致列個表 這種應用 目錄菜單什麼的
然而detailview提供一個適合“詳情頁”的佈局視圖
非常類似ListView 你只需在catalog/view.py 中添加:
class BookDetailView(generic.DetailView):
model = Book
同樣 book_detail 作爲模板的文件名稱:
不過模板變量變成model的類名 book
在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 %}
注意“book.bookinstance_set”
首先 book 與 bookinstance 是外鍵 而且是一對多的
我們這裏在book這端 用“一”引用多 就用了book.bookinstance_set 這是django給我們封裝好的
分頁的編輯
我們之前通過paginate_by = 10 進行分頁 但這只是源頭上限制了數據 但不能實現“前一頁”“後一頁”的按鈕等
django封裝了這個
由於我們幾乎所有網頁都這樣式 我們直接在base_generic 更改:
打開 /locallibrary/catalog/templates/base_generic.html
{% 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">
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
</span>
{% if page_obj.has_next %}
<a href="{{ request.path }}?page={{ page_obj.next_page_number }}">next</a>
{% endif %}
</span>
</div>
{% endif %}
{% endblock %}
-
page_obj 是一個 Paginator 對象,如果在當前頁面上使用分頁 如paginate_by = 10 ,它將啓動
這玩意允許您獲取有關當前頁面,之前頁面,有多少頁面等的所有信息。 -
{{ request.path }}可用來獲取用於創建分頁鏈接的當前頁面URL。
另外 我們順便把author的也弄了:
模板 template/catalog/author_detail.html:
{% extends "base_generic.html" %}
{% block content %}
<h1> {{ author.first_name }}.{{author.last_name}}</h1>
<p><strong>living:</strong> {{ author.first_name }}.{{ author.last_name }} ({{ author.date_of_birth }}-{{ author.date_of_death }})</p>
<div style="margin-left:20px;margin-top:20px">
<h4>What this poor bastard wrote:</h4><ul>
<!-- 這裏反向查找 ‘多’引用‘一’ 而不像之前的 ‘一’引用‘多’ -->
{% for copy in author.book_set.all %}
<li><a href="">《{{copy.title}}》 ISBN:{{copy.isbn}}</a></li>
{% endfor %}
</ul>
</div>
{% endblock %}
模板 template/catalog/author_list.html:
{% extends "base_generic.html" %}
{% block content %}
<h1>Author List</h1>
{% if author_list %}
<ul>
{% for author in author_list %}
<li>
<a href="{{ author.get_absolute_url }}">{{ author.first_name }}.{{ author.last_name }}</a>
</li>
{% endfor %}
</ul>
{% else %}
<p>There are no one.</p>
{% endif %}
{% endblock %}
catalog/view.py 添加
class AuthorListView(generic.ListView):
model = Author
paginate_by = 5
class AuthorDetailView(generic.DetailView):
model = Author
結語( ̄︶ ̄)↗
runserver檢驗戰果
不出意外 你將收穫:
到這裏 基本上很多頁面都能搞定了
下一站 我們會聊聊 會話
這是軟菜雞的其他系列學習文章 希望能夠幫到你 ( •̀ ω •́ )✧