簡(jiǎn)書(shū)文章目錄生成腳本: 左側(cè)目錄
不要錯(cuò)過(guò),在簡(jiǎn)書(shū),你一定需要的
喜歡本文,請(qǐng)點(diǎn)個(gè)??,Thanks!
1. 創(chuàng)建網(wǎng)站框架
1.1 創(chuàng)建項(xiàng)目
用django-admin startproject命令創(chuàng)建新項(xiàng)目,并進(jìn)入該文件夾
django-admin startproject locallibrary
cd locallibrary
1.2 創(chuàng)建應(yīng)用(App)——catalog
python manage.py startapp catalog
1.3 項(xiàng)目設(shè)置文件配置
打開(kāi)項(xiàng)目設(shè)置文件 locallibrary/locallibrary/settings.py
1.3.1 注冊(cè)應(yīng)用
找到 INSTALLED_APPS 列表里的定義。 如下所示,在列表的最后添加新的一行
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'catalog.apps.CatalogConfig', # 注冊(cè)應(yīng)用
]
1.3.2 語(yǔ)言和時(shí)區(qū)設(shè)置
LANGUAGE_CODE = 'zh-hans'
TIME_ZONE = 'Asia/Shanghai'
1.4 網(wǎng)站路由URL設(shè)置
-
項(xiàng)目主URL
打開(kāi)locallibrary/locallibrary/urls.py
from django.conf.urls.static import static
from django.contrib import admin
from django.urls import path, include
from django.views.generic import RedirectView
from locallibrary import settings
urlpatterns = [
path('admin/', admin.site.urls),
path('catalog/', include('catalog.urls')), # 將帶有 catalog/ 的請(qǐng)求轉(zhuǎn)發(fā)到模塊 catalog.urls (使用相對(duì)路徑 URL /catalog/urls.py)
path('', RedirectView.as_view(url='/catalog/')), # 重定向,把網(wǎng)站的根URL(例:127.0.0.1:8000)重定向到該URL:127.0.0.1:8000/catalog/
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) # 啟用靜態(tài)文件的服務(wù),CSS, JavaScript, 和圖片等靜態(tài)文件
-
App路由
在catalog 文件夾下創(chuàng)建一個(gè)名為 urls.py 的文件,并添加以下文本(空的 urlpatterns)
from django.urls import path
from catalog import views
urlpatterns = [
]
1.5 測(cè)試網(wǎng)站框架
1.5.1 數(shù)據(jù)庫(kù)遷移
python manage.py makemigrations
python manage.py migrate
重要信息: 每次模型改變,都需要運(yùn)行以上命令,來(lái)影響需要存儲(chǔ)的數(shù)據(jù)結(jié)構(gòu)(包括添加和刪除整個(gè)模型和單個(gè)字段)。
1.5.2 運(yùn)行網(wǎng)站
python manage.py runserver 0.0.0.0:8000
- 瀏覽器打開(kāi)網(wǎng)址:localhost:8000
2. ## 設(shè)計(jì)LocalLibaray模型
2.1 模型入門(mén)
2.1.1 模型定義
- 模型通常在應(yīng)用程序的models.py文件中定義
-
可以包括
字段、方法和元數(shù)據(jù)
下面的代碼片段顯示了一個(gè)名為 的“典型”模型MyModelName:
from django.db import models
class MyModelName(models.Model):
"""A typical class defining a model, derived from the Model class."""
# Fields
my_field_name = models.CharField(max_length=20, help_text='Enter field documentation')
...
# Metadata
class Meta:
ordering = ['-my_field_name']
# Methods
def get_absolute_url(self):
"""Returns the url to access a particular instance of MyModelName."""
return reverse('model-detail-view', args=[str(self.id)])
def __str__(self):
"""String for representing the MyModelName object (in Admin site etc.)."""
return self.my_field_name
2.1.1.1 字段
- 一個(gè)模型可以有任意數(shù)量的任何類(lèi)型的字段
- 每個(gè)字段代表存儲(chǔ)在數(shù)據(jù)庫(kù)表中的一列數(shù)據(jù)
- 字段選項(xiàng)的完整列表
- 字段類(lèi)型的完整列表
2.1.1.2 元數(shù)據(jù)
聲明模型級(jí)元數(shù)據(jù)class Meta
class Meta:
ordering = ['-my_field_name']
2.1.1.3 方法
- 模型也可以有方法
-
常用方法
__str__(): 返回標(biāo)題或名稱字段, 用于站點(diǎn)管理 -
常用方法是
get_absolute_url(): 返回一個(gè) URL,用于在網(wǎng)站上顯示1個(gè)模型記錄
def get_absolute_url(self):
"""Returns the url to access a particular instance of the model."""
return reverse('model-detail-view', args=[str(self.id)])
注意:
- 使用 URL/myapplication/mymodelname/2來(lái)顯示模型的單個(gè)記錄(其中“2”id代表特定記錄),需要?jiǎng)?chuàng)建一個(gè) URL 映射器以將
響應(yīng)和id傳遞到“模型詳細(xì)信息視圖”(這將完成顯示記錄所需的工作)。- reverse()上面的函數(shù)能夠“反轉(zhuǎn)”您的 url 映射器(在上述情況下名為'model-detail-view')以創(chuàng)建正確格式的 URL。
- 要完成這項(xiàng)工作,需要繼續(xù)完善編寫(xiě) URL 映射、視圖和模板**
2.1.3 模型管理
- 一旦定義了模型類(lèi),可以使用它們來(lái)創(chuàng)建、更新或刪除記錄,以及運(yùn)行查詢以獲取所有記錄或記錄的特定子集。
- 在定義視圖教程中詳細(xì)展示如何做到這一點(diǎn)
- 創(chuàng)建和修改記錄
# Create a new record using the model's constructor.
record = MyModelName(my_field_name="Instance #1")
# Save the object into the database.
record.save()
使用點(diǎn)語(yǔ)法訪問(wèn)此新記錄中的字段,并更改值, 然后調(diào)用save()將修改后的值存儲(chǔ)到數(shù)據(jù)庫(kù)中
# Access model field values using Python attributes.
print(record.id) # should return 1 for the first record.
print(record.my_field_name) # should print 'Instance #1'
# Change record by modifying the fields, then calling save().
record.my_field_name = "New Instance Name"
record.save()
- 搜索記錄
使用模型的objects屬性(由基類(lèi)提供)搜索符合特定條件的記錄
all_books = Book.objects.all()
Django 的filter()方法允許根據(jù)特定條件過(guò)濾返回QuerySet以匹配指定的文本或數(shù)字字段。例如,要過(guò)濾標(biāo)題中包含“wild”的書(shū)籍,然后對(duì)其進(jìn)行計(jì)數(shù)
wild_books = Book.objects.filter(title__contains='wild')
number_wild_books = wild_books.count()
2.2 定義 LocalLibrary 模型
該圖還顯示了模型之間的關(guān)系,包括它們的多重性
多重性是圖表上的數(shù)字,顯示關(guān)系中可能存在的每個(gè)模型的數(shù)量(最大值和最小值)
如,框之間的連接線顯示 Book 和 Genre 相關(guān)。靠近 Genre 模型的數(shù)字表明一本書(shū)必須有一個(gè)或多個(gè) Genres(任意數(shù)量),而 Book 模型旁邊該行另一端的數(shù)字表明一個(gè) Genre 可以有零個(gè)或多個(gè)相關(guān)聯(lián)圖書(shū)

2.2.1 Genre(體裁)模型
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
2.2.2 Book模型
from django.urls import reverse # Used to generate URLs by reversing the URL patterns
class Book(models.Model):
"""Model representing a book (but not a specific copy of a book)."""
title = models.CharField(max_length=200)
# 使用外鍵,因?yàn)闀?shū)只能有一個(gè)作者,但作者可以有多本書(shū)
# 作者作為字符串而不是對(duì)象編寫(xiě),因?yàn)樗形丛谖募新暶? author = models.ForeignKey('Author', on_delete=models.SET_NULL, null=True)
# summary文本可能很長(zhǎng),使用長(zhǎng)文本類(lèi)型
summary = models.TextField(max_length=1000, help_text='Enter a brief description of the book')
# 將標(biāo)簽顯式設(shè)置為“ISBN”(否則默認(rèn)為“Isbn”)
# 設(shè)置參數(shù) unique 為 true以確保所有書(shū)籍都有唯一的 ISBN(唯一參數(shù)使字段值在表中全局唯一)
isbn = models.CharField('ISBN', max_length=13, unique=True,
help_text='13 Character <a >ISBN number</a>')
# 使用ManyToManyField是因?yàn)轶w裁可以包含許多書(shū)籍。書(shū)籍可以涵蓋多種體裁.
# 體裁類(lèi)已經(jīng)定義,所以可以指定上面的對(duì)象.
genre = models.ManyToManyField(Genre, help_text='Select a genre 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', args=[str(self.id)])
get_absolute_url()返回一個(gè) URL,
該 URL 可用于訪問(wèn)此模型的詳細(xì)記錄
因此,必須定義一個(gè)具有 name 的 URL 映射book-detail,并定義關(guān)聯(lián)的視圖和模板)
2.2.3 BookInstance(圖書(shū)實(shí)例)模型
import uuid # 要求圖書(shū)實(shí)例具有唯一性
class BookInstance(models.Model):
"""表示一本書(shū)的特定副本(即可從圖書(shū)館借閱的副本)的模型."""
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.CharField(max_length=200)
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})'
UUIDField用于id字段將其設(shè)置primary_key為此模型的。這種類(lèi)型的字段為每個(gè)實(shí)例分配一個(gè)全局唯一的值。
DateField用于due_back日期(預(yù)計(jì)圖書(shū)在借出或維護(hù)后可用的日期)。該值可以是blank或null(當(dāng)圖書(shū)可用時(shí)需要)
Class Meta當(dāng)在查詢中返回記錄時(shí),模型元數(shù)據(jù) ( ) 使用此字段對(duì)記錄進(jìn)行排序
status是CharField定義選擇/選擇列表的 。定義一個(gè)包含鍵值對(duì)元組的元組,并將其傳遞給choices 參數(shù)鍵/值對(duì)中的值是用戶可以選擇的顯示值,而鍵是選擇該選項(xiàng)時(shí)實(shí)際保存的值
設(shè)置一個(gè)默認(rèn)值“m”(維護(hù)),因?yàn)樵跁?shū)上架之前,書(shū)最初會(huì)被創(chuàng)建為不可用
該方法使用其唯一 id 和相關(guān)聯(lián)的標(biāo)題的組合來(lái)str()表示BookInstance對(duì)象Book
從Python 3.6開(kāi)始,可以使用字符串插值語(yǔ)法(也稱為f-字符串)f'{self.id} ({self.book.title})'
2.2.4 Author(作者)模型
class Author(models.Model):
"""作者模型"""
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:
# 以last name,firstname順序返回名稱
ordering = ['last_name', 'first_name']
def get_absolute_url(self):
"""反轉(zhuǎn)author-detail的URL 映射以獲取用于顯示單個(gè)作者的 URL"""
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}'
3. 管理站點(diǎn)
3.1 注冊(cè)模型
在目錄應(yīng)用程序(/locallibrary/catalog/admin.py)中打開(kāi) admin.py
導(dǎo)入模型,調(diào)用 admin.site.register 注冊(cè)模型
from .models import Author, Genre, Book, BookInstance, Language
admin.site.register(Book)
admin.site.register(Author)
admin.site.register(Genre)
admin.site.register(BookInstance)
admin.site.register(Language)
3.2 創(chuàng)建超級(jí)用戶
- python manage.py createsuperuser
- python manage.py makemigrations
- python manage.py migrate
3.3 登錄和使用網(wǎng)站
python manage.py runserver 0.0.0.0:8000
登錄網(wǎng)站,打開(kāi)/admin(e.g. localhost:8000/admin)
添加一些體裁、作者、語(yǔ)言、圖書(shū)、圖書(shū)實(shí)例
3.4 高級(jí)配置
視圖列表- 添加每個(gè)記錄顯示的其他字段/信息
- 添加過(guò)濾器以根據(jù)日期或某些其他選擇值(例如圖書(shū)借閱狀態(tài))選擇列出哪些記錄
- 在列表視圖中的操作菜單中添加其他選項(xiàng),并選擇此菜單在表單上顯示的位置
詳細(xì)視圖- 選擇要顯示(或排除)的字段,以及其順序,分組,是否可編輯,使用的小部件,方向等
- 將相關(guān)字段添加到記錄以允許內(nèi)聯(lián)編輯(例如:添加在創(chuàng)建作者記錄時(shí)添加和編輯圖書(shū)記錄的功能)
3.4.1 注冊(cè) 一個(gè) ModelAdmin 類(lèi)
定義 ModelAdmin類(lèi)(描述布局),并將其注冊(cè)到模型中,用于管理界面改變模型的展示方式
打開(kāi) admin.py 在目錄應(yīng)用程序(/locallibrary/catalog/admin.py)
Author 模型
# 注釋原始注冊(cè)(前綴為#)
# admin.site.register(Author)
添加一個(gè) AuthorAdmin 和注冊(cè)
# Define the admin class
class AuthorAdmin(admin.ModelAdmin):
pass
# Register the admin class with the associated model
admin.site.register(Author, AuthorAdmin)
為Book 和 BookInstance 類(lèi)添加 ModelAdmin 類(lèi)
注釋原始注冊(cè)
#admin.site.register(Book)
#admin.site.register(BookInstance)
使用@register 裝飾器來(lái)注冊(cè)模型(與admin.site.register() 語(yǔ)法作用一樣)
# Register the Admin classes for Book using the decorator
@admin.register(Book)
class BookAdmin(admin.ModelAdmin):
pass
# Register the Admin classes for BookInstance using the decorator
@admin.register(BookInstance)
class BookInstanceAdmin(admin.ModelAdmin):
pass
可以看到現(xiàn)在的 ModelAdmin類(lèi)都是空的 (“pass”),所以管理操作并不會(huì)改變
對(duì)這些類(lèi)進(jìn)行擴(kuò)展,以定義針對(duì)模型的管理行為
3.4.2 配置列表視圖list_display
使用list_display 向視圖添加其他字段
- Author模型
@admin.register(Author)
class AuthorAdmin(admin.ModelAdmin):
list_display = ('last_name', 'first_name', 'date_of_birth', 'date_of_death')
- Book模型
@admin.register(Book)
class BookAdmin(admin.ModelAdmin):
# display_genre:Book模型中定義的方法
list_display = ('title', 'author', 'display_genre')
- BookInstance模型
@admin.register(BookInstance)
class BookAdmin(admin.ModelAdmin):
# display_genre:Book模型中定義的方法
list_display = ('id', 'book', 'due_back', 'status')
3.4.3 添加列表過(guò)濾器list_filter
@admin.register(BookInstance)
class BookAdmin(admin.ModelAdmin):
# display_genre:Book模型中定義的方法
list_display = ('id', 'book', 'due_back', 'status')
list_filter = ('status', 'due_back')
3.5 整理視圖布局
3.5.1 控制哪些字段被顯示和詳細(xì)視圖布局fields
- Author模型
@admin.register(Author)
class AuthorAdmin(admin.ModelAdmin):
list_display = ('last_name', 'first_name', 'date_of_birth', 'date_of_death')
fields = ['first_name', 'last_name', ('date_of_birth', 'date_of_death')]**
在fields 屬性列表只是要顯示在表格上字段
字段默認(rèn)情況下垂直顯示
將它們分組在元組中(如上述“日期”字段中所示),則會(huì)水平顯示
還可以使用exclude屬性來(lái)聲明要從表單中排除的屬性列表(將顯示模型中的所有其他屬性)
3.5.2 詳細(xì)視圖字段分組
@admin.register(BookInstance)
class BookInstanceAdmin(admin.ModelAdmin):
list_filter = ('status', 'due_back')
fieldsets = (
(None, {
'fields': ('book','imprint', 'id')
}),
('Availability', {
'fields': ('status', 'due_back')
}),
)
每個(gè)部分都有自己的標(biāo)題(或者None如果你不想要一個(gè)標(biāo)題)和字典中的一個(gè)相關(guān)的元組 - 描述
3.5.3 關(guān)聯(lián)記錄的內(nèi)聯(lián)編輯
有時(shí),可以同時(shí)添加關(guān)聯(lián)記錄是有意義的
例如,將書(shū)籍信息和有關(guān)詳細(xì)信息頁(yè)面上的特定副本的信息同時(shí)顯示可能是有意義的
通過(guò)聲明 inlines, 類(lèi)型 TabularInline (水平布局 ) or StackedInline (垂直布局 ,默認(rèn)布局)
class BooksInstanceInline(admin.TabularInline):
model = BookInstance
@admin.register(Book)
class BookAdmin(admin.ModelAdmin):
list_display = ('title', 'author', 'display_genre')
inlines = [BooksInstanceInline]
4. 構(gòu)建主頁(yè)
創(chuàng)建一個(gè)url映射器,視圖和模板來(lái)顯示這些頁(yè)面
URL映射: 根據(jù)支持的URL(以及任何編碼在URL里的信息)跳轉(zhuǎn)到相應(yīng)的View功能函數(shù)
View 函數(shù)從模型中獲取請(qǐng)求的數(shù)據(jù),創(chuàng)建一個(gè)顯示數(shù)據(jù)的HTML頁(yè)面,并將其返回給用戶在瀏覽器查看
Templates在View視圖中進(jìn)行數(shù)據(jù)渲染的時(shí)候使用
處理HTTP請(qǐng)求/響應(yīng)時(shí)需要實(shí)現(xiàn)的數(shù)據(jù)和事件的主要流程
4.1 定義資源URL
5個(gè)頁(yè)面
catalog/ — 主頁(yè)
catalog/books/ — 書(shū)單頁(yè)
catalog/authors/ — 作者頁(yè)
catalog/book/<id> — 主鍵字段 ID的具體書(shū) —詳細(xì)視圖。如/catalog/book/3,第三本書(shū)。
catalog/author/<id> — 主鍵字段 ID的具體作者—詳細(xì)視圖。如 /catalog/author/11,第11個(gè)作者
4.2 創(chuàng)建索引頁(yè)
創(chuàng)建的第一個(gè)頁(yè)面是索引頁(yè)(catalog/)
這會(huì)顯示一些靜態(tài)HTML,以及數(shù)據(jù)庫(kù)中不同記錄的一些計(jì)算的“計(jì)數(shù)“
為了使其工作,必須分別創(chuàng)建一個(gè)URL映射,視圖和模板
4.2.1 URL映射
在創(chuàng)建的
基礎(chǔ)網(wǎng)站上,更新 /locallibrary/urls.py 文件
以確保接收到以**catalog/**開(kāi)頭的URL時(shí),URLConf模塊中的catalog.urls會(huì)處理剩余的字符串
打開(kāi)catalog/urls.py
urlpatterns = [
path('', views.index, name='index'), # 檢測(cè)到URL模式'',(views.index——在view.py中函數(shù)命名index() )將被調(diào)用
]
name參數(shù),此唯一標(biāo)識(shí)指定 URL 映射
可以使用 "reverse" 映射—去動(dòng)態(tài)創(chuàng)建指定映射設(shè)計(jì)處理的資源的一個(gè)URL
例如,可以通過(guò)在模板中創(chuàng)建以下鏈接到主頁(yè)
<a href="{% url 'index' %}">Home</a>
# 可以硬編碼上面的鏈接(如:<a href="/catalog/">Home</a>)
# 但是如果改變了主頁(yè)的模式,模版將不再正確鏈接,使用反向網(wǎng)址映射會(huì)更靈活和強(qiáng)大
4.2.2 View (基于函數(shù))
視圖是處理 HTTP 請(qǐng)求,從數(shù)據(jù)庫(kù)中獲取所需數(shù)據(jù),使用 HTML 模板在 HTML 頁(yè)面中呈現(xiàn)數(shù)據(jù),然后在 HTTP 響應(yīng)中返回生成的 HTML 以向用戶顯示頁(yè)面的功能。
索引視圖遵循這個(gè)模型——它獲取數(shù)據(jù)庫(kù)中擁有的Book、BookInstance、 可用BookInstance 和Author記錄數(shù)量的 信息,并將該信息傳遞給模板進(jìn)行顯示。
打開(kāi)catalog/views.py
from .models import Book, Author, BookInstance, Genre # 導(dǎo)入模型類(lèi)
def index(request):
"""View function for home page of site."""
# Generate counts of some of the main objects
# 使用模型類(lèi)上的objects.all()屬性獲取記錄數(shù)`objects.all`
num_books = Book.objects.all().count()
num_instances = BookInstance.objects.all().count()
# Available books (status = 'a')
# 獲取BookInstance模型中status字段中值為“a”(可用)的對(duì)象列表`objects.filter`
num_instances_available = BookInstance.objects.filter(status__exact='a').count()
# The 'all()' is implied by default.
num_authors = Author.objects.count()
# context變量,是一個(gè) Python 字典,包含要插入占位符的數(shù)據(jù)
context = {
'num_books': num_books,
'num_instances': num_instances,
'num_instances_available': num_instances_available,
'num_authors': num_authors,
}
# Render the HTML template index.html with the data in the context variable
# 調(diào)用該render()函數(shù)來(lái)創(chuàng)建一個(gè) HTML 頁(yè)面并將該頁(yè)面作為響應(yīng)返回
return render(request, 'index.html', context=context)
4.2.3 模板
模板是定義文件(例如 HTML 頁(yè)面)的結(jié)構(gòu)或布局的文本文件,使用占位符來(lái)表示實(shí)際內(nèi)容
將在使用startapp創(chuàng)建的 Django 應(yīng)用程序目錄下的templates子目錄中查找模板
在上述索引視圖中,該render()函數(shù)將在/locallibrary/catalog/templates/ 中找到文件index.html,如果該文件不存在,則會(huì)引發(fā)錯(cuò)誤
Django 會(huì)在許多地方尋找模板,默認(rèn)情況下會(huì)在應(yīng)用程序(App)中進(jìn)行搜索
關(guān)于 Django 如何查找模板以及它支持哪些模板格式的信息, 可查看Django 文檔的模板部分
4.2.3.1 擴(kuò)展模板
索引模板需要
頭部和正文的標(biāo)準(zhǔn) HTML 標(biāo)記,以及鏈接到站點(diǎn)其他頁(yè)面(尚未創(chuàng)建)的導(dǎo)航部分,以及顯示介紹性文本和書(shū)籍?dāng)?shù)據(jù)的部分
網(wǎng)站的每個(gè)頁(yè)面中的大部分 HTML 和導(dǎo)航結(jié)構(gòu)都是相同的。可以使用 Django 模板語(yǔ)言聲明一個(gè)基本模板,而不是在每個(gè)頁(yè)面上復(fù)制樣板代碼,然后擴(kuò)展它以僅替換每個(gè)特定頁(yè)面不同的位
- base_generic.html
base_generic.html文件的示例基本模板,包含標(biāo)題、側(cè)邊欄和用命名block和endblock模板標(biāo)簽標(biāo)記的主要內(nèi)容的部分
模板標(biāo)簽可以在模板中用于循環(huán)列表、基于變量值執(zhí)行條件操作等的函數(shù)
除了模板標(biāo)簽之外,模板語(yǔ)法還允許引用從視圖傳遞到模板的變量,并使用模板過(guò)濾器來(lái)格式化變量(例如,將字符串轉(zhuǎn)換為小寫(xiě))
<!DOCTYPE html>
<html lang="en">
<head>
{% block title %}<title>Local Library</title>{% endblock %}
</head>
<body>
{% block sidebar %}<!-- insert default navigation text for every page -->{% endblock %}
{% block content %}<!-- default content text (typically empty) -->{% endblock %}
</body>
</html>
- 擴(kuò)展模板
- 在為特定視圖定義模板時(shí),首先使用extends模板標(biāo)簽指定基本模板
- 然后聲明模板中想要替換的基本模板中使用block/endblock部分(如果有的話)
{% extends "base_generic.html" %}
{% block content %}
<h1>Local Library Home</h1>
<p>Welcome to LocalLibrary, a website developed by <em>Mozilla Developer Network</em>!</p>
{% endblock %}
4.3 LocalLibrary 主頁(yè)構(gòu)建
4.3.1 基礎(chǔ)模板base_generic.html
定義塊title,sidebar和content。有一個(gè)默認(rèn)標(biāo)題和一個(gè)默認(rèn)側(cè)邊欄,其中包含指向所有書(shū)籍和作者列表的鏈接,兩者都包含在塊中,以便將來(lái)輕松更改。
還引入了兩個(gè)額外的模板標(biāo)簽:url和load static
模板包括來(lái)自Bootstrap的 CSS改進(jìn) HTML 頁(yè)面的布局和呈現(xiàn)
使用 Bootstrap(或其他客戶端 Web 框架)是一種快速創(chuàng)建有吸引力的頁(yè)面的方法,該頁(yè)面可以在不同的屏幕尺寸上良好顯示
基本模板還引用了一個(gè)提供額外樣式的本地 css 文件 ( styles.css )
在/locallibrary/catalog/static/css/ 中創(chuàng)建一個(gè)styles.css文件 并將以下代碼粘貼到該文件中:
styles.css
.sidebar-nav {
margin-top: 20px;
padding: 0;
list-style: none;
}
base_generic.html
<!DOCTYPE html>
<html lang="en">
<head>
{% block title %}<title>Local Library</title>{% endblock %}
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
<!-- Add additional CSS in static file -->
{% load static %}
<link rel="stylesheet" href="{% static 'css/styles.css' %}">
</head>
<body>
<div class="container-fluid">
<div class="row">
<div class="col-sm-2">
{% block sidebar %}
<ul class="sidebar-nav">
<li><a href="{% url 'index' %}">Home</a></li>
<li><a href="">All books</a></li>
<li><a href="">All authors</a></li>
</ul>
{% endblock %}
</div>
<div class="col-sm-10 ">{% block content %}{% endblock %}</div>
</div>
</div>
</body>
</html>
4.3.2 索引模板
在 /locallibrary/catalog/templates/ 中創(chuàng)建一個(gè)新的 HTML 文件
index.html并將以下代碼粘貼到文件中。
在第一行擴(kuò)展基本模板,然后替換了模板的默認(rèn)塊content
index.html
{% extends "base_generic.html" %}
{% block content %}
<h1>Local Library Home</h1>
<p>Welcome to LocalLibrary, a website developed by <em>Mozilla Developer Network</em>!</p>
<h2>Dynamic content</h2>
<p>The library has the following record counts:</p>
<ul>
<li><strong>Books:</strong> {{ num_books }}</li>
<li><strong>Copies:</strong> {{ num_instances }}</li>
<li><strong>Copies available:</strong> {{ num_instances_available }}</li>
<li><strong>Authors:</strong> {{ num_authors }}</li>
</ul>
{% endblock %}
在動(dòng)態(tài)內(nèi)容部分,為要包含的視圖中的信息聲明占位符(模板變量)。變量用雙括號(hào)(把手)括起來(lái)。
輕松識(shí)別模板變量和模板標(biāo)簽(函數(shù))——變量用雙大括號(hào) ( {{ num_books }}) 括起來(lái),標(biāo)簽用帶百分號(hào) ( {% extends "base_generic.html" %}) 的單大括號(hào)括起來(lái)
變量是用在視圖函數(shù)中傳遞給字典的鍵命名的(參見(jiàn)下面的示例), 呈現(xiàn)模板時(shí),變量將替換為其關(guān)聯(lián)的值
context = {
'num_books': num_books,
'num_instances': num_instances,
'num_instances_available': num_instances_available,
'num_authors': num_authors,
}
return render(request, 'index.html', context=context) # context:字典,傳遞給網(wǎng)頁(yè)
4.3.3 在模板中引用靜態(tài)文件
- 項(xiàng)目可能會(huì)使用靜態(tài)資源,包括 JavaScript、CSS 和圖像
- 由于這些文件的位置可能未知(或可能更改),Django 允許在模板中指定相對(duì)于
STATIC_URL全局設(shè)置的位置- 默認(rèn)骨架網(wǎng)站設(shè)置 STATIC_URL 的值為“ /static/”,但可以選擇將這些內(nèi)容托管在內(nèi)容交付網(wǎng)絡(luò)或其他地方
在模板中,首先調(diào)用load 指定“static”的模板標(biāo)記來(lái)添加模板庫(kù)
然后,可以使用static模板標(biāo)記并指定所需文件的相對(duì) URL
<!-- Add additional CSS in static file -->
{% load static %}
<link rel="stylesheet" href="{% static 'css/styles.css' %}">
可以以類(lèi)似的方式將圖像添加到頁(yè)面中
{% load static %}
<img src="{% static 'catalog/images/local_library_model_uml.png' %}" alt="UML diagram" style="width:555px;height:540px;">
上面的示例指定了文件所在的位置,但 Django 默認(rèn)不提供
通過(guò)修改全局 URL 映射器 (/locallibrary/locallibrary/urls.py)將Web 服務(wù)器配置為提供文件服務(wù),但仍需要在生產(chǎn)中啟用文件服務(wù)(詳見(jiàn)后文)
有關(guān)使用靜態(tài)文件的更多信息,請(qǐng)參閱 Django 文檔中管理靜態(tài)文件
4.3.4 鏈接到 URL
上面的基礎(chǔ)模板引入了
url模板標(biāo)簽
此標(biāo)記接受path()在urls.py 中調(diào)用的函數(shù)的名稱以及關(guān)聯(lián)視圖將從該函數(shù)接收的任何參數(shù)的值,并返回可用于鏈接到資源的 URL
<li><a href="{% url 'index' %}">Home</a></li>
4.3.5 配置在哪里可以找到模板
Django 搜索模板的位置在
settings.py文件中的TEMPLATES對(duì)象中指定。默認(rèn)settings.py如下:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
設(shè)置 'APP_DIRS': True是最重要的,因?yàn)樗嬖V Django 在項(xiàng)目中每個(gè)應(yīng)用程序的子目錄中搜索模板,命名為“模板”
可以指定 Django 使用的特定位置來(lái)搜索目錄'DIRS': [](但這還不是必需的)
有關(guān) Django 如何查找模板以及它支持哪些模板格式的更多信息Django 文檔的模板部分
5. 通用列表和詳細(xì)信息視圖
5.1 書(shū)本清單頁(yè)面
5.1.1 URL 映射
- 打開(kāi)
/catalog/urls.py- 調(diào)用視圖函數(shù)
views.BookListView.as_view()和一個(gè)對(duì)應(yīng)這個(gè)特定映射的名稱
urlpatterns = [
path('', views.index, name='index'),
path('books/', views.BookListView.as_view(), name='books'),
]
視圖將以類(lèi)別來(lái)實(shí)現(xiàn)
對(duì)于基于Django類(lèi)的視圖,通過(guò)調(diào)用'類(lèi)方法as_view()',來(lái)訪問(wèn)適當(dāng)?shù)囊晥D函數(shù)。這樣做可以創(chuàng)建類(lèi)的實(shí)例,并確保為傳入的 HTTP 請(qǐng)求調(diào)用正確的處理程序方法。
5.1.2 視圖 (基于類(lèi))
- 可以很容易地,將
書(shū)本列表視圖編寫(xiě)為常規(guī)函數(shù)(類(lèi)似于索引視圖),它將查詢數(shù)據(jù)庫(kù)中的所有書(shū)本,然后調(diào)用render(),將列表傳遞給指定的模板- 然而,此處將使用
基于類(lèi)的通用列表視圖(ListView) - 一個(gè)繼承自現(xiàn)有視圖的類(lèi)- 因?yàn)橥ㄓ靡晥D,已經(jīng)實(shí)現(xiàn)了需要的大部分功能,將能夠創(chuàng)建更強(qiáng)大的列表視圖,具有代碼更少,重復(fù)次數(shù)更少,最終維護(hù)更少的優(yōu)點(diǎn)
打開(kāi)
catalog/views.py, 復(fù)制下面的代碼:
from django.views import generic
class BookListView(generic.ListView):
model = Book
- **
通用視圖將查詢數(shù)據(jù)庫(kù),以獲取指定模型(Book)的所有記錄,然后呈現(xiàn)位于/locallibrary/catalog/templates/catalog/book_list.html 的模板(將在下面創(chuàng)建)- 在模板中,可以使用名為
object_list或book_list的模板變量(即通常為“the_model_name_list”),以訪問(wèn)書(shū)本列表
注意: 模板位置路徑不是印刷錯(cuò)誤 - 通用視圖在應(yīng)用程序的/application_name/templates/目錄中(/catalog/templates/),查找模板/application_name/the_model_name_list.html(在本例中為catalog/book_list.html
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
5.1.2.1 覆蓋基于類(lèi)的視圖中的方法
- 以覆蓋
get_queryset()方法,來(lái)更改返回的記錄列表。這比僅僅設(shè)置queryset屬性更靈活
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(),以將其他context 變量傳遞給模板(例如,默認(rèn)情況下傳遞書(shū)本列表)- 下面代碼,顯示了如何將一個(gè)名為
some_data的變量添加到上下文中(然后它將作為一個(gè)模板變量,而被提供)
class BookListView(generic.ListView):
model = Book
def get_context_data(self, **kwargs):
# Call the base implementation first to get the context
context = super(BookListView, self).get_context_data(**kwargs)
# Create any data and add it to the context
context['some_data'] = 'This is just some data'
return context
注意: 查看內(nèi)置的基于類(lèi)的通用視圖(Django文檔),了解更多可以執(zhí)行的操作示例
5.1.3 創(chuàng)建列表視圖模板
- 創(chuàng)建 HTML 文件
/locallibrary/catalog/templates/catalog/book_list.html- 視圖默認(rèn)將
context (書(shū)本列表)作為object_list和book_list的別名傳遞;任何一個(gè)都會(huì)奏效
{% 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 %}
5.1.3.1 條件執(zhí)行
使用
if、else、 和endif模板標(biāo)簽來(lái)檢查 是否book_list已定義且不為空
如果book_list為空,則該else子句顯示文本,說(shuō)明沒(méi)有要列出的書(shū)籍
如果book_list不為空,則遍歷書(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 %})測(cè)試其他條件。有關(guān)條件運(yùn)算符的更多信息,請(qǐng)參閱:如果, ifequal/ifnotequal, 和 如果改變 在 內(nèi)置模板標(biāo)簽和過(guò)濾器
5.1.3.2 For 循環(huán)
{% for book in book_list %}
<li> <!-- code here get information from each book item --> </li>
{% endfor %}
5.1.3.3 訪問(wèn)變量
循環(huán)內(nèi)的代碼為每本書(shū)創(chuàng)建一個(gè)列表項(xiàng),顯示標(biāo)題(作為指向尚未創(chuàng)建的詳細(xì)信息視圖的鏈接)和作者
<a href="{{ book.get_absolute_url }}">{{ book.title }}</a> ({{book.author}})
**使用“點(diǎn)符號(hào)”訪問(wèn)相關(guān)書(shū)籍記錄的字段,其中項(xiàng)目后面的文本是字段名稱(如模型中定義的)。book.titlebook.authorbook
5.1.3.4 更新基本模板
打開(kāi)基本模板 (
/locallibrary/catalog/templates/ base_generic.html) 并將{% url 'books' %}插入到All books的 URL 鏈接中
5.2 圖書(shū)詳情頁(yè)面
5.2.1 網(wǎng)址映射
打開(kāi)
/catalog/urls.py并添加名為“ book-detail ”的路徑
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'),
]
5.2.1.1 高級(jí)路徑匹配/正則表達(dá)式入門(mén)
5.2.1.2 在 URL 映射中傳遞其他選項(xiàng)
5.2.2 視圖 (基于類(lèi))
5.2.3 創(chuàng)建詳情視圖模板
5.3 分頁(yè)
5.3.1 視圖(基于類(lèi))
打開(kāi)
catalog/views.py,然后添加paginate_by
class BookListView(generic.ListView):
model = Book
paginate_by = 10
通過(guò)添加這行,只要超過(guò)10條記錄,視圖就會(huì)開(kāi)始對(duì)它發(fā)送到模板的數(shù)據(jù),進(jìn)行分頁(yè)
使用 GET 參數(shù)訪問(wèn)不同的頁(yè)面 - 如要訪問(wèn)第2頁(yè),將使用URL:/catalog/books/?page=2
5.3.2 模板
現(xiàn)在數(shù)據(jù)已經(jīng)分頁(yè),需要添加對(duì)模板的支持,以滾動(dòng)結(jié)果集合
因?yàn)樾枰谒辛斜硪晥D中都執(zhí)行此操作,所以將以基本模板的方式執(zhí)行此操作
打開(kāi)/locallibrary/catalog/templates/base_generic.html,并復(fù)制貼士以下內(nèi)容區(qū)塊下面的分頁(yè)區(qū)塊(以粗體突出顯示)
代碼首先檢查當(dāng)前頁(yè)面上,是否啟用了分頁(yè)。如果是,則它會(huì)根據(jù)需要,添加下一個(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是一個(gè) Paginator 對(duì)象,用于獲取有關(guān)當(dāng)前頁(yè)面,之前頁(yè)面,之后頁(yè)面,頁(yè)面總數(shù)等信息。
使用{{ request.path }},來(lái)獲取用于創(chuàng)建分頁(yè)鏈接的當(dāng)前頁(yè)面URL, 其獨(dú)立于正在分頁(yè)的對(duì)象。
6. 會(huì)話框架
6.1 會(huì)話是什么?
- 會(huì)話是Django(以及大多數(shù)Internet)用于跟蹤站點(diǎn)和特定瀏覽器之間“狀態(tài)”的機(jī)制。會(huì)話允許您為每個(gè)瀏覽器存儲(chǔ)任意數(shù)據(jù),并在瀏覽器連接時(shí),將該數(shù)據(jù)提供給站點(diǎn)。然后,通過(guò)“密鑰”引用與會(huì)話相關(guān)聯(lián)的各個(gè)數(shù)據(jù)項(xiàng),“密鑰”用于存儲(chǔ)和檢索數(shù)據(jù)。
- Django使用包含特殊會(huì)話ID的cookie,來(lái)識(shí)別每個(gè)瀏覽器,及其與該站點(diǎn)的關(guān)聯(lián)會(huì)話。默認(rèn)情況下,實(shí)際會(huì)話數(shù)據(jù)存儲(chǔ)在站點(diǎn)數(shù)據(jù)庫(kù)中(這比將數(shù)據(jù)存儲(chǔ)在cookie中更安全,因?yàn)樗鼈兏菀资艿綈阂庥脩舻墓簦?。您可以將Django配置為,將會(huì)話數(shù)據(jù)存儲(chǔ)在其他位置(緩存,文件,“安全”cookie),但默認(rèn)位置是一個(gè)良好且相對(duì)安全的選項(xiàng)
6.2 啟用會(huì)話
創(chuàng)建骨架網(wǎng)站時(shí),會(huì)自動(dòng)啟用會(huì)話
- 在項(xiàng)目配置文件(
locallibrary / locallibrary / settings.py)的INSTALLED_APPS和MIDDLEWARE部分中設(shè)置,如下所示:
INSTALLED_APPS = [
...
'django.contrib.sessions',
....
MIDDLEWARE = [
...
'django.contrib.sessions.middleware.SessionMiddleware',
....
6.3 使用會(huì)話
可以在如何使用會(huì)話(Django文檔)中找到完整的API
6.4 保存會(huì)話數(shù)據(jù)
默認(rèn)情況下,Django僅保存到會(huì)話數(shù)據(jù)庫(kù),并在會(huì)話被修改(分配)或刪除時(shí),將會(huì)話cookie發(fā)送到客戶端。
如果您正在更新會(huì)話數(shù)據(jù)中的某些信息,那么Django將無(wú)法識(shí)別您已對(duì)會(huì)話進(jìn)行了更改并保存了數(shù)據(jù).。在這種情況下,您需要將會(huì)話明確標(biāo)記為已修改。
# Set session as modified to force data updates/cookie to be saved.
request.session.modified = True
6.5 簡(jiǎn)單的例子 - 獲取訪問(wèn)次數(shù)
作為一個(gè)簡(jiǎn)單的實(shí)際例子,將更新圖書(shū)館,告訴當(dāng)前用戶訪問(wèn) LocalLibrary 主頁(yè)的次數(shù)
View修改
打開(kāi)
/locallibrary/catalog/views.py,進(jìn)行如下修改
def index(request):
...
num_authors=Author.objects.count() # The 'all()' is implied by default.
# Number of visits to this view, as counted in the session variable.
num_visits=request.session.get('num_visits', 0)
request.session['num_visits'] = num_visits+1
# Render the HTML template index.html with the data in the context variable.
return render(
request,
'index.html',
context={'num_books':num_books,'num_instances':num_instances,'num_instances_available':num_instances_available,'num_authors':num_authors,
'num_visits':num_visits}, # num_visits appended
)
首先得到
num_visits會(huì)話密鑰的值,如果之前沒(méi)有設(shè)置,則將值設(shè)置為0。
每次收到請(qǐng)求時(shí),該值都會(huì)遞增,并將其存回會(huì)話中(下次用戶訪問(wèn)該頁(yè)面時(shí))。
然后將num_visits變量,傳遞給模板中的context變量
參閱如何使用會(huì)話
index.html修改
將下面的代碼添加到主HTML模板(/locallibrary/catalog/templates/index.html)的 “動(dòng)態(tài)內(nèi)容” 部分底部,以顯示
context變量:
<h2>Dynamic content</h2>
<p>The library has the following record counts:</p>
<ul>
<li><strong>Books:</strong> {{ num_books }}</li>
<li><strong>Copies:</strong> {{ num_instances }}</li>
<li><strong>Copies available:</strong> {{ num_instances_available }}</li>
<li><strong>Authors:</strong> {{ num_authors }}</li>
</ul>
<p>You have visited this page {{ num_visits }}{% if num_visits == 1 %} time{% else %} times{% endif %}.</p>
7. 用戶授權(quán)與許可
7.1 啟用身份驗(yàn)證
在創(chuàng)建框架網(wǎng)站]時(shí),自動(dòng)啟用了身份驗(yàn)證,無(wú)需再執(zhí)行任何操作
7.2 創(chuàng)建用戶和分組
超級(jí)用戶已經(jīng)過(guò)身份驗(yàn)證,并擁有所有權(quán)限,因此需要?jiǎng)?chuàng)建一個(gè)測(cè)試用戶,來(lái)代表普通網(wǎng)站用戶
使用管理站點(diǎn),來(lái)創(chuàng)建組別和網(wǎng)站登錄,這是最快的方法
還可以用編程方式創(chuàng)建用戶
7.3 設(shè)置身份驗(yàn)證視圖
Django 提供了創(chuàng)建身份驗(yàn)證頁(yè)面所需的幾乎所有功能,讓處理登錄,注銷(xiāo)和密碼管理等工作,都能直接使用,包括了url 映射器,視圖和表單,但
不包括模板- 必須創(chuàng)建自己的模板!
7.3.1 項(xiàng)目網(wǎng)址
將以下內(nèi)容,添加到項(xiàng)目 urls.py(
locallibrary/locallibrary/urls.py)文件的底部:
# Use include() to add URLS from the catalog application and authentication system
from django.urls import include
#Add Django site authentication urls (for login, logout, password management)
urlpatterns += [
path('accounts/', include('django.contrib.auth.urls')),
]
打開(kāi) URL http://127.0.0.1:8000/accounts/ (注意前面的斜杠?。?,Django將顯示一個(gè)錯(cuò)誤,它無(wú)法找到此URL,并列出它嘗試過(guò)的所有URL
注意: 使用上面的方法,添加以下帶有方括號(hào)中的名稱的 URL,可用于反轉(zhuǎn) URL 映射。
不必實(shí)現(xiàn)任何其他內(nèi)容 - 上面的 url 映射,會(huì)自動(dòng)映射下面提到的URL。
accounts/ login/ [name='login']
accounts/ logout/ [name='logout']
accounts/ password_change/ [name='password_change']
accounts/ password_change/done/ [name='password_change_done']
accounts/ password_reset/ [name='password_reset']
accounts/ password_reset/done/ [name='password_reset_done']
accounts/ reset/<uidb64>/<token>/ [name='password_reset_confirm']
accounts/ reset/done/ [name='password_reset_complete']
現(xiàn)在嘗試打開(kāi)登錄 URL(http://127.0.0.1:8000/accounts/login/)。這將再次失敗,但顯示錯(cuò)誤信息:在模板搜索路徑上缺少必需的模板(registration/login.html)。將在頂部的黃色部分中,看到以下文字:
Exception Type: TemplateDoesNotExist
Exception Value: registration/login.html
下一步是在搜索路徑上創(chuàng)建注冊(cè)目錄,然后添加 login.html 文件
7.3.2 模板目錄
我們希望在模板搜索路徑中的目錄
/registration/某處,找到剛剛添加的 url(以及隱式視圖)的關(guān)聯(lián)模板。
此站點(diǎn) HTML 頁(yè)面放在templates/registration/目錄中。templates目錄應(yīng)該位于項(xiàng)目的根目錄中,即與 catalog 和 locallibrary 文件夾相同的目錄)。
要使這些目錄對(duì)模板加載器可見(jiàn)(即將此目錄放在模板搜索路徑中),打開(kāi)項(xiàng)目設(shè)置(/locallibrary/locallibrary/settings.py),并更新TEMPLATES部分的DIRS那一行,如下所示:
TEMPLATES = [
{
...
'DIRS': ['./templates',],
'APP_DIRS': True,
...
7.3.3 登錄模板(login.html)
創(chuàng)建一個(gè)名為 `/locallibrary/templates/registration/login.html'的新HTML文件。加入以下內(nèi)容:
{% extends "base_generic.html" %}
{% block content %}
{% if form.errors %}
<p>Your username and password didn't match. Please try again.</p>
{% endif %}
{% if next %}
{% if user.is_authenticated %}
<p>Your account doesn't have access to this page. To proceed,
please login with an account that has access.</p>
{% else %}
<p>Please login to see this page.</p>
{% endif %}
{% endif %}
<form method="post" action="{% url 'login' %}">
{% csrf_token %}
<div>
<td>{{ form.username.label_tag }}</td>
<td>{{ form.username }}</td>
</div>
<div>
<td>{{ form.password.label_tag }}</td>
<td>{{ form.password }}</td>
</div>
<div>
<input type="submit" value="login" />
<input type="hidden" name="next" value="{{ next }}" />
</div>
</form>
{# Assumes you setup the password_reset view in your URLconf #}
<p><a href="{% url 'password_reset' %}">Lost password?</a></p>
{% endblock %}
如果您嘗試登錄,將會(huì)成功,并且被重定向到另一個(gè)頁(yè)面(默認(rèn)情況下,這將是 http://127.0.0.1:8000/accounts/profile/)。
這里的問(wèn)題是,默認(rèn)情況下,Django希望在登錄后,可能會(huì)被帶到個(gè)人資料頁(yè)面,這可能是,也可能不是。由于還沒(méi)有定義此頁(yè)面,將收到另一個(gè)錯(cuò)誤!
打開(kāi)項(xiàng)目設(shè)置(
/locallibrary/locallibrary/settings.py),并將下面的文本添加到底部?,F(xiàn)在登錄時(shí),將重定向到站點(diǎn)主頁(yè)。
# Redirect to home URL after login (Default redirects to /accounts/profile/)
LOGIN_REDIRECT_URL = '/'
7.3.4 登出模板(logout.html)
打開(kāi)登出網(wǎng)址(http://127.0.0.1:8000/accounts/logout/),會(huì)看到 - 管理員登出頁(yè)面
創(chuàng)建并打開(kāi) /locallibrary/templates/registration/logged_out.html。將下面的文字,復(fù)制到文檔中:
{% extends "base_generic.html" %}
{% block content %}
<p>Logged out!</p>
<a href="{% url 'login'%}">Click here to login again.</a>
{% endblock %}
7.3.5 密碼重置模板
默認(rèn)密碼重置系統(tǒng),使用電子郵件向用戶發(fā)送重置鏈接。您需要?jiǎng)?chuàng)建表單,以獲取用戶的電子郵件地址,發(fā)送電子郵件,允許他們輸入新密碼,以及記錄整個(gè)過(guò)程的完成時(shí)間。
7.3.5.1 密碼重置表單
用于獲取用戶電子郵件地址的表單(用于發(fā)送密碼重置電子郵件)
創(chuàng)建/locallibrary/templates/registration/password_reset_form.html,并添加以下內(nèi)容:
{% extends "base_generic.html" %}
{% block content %}
<form action="" method="post">{% csrf_token %}
{% if form.email.errors %} {{ form.email.errors }} {% endif %}
<p>{{ form.email }}</p>
<input type="submit" class="btn btn-default btn-lg" value="Reset password" />
</form>
{% endblock %}
7.3.5.2 密碼重置完成
收集您的電子郵件地址后,會(huì)顯示此表單
創(chuàng)建 /locallibrary/templates/registration/password_reset_done.html,并為其提供以下內(nèi)容:
{% extends "base_generic.html" %}
{% block content %}
<p>We've emailed you instructions for setting your password. If they haven't arrived in a few minutes, check your spam folder.</p>
{% endblock %}
7.3.5.3 密碼重置電子郵件
此模板提供 HTML 電子郵件的文本,其中包含我們將發(fā)送給用戶的重置鏈接。創(chuàng)建 /locallibrary/templates/registration/password_reset_email.html,并為其提供以下內(nèi)容:
Someone asked for password reset for email {{ email }}. Follow the link below:
{{ protocol}}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}
7.3.5.4 密碼重置確認(rèn)
點(diǎn)擊密碼重置電子郵件中的鏈接后,您可以在此頁(yè)面輸入新密碼。創(chuàng)建 /locallibrary/templates/registration/password_reset_confirm.html,并為其提供以下內(nèi)容:
{% extends "base_generic.html" %}
{% block content %}
{% if validlink %}
<p>Please enter (and confirm) your new password.</p>
<form action="" method="post">
<div style="display:none">
<input type="hidden" value="{{ csrf_token }}" name="csrfmiddlewaretoken">
</div>
<table>
<tr>
<td>{{ form.new_password1.errors }}
<label for="id_new_password1">New password:</label></td>
<td>{{ form.new_password1 }}</td>
</tr>
<tr>
<td>{{ form.new_password2.errors }}
<label for="id_new_password2">Confirm password:</label></td>
<td>{{ form.new_password2 }}</td>
</tr>
<tr>
<td></td>
<td><input type="submit" value="Change my password" /></td>
</tr>
</table>
</form>
{% else %}
<h1>Password reset failed</h1>
<p>The password reset link was invalid, possibly because it has already been used. Please request a new password reset.</p>
{% endif %}
{% endblock %}
7.3.5.4 密碼重置完成
這是最后一個(gè)密碼重置模板,顯示該模板,以在密碼重置成功時(shí)通知您。創(chuàng)建 /locallibrary/templates/registration/password_reset_complete.html,并為其提供以下內(nèi)容:
{% extends "base_generic.html" %}
{% block content %}
<h1>The password has been changed!</h1>
<p><a href="{% url 'login' %}">log in again?</a></p>
{% endblock %}
7.4 測(cè)試已驗(yàn)證身份的用戶
Django只會(huì)向已存儲(chǔ)在其數(shù)據(jù)庫(kù)中的地址(用戶)發(fā)送重置電子郵件!*
密碼重置系統(tǒng),要求您的網(wǎng)站支持電子郵件,這超出了本文的范圍,因此該部分將無(wú)法使用。要測(cè)試此功能,請(qǐng)將以下一行放在 settings.py 文件的末尾。這會(huì)記錄發(fā)送到命令行控制臺(tái)的所有電子郵件(因此您可以從命令行控制臺(tái),復(fù)制密碼重置鏈接)。
參閱發(fā)送電子郵件(Django文檔)
7.5 示例 - 列出當(dāng)前用戶的書(shū)本
7.5.1 在模板中測(cè)試
打開(kāi)基本模板(
/locallibrary/catalog/templates/base_generic.html),并將以下文本,復(fù)制到側(cè)邊欄區(qū)塊sidebar中,緊接在endblock模板標(biāo)記之前。
<ul class="sidebar-nav">
...
{% if user.is_authenticated %}
<li>User: {{ user.get_username }}</li>
<li><a href="{% url 'logout'%}?next={{request.path}}">Logout</a></li>
{% else %}
<li><a href="{% url 'login'%}?next={{request.path}}">Login</a></li>
{% endif %}
</ul>
使用 if-else-endif模板標(biāo)簽,根據(jù) {{ user.is_authenticated }} 是否為 true ,來(lái)有條件地顯示文本。如果用戶已通過(guò)身份驗(yàn)證,那么我們知道,我們擁有有效用戶,因此我們會(huì)調(diào)用 {{ user.get_username }} ,來(lái)顯示其名稱
使用 url模板標(biāo)記,和相應(yīng) URL 配置的名稱,創(chuàng)建登錄和登出鏈接 URL。另外請(qǐng)注意,我們?nèi)绾螌?“?next={{request.path}}附加到URL的末尾。這樣做,是將包含當(dāng)前頁(yè)面地址(URL)的URL參數(shù),添加到鏈接URL的末尾。用戶成功登錄/登出后,視圖將使用此“下一個(gè)”值,將用戶重定向,回到他們首次單擊登錄/登出鏈接的頁(yè)面
7.5.2 在視圖中測(cè)試
使用基于函數(shù)的視圖,則限制訪問(wèn)函數(shù)的最簡(jiǎn)單方法,是將login_required裝飾器,應(yīng)用于您的視圖函數(shù),如下所示。如果用戶已登錄,則您的視圖代碼將正常執(zhí)行。
如果用戶未登錄,則會(huì)重定向到項(xiàng)目設(shè)置 (settings.LOGIN_URL)中定義的登錄URL,并將當(dāng)前絕對(duì)路徑,作為URL參數(shù)("下一個(gè)"next)來(lái)傳遞。如果用戶成功登錄,則會(huì)返回到此頁(yè)面,但這次會(huì)進(jìn)行身份驗(yàn)證。
from django.contrib.auth.decorators import login_required
@login_required
def my_view(request):
...
7.6 實(shí)例
讓用戶可以借用書(shū)本實(shí)例BookInstance(我們已經(jīng)擁有狀態(tài)status和還書(shū)日期due_back,但這個(gè)模型和用戶之間,沒(méi)有任何關(guān)聯(lián)。我們將使用ForeignKey(一對(duì)多)字段,來(lái)創(chuàng)建一個(gè)。我們還需要一個(gè)簡(jiǎn)單的機(jī)制,來(lái)測(cè)試借出的書(shū)是否過(guò)期。
打開(kāi) catalog/models.py,然后從 django.contrib.auth.models 導(dǎo)入 User模型(在文件頂部的上一個(gè)導(dǎo)入行的正下方添加它,好讓后續(xù)代碼可以使用 User)
from django.contrib.auth.models import User
接下來(lái)將借用者字段borrower,添加到BookInstance模型:
borrower = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True)
from datetime import date
@property
def is_overdue(self):
if self.due_back and date.today() > self.due_back:
return True
return False
