服務端編程(十)- Django -創建網站頁面

前言 ´・ᴗ・`

  • 上一節我們建立了主頁 這裏我們來創建一些別的網頁 比如關於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

  1. 模板編輯:
    創建: /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檢驗戰果
不出意外 你將收穫:
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
到這裏 基本上很多頁面都能搞定了
下一站 我們會聊聊 會話

這是軟菜雞的其他系列學習文章 希望能夠幫到你 ( •̀ ω •́ )✧

  • 想學習數據庫嘛? 不妨從MySQL入手
    MySQL專欄

  • python這麼火 想要深入學習python 玩一下簡單的應用嘛?可以看我專欄 還在持續更新中哦:
    python應用

  • 這是本服務端編程專欄
    手把手帶你學服務端

  • 謝謝大佬支持!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章