先決條件: | 完成之前的所有教學(xué)主題,包括 Django教程第5部分:創(chuàng)建我們的主頁(yè)。 |
---|---|
目的: | 了解在何處以及如何使用基于類的基本視圖,以及如何從URL中提取模式并將信息傳遞給視圖。 |
在本教程中,我們將完成第一個(gè)版本的 LocalLibrary >通過(guò)添加圖書(shū)和作者的列表和詳細(xì)信息頁(yè)面(或更準(zhǔn)確地說(shuō),我們將向您介紹如何實(shí)現(xiàn)圖書(shū)頁(yè)面,并讓您自己創(chuàng)建作者頁(yè)面)。
該過(guò)程類似于創(chuàng)建索引頁(yè),我們?cè)谏弦粋€(gè)教程中顯示。 我們?nèi)匀恍枰獎(jiǎng)?chuàng)建URL地圖,視圖和模板。 主要的區(qū)別是,對(duì)于詳細(xì)頁(yè)面,我們將有額外的挑戰(zhàn),從URL中的模式提取信息并將其傳遞給視圖。 對(duì)于這些頁(yè)面,我們將演示一個(gè)完全不同類型的視圖:基于類的列表和詳細(xì)視圖。 這些可以顯著減少所需的視圖代碼量,使其更易于編寫(xiě)和維護(hù)。
本教程的最后一部分將演示如何在使用基于類的列表視圖時(shí)對(duì)數(shù)據(jù)進(jìn)行分頁(yè)。
圖書(shū)列表頁(yè)面將顯示頁(yè)面中所有可用圖書(shū)記錄的列表,使用以下網(wǎng)址訪問(wèn): catalog / books /
。 該頁(yè)面將顯示每個(gè)記錄的標(biāo)題和作者,標(biāo)題是相關(guān)聯(lián)的圖書(shū)詳細(xì)信息頁(yè)面的超鏈接。 該網(wǎng)頁(yè)與網(wǎng)站中的所有其他網(wǎng)頁(yè)具有相同的結(jié)構(gòu)和導(dǎo)航,因此可以擴(kuò)展我們?cè)谏弦唤坛讨袆?chuàng)建的基本模板( base_generic.html )。
打開(kāi) /catalog/urls.py ,然后復(fù)制下面粗體顯示的行。 與我們的索引映射非常類似,這個(gè) url()
函數(shù)定義了一個(gè)正則表達(dá)式(RE)來(lái)匹配URL( r\'^ books / $\' 如果URL匹配( views.BookListView.as_view()
)和此特定映射的名稱,則將調(diào)用此函數(shù)。
urlpatterns = [ url(r'^$', views.index, name='index'), ? url(r'^books/$', views.BookListView.as_view(), name='books'), ]
這里的正則表達(dá)式匹配等于 books /
( ^
是字符串開(kāi)始標(biāo)記, $
是字符串標(biāo)記的結(jié)尾)的URL。 如前面的教程中所討論的,URL必須已經(jīng)具有匹配的 / catalog
,因此視圖將實(shí)際調(diào)用URL: / catalog / books /
。
視圖函數(shù)具有與以前不同的格式 - 這是因?yàn)榇艘晥D實(shí)際上將實(shí)現(xiàn)為類。 我們將繼承一個(gè)現(xiàn)有的通用視圖函數(shù),它已經(jīng)完成了我們想要此視圖函數(shù)所做的大部分工作,而不是從頭開(kāi)始編寫(xiě)自己的視圖函數(shù)。
對(duì)于基于Django類的視圖,我們通過(guò)調(diào)用類方法 as_view()
來(lái)訪問(wèn)一個(gè)合適的視圖函數(shù)。 這將完成創(chuàng)建類的實(shí)例的所有工作,并確保為傳入的HTTP請(qǐng)求調(diào)用正確的處理程序方法。
我們可以很容易地將書(shū)列表視圖作為常規(guī)函數(shù)(就像我們以前的索引視圖一樣),它將查詢數(shù)據(jù)庫(kù)中的所有書(shū),然后調(diào)用 render()
將列表傳遞給 指定模板。 相反,我們將使用基于類的通用列表視圖(ListView) - 從現(xiàn)有視圖繼承的類。 因?yàn)橥ㄓ靡晥D已經(jīng)實(shí)現(xiàn)了我們所需要的大多數(shù)功能,并且遵循Django最佳實(shí)踐,我們將能夠創(chuàng)建一個(gè)更健壯的列表視圖,代碼更少,重復(fù)次數(shù)更少,最終減少維護(hù)。
打開(kāi) catalog / views.py ,然后將以下代碼復(fù)制到文件底部:
from django.views import generic class BookListView(generic.ListView): model = Book
而已! 通用視圖將查詢數(shù)據(jù)庫(kù)以獲取指定模型的所有記錄( Book
),然后渲染位于 /locallibrary/catalog/templates/catalog/book_list.html (我們將在下面創(chuàng)建)。 在模板中,您可以使用名為 object_list
或 book_list
的模板變量訪問(wèn)圖書(shū)列表(即通常為" the_model_name _list 代碼>")。
注意:模板位置的尷尬路徑不是錯(cuò)誤印記 - 通用視圖會(huì)在 / application_name / the_model_name
應(yīng)用程序的 / application_name / templates /
目錄()中的
( / list.html
catalog / book_list.html
> / catalog / templates /)。
您可以添加屬性以更改上述默認(rèn)行為。 例如,如果您需要具有使用此相同模型的多個(gè)視圖,則可以指定另一個(gè)模板文件,或者如果 book_list
對(duì)您的特定模板使用不直觀,則可能需要使用不同的模板變量名稱 -案件。 可能最有用的變化是更改/過(guò)濾返回的結(jié)果子集 - 因此,不是列出所有圖書(shū),而是列出其他用戶閱讀的前5個(gè)圖書(shū)。
class BookListView(generic.ListView): model = Book context_object_name = 'my_book_list' # your own name for the list as a template variable queryset = Book.objects.filter(title__icontains='war')[:5] # Get 5 books containing the title war template_name = 'books/my_arbitrary_template_name_list.html' # Specify your own template name/location
雖然我們不需要這樣做,你也可以覆蓋一些類方法。
例如,我們可以覆蓋 get_queryset()
方法來(lái)更改返回的記錄列表。 這比設(shè)置 queryset
屬性更靈活,就像我們?cè)谇懊娴拇a片段中做的那樣(雖然在這種情況下沒(méi)有真正的好處):
class BookListView(generic.ListView): model = Book ? ? def get_queryset(self): ? ? ? ? return Book.objects.filter(title__icontains='war')[:5] # Get 5 books containing the title war
我們還可以覆蓋 get_context_data()
,以便將其他上下文變量傳遞給模板(例如,默認(rèn)情況下會(huì)傳遞書(shū)籍列表)。 下面的片段顯示了如何向上下文添加一個(gè)名為"some_data"的變量(它將作為模板變量使用)。
class BookListView(generic.ListView): model = Book ? ? def get_context_data(self, **kwargs): ? ? ? ? # Call the base implementation first to get a context ? ? ? ? context = super(BookListView, self).get_context_data(**kwargs) ? ? ? ? # Get the blog from id and add it to the context ? ? ? ? context['some_data'] = 'This is just some data' ? ? ? ? return context
當(dāng)這樣做時(shí),重要的是遵循上面使用的模式:
注意:查看內(nèi)置 - 在基于類的通用視圖(Django docs)中有更多可以做的事例。
創(chuàng)建HTML文件 /locallibrary/catalog/templates/catalog/book_list.html ,然后在下面的文本中復(fù)制。 如上所述,這是基于通用類的列表視圖(對(duì)于名為目錄
的應(yīng)用程序中名為 Book
的模型)所期望的默認(rèn)模板文件。
通用視圖的模板就像任何其他模板(雖然傳遞給模板的上下文/信息當(dāng)然可能不同)。 與我們的 index 模板一樣,我們?cè)诘谝恍兄袛U(kuò)展我們的基本模板,然后替換名為 content
的塊。
{% 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 %}
默認(rèn)情況下,視圖傳遞上下文(書(shū)籍列表)為 object_list
和 book_list
(別名;將起作用)。
我們使用 如果
, else
和 endif
模板標(biāo)簽來(lái)檢查 book_list
是否已定義并且不為空。 它是空的( else
子句),然后我們顯示文本,說(shuō)明沒(méi)有圖書(shū)要顯示。 如果它不為空,那么我們遍歷書(shū)的列表。
{% if book_list %} <!-- code here to list the books --> {% else %} <p>There are no books in the library.</p> {% endif %}
上述條件僅檢查一種情況,但您可以使用 elif
模板標(biāo)記(例如 {%elif var2%}
)對(duì)其他條件進(jìn)行測(cè)試。 有關(guān)條件運(yùn)算符的詳情,請(qǐng)參閱:如果, class ="external"> ifequal / ifnotequal 和 https://docs.djangoproject.com/en/1.10/ref/templates/builtins/#ifchanged"class ="external"> ifchanged 在 en / 1.10 / ref / templates / builtins"class ="external">內(nèi)置模板標(biāo)簽和過(guò)濾器(Django Docs)。
該模板使用 和 endfor
代碼>模板標(biāo)記循環(huán)訪問(wèn)圖書(shū)列表,如下所示。 每次迭代用當(dāng)前列表項(xiàng)的信息填充 book
模板變量。
{% for book in book_list %} <li> <!-- code here get information from each book item --> </li> {% endfor %}
雖然這里不使用,但在循環(huán)內(nèi)Django還將創(chuàng)建其他變量,您可以使用它來(lái)跟蹤迭代。 例如,您可以測(cè)試 forloop.last
變量,以便在上次運(yùn)行循環(huán)時(shí)執(zhí)行條件處理。
循環(huán)中的代碼為每本書(shū)創(chuàng)建一個(gè)列表項(xiàng),該列表項(xiàng)顯示標(biāo)題(作為尚未創(chuàng)建的詳細(xì)視圖的鏈接)和作者。
<a href="{{ book.get_absolute_url }}">{{ book.title }}</a> ({{book.author}})
我們使用"點(diǎn)符號(hào)"(例如 book.title
和 book.author
)訪問(wèn)關(guān)聯(lián)的圖書(shū)記錄的字段 在 book
項(xiàng)下是字段名(如模型中定義)。
我們還可以在模板中從模板中調(diào)用函數(shù) - 在這種情況下,我們調(diào)用 Book.get_absolute_url()
獲取一個(gè)URL, 。 這個(gè)工作提供的函數(shù)沒(méi)有任何參數(shù)(沒(méi)有辦法傳遞參數(shù)!)
注意:在模板中調(diào)用函數(shù)時(shí),我們必須小心處理"副作用"。 這里我們只是得到一個(gè)顯示的URL,但是一個(gè)函數(shù)可以做任何事情 - 我們不想刪除我們的數(shù)據(jù)庫(kù)(例如)只是通過(guò)渲染我們的模板!
打開(kāi)基本模板( / locallibrary / catalog / templates / base_generic.html ),然后在網(wǎng)址中插入 {%url\'books\'%} 所有圖書(shū)的鏈接,如下所示。 這將啟用所有頁(yè)面的鏈接(我們可以成功地把它放在位,現(xiàn)在我們已經(jīng)創(chuàng)建了"書(shū)籍"URL映射器)。
<li><a href="{% url 'index' %}">Home</a></li> <li><a href="{% url 'books' %}">All books</a></li> <li><a href="">All authors</a></li>
您將無(wú)法構(gòu)建圖書(shū)列表,因?yàn)槲覀內(nèi)匀蝗鄙僖蕾図?xiàng) - 圖書(shū)詳細(xì)信息頁(yè)面的URL地圖,需要?jiǎng)?chuàng)建指向各個(gè)圖書(shū)的超鏈接。 在下一節(jié)后,我們將顯示列表和詳細(xì)信息視圖。
書(shū)詳細(xì)信息頁(yè)將顯示關(guān)于使用網(wǎng)址 catalog / book / < id>
(其中 < id>
是圖書(shū)的主鍵)。 除了 Book
模型(作者,摘要,ISBN,語(yǔ)言和流派)中的字段,我們還會(huì)列出可用副本的詳細(xì)信息( BookInstances
), 狀態(tài),預(yù)期的返回日期,印記和ID,這將使我們的讀者不僅了解這本書(shū),而且確認(rèn)是否/何時(shí)可用。
打開(kāi) /catalog/urls.py 并添加" book-detail "URL映射器,如下面的粗體所示。 這個(gè) url()
函數(shù)定義一個(gè)模式,關(guān)聯(lián)的基于類的詳細(xì)視圖和一個(gè)名稱。
urlpatterns = [ url(r'^$', views.index, name='index'), ? url(r'^books/$', views.BookListView.as_view(), name='books'), ? url(r'^book/(?P<pk>\d+)$', views.BookDetailView.as_view(), name='book-detail'), ]
與我們以前的映射器不同,在這種情況下,我們使用正則表達(dá)式(RE)匹配一個(gè)真正的"模式",而不只是一個(gè)字符串。 這個(gè)特定的RE所做的是與以 book /
開(kāi)頭的任何網(wǎng)址匹配,后跟在行標(biāo)記結(jié)束之前的一個(gè)或多個(gè)數(shù)字(數(shù)字)。 在執(zhí)行匹配時(shí),它"捕獲"數(shù)字,并將它們作為名為 pk
的參數(shù)傳遞給視圖函數(shù)。
注意:如前所述,我們匹配的網(wǎng)址實(shí)際上是 catalog / book /< digits>
(因?yàn)槲覀兾挥?strong>目錄應(yīng)用程序 代碼> / catalog / )。
重要:通用基于類的詳細(xì)視圖期望傳遞名為pk的參數(shù)。 如果你正在編寫(xiě)我們自己的函數(shù)視圖,你可以使用任何你喜歡的參數(shù)名,或者確實(shí)在一個(gè)未命名的參數(shù)傳遞信息。
正則表達(dá)式是一個(gè)令人難以置信的強(qiáng)大的模式映射工具。 我們之前已經(jīng)避免了很多關(guān)于它們的事情,因?yàn)槲覀冊(cè)赨RL中匹配硬編碼的字符串(而不是模式),并且坦率地說(shuō),它們對(duì)初學(xué)者來(lái)說(shuō)是非常直觀和可怕的。
注意:不要驚慌! 我們將匹配的模式很簡(jiǎn)單,在很多情況下都有很好的文檔!
首先要知道的是,正則表達(dá)式通常應(yīng)該使用原始字符串文字語(yǔ)法來(lái)聲明(即它們?nèi)缦滤? r\'
聲明模式匹配所需的語(yǔ)法的主要部分是:
符號(hào) | 含義 |
---|---|
^ | 匹配文本的開(kāi)頭 |
$ | 匹配文本的結(jié)尾 |
\d | 匹配數(shù)字(0,1,2,... 9) |
\w | 匹配字詞字符,例如 字母表中的任何大寫(xiě)或小寫(xiě)字符,數(shù)字或下劃線字符(_) |
+ | Match one or more of the preceding character. For example, to match one or more digits you would use \d+ . To match one or more "a" characters, you could use a+
|
* | Match zero or more of the preceding character. For example, to match nothing or a word you could use \w*
|
() | 捕獲括號(hào)內(nèi)的模式部分。 任何捕獲的值都將作為未命名參數(shù)傳遞到視圖(如果捕獲多個(gè)模式,則相關(guān)參數(shù)將按聲明捕獲的順序提供)。 |
(?P<name>...) | 捕獲模式(由...指示)作為命名變量(在本例中為"名稱")。 捕獲的值將傳遞到具有指定名稱的視圖。 因此,您的視圖必須聲明具有相同名稱的參數(shù)! |
[] | 與集合中的一個(gè)字符匹配。 例如,[abc]將匹配\'a\'或\'b\'或\'c\'。 [ - \\ w]將匹配" - "字符或任何字字符。 |
大多數(shù)其他字符可以采取字面意思!
讓我們考慮幾個(gè)真實(shí)的模式例子:
模式 | 描述 |
---|---|
r'^book/(?P<pk>\d+)$' |
這是我們的url映射器中使用的RE。 它與在行開(kāi)頭有 它還捕獲所有數(shù)字(?P 例如,這將匹配 |
r'^book/(\d+)$' | 此匹配與上述情況相同的網(wǎng)址。 捕獲的信息將作為未命名的參數(shù)發(fā)送到視圖。 |
r'^book/(?P<stub>[-\w]+)$' |
此操作與在行開(kāi)頭有 這是一個(gè)相當(dāng)?shù)湫偷哪J綖?存根"。 存根是用于數(shù)據(jù)的基于URL的基于字的主鍵。 如果您希望圖書(shū)網(wǎng)址更具信息性,則可以使用存根。 例如 |
您可以在一個(gè)匹配中捕獲多個(gè)模式,從而在URL中編碼大量不同的信息。
注意:作為一個(gè)挑戰(zhàn),請(qǐng)考慮如何對(duì)網(wǎng)址進(jìn)行編碼,以列出在特定年份,月份,日期和RE中發(fā)布的所有可用于匹配的圖書(shū)。
我們?cè)谶@里沒(méi)有使用,但您可能會(huì)發(fā)現(xiàn)有價(jià)值的一個(gè)功能是,您可以聲明并傳遞 views-extra-options"class ="external">其他選項(xiàng)。 選項(xiàng)聲明為一個(gè)字典,作為第三個(gè)未命名的參數(shù)傳遞給 url()
函數(shù)。 如果要對(duì)多個(gè)資源使用相同的視圖,并傳遞數(shù)據(jù)以配置其在每種情況下的行為(在每種情況下我們提供不同的模板),此方法可能很有用。
url(r'^/url/$', views.my_reused_view, {'my_template_name': 'some_path'}, name='aurl'), url(r'^/anotherurl/$', views.my_reused_view, {'my_template_name': 'another_path'}, name='anotherurl'),
注意:將兩個(gè)額外選項(xiàng)和命名捕獲的模式作為命名的參數(shù)傳遞給視圖。 如果對(duì)捕獲的模式和額外選項(xiàng)使用同名,則只會(huì)將捕獲的模式值發(fā)送到視圖(在附加選項(xiàng)中指定的值將被刪除)。
打開(kāi) catalog / views.py ,然后將以下代碼復(fù)制到文件底部:
class BookDetailView(generic.DetailView): ? ? model = Book
而已! 您現(xiàn)在需要做的是創(chuàng)建一個(gè)名為 /locallibrary/catalog/templates/catalog/book_detail.html 的模板,該視圖將為其傳遞特定 Book
的數(shù)據(jù)庫(kù)信息 >記錄由URL映射器提取。 在模板中,您可以使用名為 object
或 book
的模板變量訪問(wèn)書(shū)籍列表(即通常為" the_model_name
>")。
如果需要,可以更改模板中使用的模板以及用于引用該書(shū)的上下文對(duì)象的名稱。 您還可以覆蓋方法,例如,向上下文添加附加信息。
如果一個(gè)請(qǐng)求的記錄不存在,那么通用的基于類的細(xì)節(jié)視圖將自動(dòng)引發(fā)一個(gè)Http404異常 - 在生產(chǎn)中,這將自動(dòng)顯示一個(gè)適當(dāng)?shù)?找不到資源"頁(yè)面,如果需要可以自定義。
只是為了讓你了解這是如何工作的,下面的代碼片段演示了如何實(shí)現(xiàn)基于類的視圖作為一個(gè)函數(shù),如果你不使用通用基于類的細(xì)節(jié)視圖。
def book_detail_view(request,pk): try: book_id=Book.objects.get(pk=pk) except Book.DoesNotExist: raise Http404("Book does not exist") ? #book_id=get_object_or_404(Book, pk=pk) return render( request, 'catalog/book_detail.html', context={'book':book_id,} )
視圖首先嘗試從模型中獲取特定的書(shū)記錄。 如果這個(gè)失敗,視圖應(yīng)該引發(fā)一個(gè) Http404
異常,表示該書(shū)"找不到"。 最后一步是像往常一樣,使用模板名稱和 context
參數(shù)(作為字典)調(diào)用 render()
。
注意:如果未找到記錄,則 get_object_or_404()
(如上所示已注釋掉)是提高 Http404
異常的一個(gè)方便的快捷方式。
創(chuàng)建HTML文件 /locallibrary/catalog/templates/catalog/book_detail.html ,并為其提供以下內(nèi)容。 如上所述,這是基于通用類的 detail 視圖(在名為目錄的應(yīng)用程序中名為
代碼>)。 Book
的模型)
{% 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 == '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 %}
上面的tempate中的作者鏈接有一個(gè)空的網(wǎng)址,因?yàn)槲覀冞€沒(méi)有創(chuàng)建一個(gè)作者詳細(xì)頁(yè)面。 一旦存在,您應(yīng)該更新URL如下:
<a href="{% url 'author-detail' book.author.pk %}">{{ book.author }}</a>
雖然有點(diǎn)大,幾乎在這個(gè)模板中的一切都已經(jīng)描述過(guò):
for
loops to loop through lists of objects.book
; we could also use "object
")我們之前沒(méi)有看到的一個(gè)有趣的事情是函數(shù) book.bookinstance_set.all()
。 這個(gè)方法是由Django"自動(dòng)地"構(gòu)造的,以返回與特定 Book
相關(guān)聯(lián)的 BookInstance
記錄集。
{% for copy in book.bookinstance_set.all %} <!-- code to iterate across each copy/instance of a book --> {% endfor %}
需要此方法,因?yàn)槟辉陉P(guān)系的"一"端聲明了一個(gè) ForeignKey
(一對(duì)多)字段。 因?yàn)槟銢](méi)有在其他("many")模型中聲明關(guān)系,所以它沒(méi)有任何字段來(lái)獲取關(guān)聯(lián)記錄的集合。 為了克服這個(gè)問(wèn)題,Django構(gòu)造了一個(gè)可以使用的適當(dāng)命名的"反向查找"函數(shù)。 該函數(shù)的名稱由下殼構(gòu)造,其中 ForeignKey
被聲明的模型名稱后面跟 _set
(即在 Book code>是
bookinstance_set()
)。
注意:此處我們使用 all()
獲取所有記錄(默認(rèn))。 雖然您可以使用 filter()
方法獲取代碼中的記錄子集,但是您無(wú)法在模板中直接執(zhí)行此操作,因?yàn)槟荒転楹瘮?shù)指定參數(shù)。
在這一點(diǎn)上,我們應(yīng)該創(chuàng)建顯示圖書(shū)列表和圖書(shū)詳細(xì)頁(yè)面所需的一切。 運(yùn)行服務(wù)器( python3 manage.py runserver
),然后打開(kāi)瀏覽器 http://127.0。 0.1:8000 / 。
警告:不要點(diǎn)擊任何作者或作者詳細(xì)信息鏈接 - 您將在挑戰(zhàn)中創(chuàng)建這些鏈接!
點(diǎn)擊所有圖書(shū)鏈接以顯示圖書(shū)列表。
; width:823px;">
然后點(diǎn)擊您的某本書(shū)的鏈接。 如果一切設(shè)置正確,您應(yīng)該看到類似以下屏幕截圖。
; width:926px;">
如果你只有幾個(gè)記錄,我們的書(shū)列表頁(yè)面看起來(lái)很好。 然而,當(dāng)你進(jìn)入幾十或幾百的記錄,頁(yè)面將逐漸加載(和有太多的內(nèi)容,以適當(dāng)瀏覽)。 此問(wèn)題的解決方案是在列表視圖中添加分頁(yè),減少每個(gè)頁(yè)面上顯示的項(xiàng)目數(shù)。
Django對(duì)分頁(yè)提供了極好的內(nèi)置支持。 更好的是,這是基于類的列表視圖,所以你不必做太多的啟用它!
打開(kāi) catalog / views.py ,然后添加以粗體顯示的 paginate_by
行。
class BookListView(generic.ListView): model = Book paginate_by = 10
使用此添加,只要您有超過(guò)10條記錄,視圖將開(kāi)始分頁(yè)發(fā)送到模板的數(shù)據(jù)。 使用GET參數(shù)訪問(wèn)不同的網(wǎng)頁(yè) - 要訪問(wèn)第2頁(yè),您需要使用網(wǎng)址: / catalog / books / ?page = 2
。
現(xiàn)在數(shù)據(jù)已分頁(yè),我們需要添加對(duì)模板的支持以滾動(dòng)瀏覽結(jié)果集。 因?yàn)槲覀兛赡芟朐谒辛斜硪晥D中執(zhí)行此操作,我們將以可添加到基本模板的方式執(zhí)行此操作。
打開(kāi) / locallibrary / catalog / templates / base_generic.html ,并在我們的內(nèi)容塊下面的下面的分頁(yè)塊中復(fù)制(下面粗體突出顯示)。 代碼首先檢查是否在當(dāng)前頁(yè)面上啟用了分頁(yè)。 如果是,則它適當(dāng)?shù)靥砑酉乱粋€(gè)和上一個(gè)鏈接(以及當(dāng)前頁(yè)碼)。
{% 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 如果在當(dāng)前頁(yè)面上使用分頁(yè),則將存在的對(duì)象。 它允許您獲取有關(guān)當(dāng)前頁(yè)面,上一頁(yè),有多少頁(yè)面等的所有信息。
我們使用 {{request.path}}
獲取用于創(chuàng)建分頁(yè)鏈接的當(dāng)前網(wǎng)頁(yè)網(wǎng)址。 這是有用的,因?yàn)樗?dú)立于我們分頁(yè)的對(duì)象。
而已!
下面的屏幕截圖顯示了分頁(yè)的樣子 - 如果您沒(méi)有在數(shù)據(jù)庫(kù)中輸入超過(guò)10個(gè)標(biāo)題,那么您可以通過(guò)降低 paginate_by
行中指定的數(shù)字更容易地測(cè)試它, strong> catalog / views.py 文件。 為了得到下面的結(jié)果,我們將它改為 paginate_by = 2
。
分頁(yè)鏈接顯示在底部,根據(jù)您所在的頁(yè)面顯示下一個(gè)/上一個(gè)鏈接。
; width:924px;">
本文中的挑戰(zhàn)是創(chuàng)建作者詳細(xì)信息和列出完成項(xiàng)目所需的視圖。 這些應(yīng)在以下網(wǎng)址提供:
catalog/authors/
?— The list of all authors.catalog/author/<id>
?—?The detail view for the specific author?with a primary key field named?<id>
URL映射器和視圖所需的代碼應(yīng)該與上面創(chuàng)建的 Book
列表和詳細(xì)視圖幾乎相同。 模板將是不同的,但會(huì)共享類似的行為。
注意:
<p><strong>Author:</strong> <a href="{% url 'author-detail' book.author.pk %}">{{ book.author }}</a></p>
完成后,您的網(wǎng)頁(yè)應(yīng)該像下面的屏幕截圖。
; width:825px;">
恭喜,我們的基本庫(kù)功能現(xiàn)已完成!
在本文中,我們學(xué)習(xí)了如何使用基于類的列表和詳細(xì)視圖,并使用它們來(lái)創(chuàng)建頁(yè)面來(lái)查看我們的書(shū)籍和作者。 一路上,我們學(xué)習(xí)了使用正則表達(dá)式的模式匹配,以及如何將數(shù)據(jù)從URL傳遞到視圖。 我們還學(xué)習(xí)了使用模板的更多技巧。 最后,我們展示了如何對(duì)列表視圖進(jìn)行分頁(yè),以便我們的列表是可管理的,即使我們有很多記錄。
在我們的下一篇文章中,我們將擴(kuò)展此庫(kù)以支持用戶帳戶,從而演示用戶身份驗(yàn)證,權(quán)限,會(huì)話和表單。
更多建議: