簡書文章目錄生成腳本: 左側(cè)目錄
不要錯過,在簡書,你一定需要的
喜歡本文,請點個??,Thanks!
1. 創(chuàng)建網(wǎng)站框架
1.1 創(chuàng)建項目
用django-admin startproject命令創(chuàng)建新項目,并進入該文件夾
django-admin startproject locallibrary
cd locallibrary
1.2 創(chuàng)建應(yīng)用(App)——catalog
python manage.py startapp catalog
1.3 項目設(shè)置文件配置
打開項目設(shè)置文件 locallibrary/locallibrary/settings.py
1.3.1 注冊應(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', # 注冊應(yīng)用
]
1.3.2 語言和時區(qū)設(shè)置
LANGUAGE_CODE = 'zh-hans'
TIME_ZONE = 'Asia/Shanghai'
1.4 網(wǎng)站路由URL設(shè)置
-
項目主URL
打開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/ 的請求轉(zhuǎn)發(fā)到模塊 catalog.urls (使用相對路徑 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)建一個名為 urls.py 的文件,并添加以下文本(空的 urlpatterns)
from django.urls import path
from catalog import views
urlpatterns = [
]
1.5 測試網(wǎng)站框架
1.5.1 數(shù)據(jù)庫遷移
python manage.py makemigrations
python manage.py migrate
重要信息: 每次模型改變,都需要運行以上命令,來影響需要存儲的數(shù)據(jù)結(jié)構(gòu)(包括添加和刪除整個模型和單個字段)。
1.5.2 運行網(wǎng)站
python manage.py runserver 0.0.0.0:8000
- 瀏覽器打開網(wǎng)址:localhost:8000
2. ## 設(shè)計LocalLibaray模型
2.1 模型入門
2.1.1 模型定義
- 模型通常在應(yīng)用程序的models.py文件中定義
-
可以包括
字段、方法和元數(shù)據(jù)
下面的代碼片段顯示了一個名為 的“典型”模型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 字段
2.1.1.2 元數(shù)據(jù)
聲明模型級元數(shù)據(jù)class Meta
class Meta:
ordering = ['-my_field_name']
2.1.1.3 方法
- 模型也可以有方法
-
常用方法
__str__(): 返回標題或名稱字段, 用于站點管理 -
常用方法是
get_absolute_url(): 返回一個 URL,用于在網(wǎng)站上顯示1個模型記錄
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來顯示模型的單個記錄(其中“2”id代表特定記錄),需要創(chuàng)建一個 URL 映射器以將
響應(yīng)和id傳遞到“模型詳細信息視圖”(這將完成顯示記錄所需的工作)。- reverse()上面的函數(shù)能夠“反轉(zhuǎn)”您的 url 映射器(在上述情況下名為'model-detail-view')以創(chuàng)建正確格式的 URL。
- 要完成這項工作,需要繼續(xù)完善編寫 URL 映射、視圖和模板**
2.1.3 模型管理
- 一旦定義了模型類,可以使用它們來創(chuàng)建、更新或刪除記錄,以及運行查詢以獲取所有記錄或記錄的特定子集。
- 在定義視圖教程中詳細展示如何做到這一點
- 創(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ào)用save()將修改后的值存儲到數(shù)據(jù)庫中
# 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屬性(由基類提供)搜索符合特定條件的記錄
all_books = Book.objects.all()
Django 的filter()方法允許根據(jù)特定條件過濾返回QuerySet以匹配指定的文本或數(shù)字字段。例如,要過濾標題中包含“wild”的書籍,然后對其進行計數(shù)
wild_books = Book.objects.filter(title__contains='wild')
number_wild_books = wild_books.count()
2.2 定義 LocalLibrary 模型
該圖還顯示了模型之間的關(guān)系,包括它們的多重性
多重性是圖表上的數(shù)字,顯示關(guān)系中可能存在的每個模型的數(shù)量(最大值和最小值)
如,框之間的連接線顯示 Book 和 Genre 相關(guān)。靠近 Genre 模型的數(shù)字表明一本書必須有一個或多個 Genres(任意數(shù)量),而 Book 模型旁邊該行另一端的數(shù)字表明一個 Genre 可以有零個或多個相關(guān)聯(lián)圖書

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)
# 使用外鍵,因為書只能有一個作者,但作者可以有多本書
# 作者作為字符串而不是對象編寫,因為它尚未在文件中聲明
author = models.ForeignKey('Author', on_delete=models.SET_NULL, null=True)
# summary文本可能很長,使用長文本類型
summary = models.TextField(max_length=1000, help_text='Enter a brief description of the book')
# 將標簽顯式設(shè)置為“ISBN”(否則默認為“Isbn”)
# 設(shè)置參數(shù) unique 為 true以確保所有書籍都有唯一的 ISBN(唯一參數(shù)使字段值在表中全局唯一)
isbn = models.CharField('ISBN', max_length=13, unique=True,
help_text='13 Character <a >ISBN number</a>')
# 使用ManyToManyField是因為體裁可以包含許多書籍。書籍可以涵蓋多種體裁.
# 體裁類已經(jīng)定義,所以可以指定上面的對象.
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()返回一個 URL,
該 URL 可用于訪問此模型的詳細記錄
因此,必須定義一個具有 name 的 URL 映射book-detail,并定義關(guān)聯(lián)的視圖和模板)
2.2.3 BookInstance(圖書實例)模型
import uuid # 要求圖書實例具有唯一性
class BookInstance(models.Model):
"""表示一本書的特定副本(即可從圖書館借閱的副本)的模型."""
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為此模型的。這種類型的字段為每個實例分配一個全局唯一的值。
DateField用于due_back日期(預計圖書在借出或維護后可用的日期)。該值可以是blank或null(當圖書可用時需要)
Class Meta當在查詢中返回記錄時,模型元數(shù)據(jù) ( ) 使用此字段對記錄進行排序
status是CharField定義選擇/選擇列表的 。定義一個包含鍵值對元組的元組,并將其傳遞給choices 參數(shù)鍵/值對中的值是用戶可以選擇的顯示值,而鍵是選擇該選項時實際保存的值
設(shè)置一個默認值“m”(維護),因為在書上架之前,書最初會被創(chuàng)建為不可用
該方法使用其唯一 id 和相關(guān)聯(lián)的標題的組合來str()表示BookInstance對象Book
從Python 3.6開始,可以使用字符串插值語法(也稱為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 映射以獲取用于顯示單個作者的 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. 管理站點
3.1 注冊模型
在目錄應(yīng)用程序(/locallibrary/catalog/admin.py)中打開 admin.py
導入模型,調(diào)用 admin.site.register 注冊模型
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)建超級用戶
- 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)站,打開/admin(e.g. localhost:8000/admin)
添加一些體裁、作者、語言、圖書、圖書實例
3.4 高級配置
視圖列表- 添加每個記錄顯示的其他字段/信息
- 添加過濾器以根據(jù)日期或某些其他選擇值(例如圖書借閱狀態(tài))選擇列出哪些記錄
- 在列表視圖中的操作菜單中添加其他選項,并選擇此菜單在表單上顯示的位置
詳細視圖- 選擇要顯示(或排除)的字段,以及其順序,分組,是否可編輯,使用的小部件,方向等
- 將相關(guān)字段添加到記錄以允許內(nèi)聯(lián)編輯(例如:添加在創(chuàng)建作者記錄時添加和編輯圖書記錄的功能)
3.4.1 注冊 一個 ModelAdmin 類
定義 ModelAdmin類(描述布局),并將其注冊到模型中,用于管理界面改變模型的展示方式
打開 admin.py 在目錄應(yīng)用程序(/locallibrary/catalog/admin.py)
Author 模型
# 注釋原始注冊(前綴為#)
# admin.site.register(Author)
添加一個 AuthorAdmin 和注冊
# Define the admin class
class AuthorAdmin(admin.ModelAdmin):
pass
# Register the admin class with the associated model
admin.site.register(Author, AuthorAdmin)
為Book 和 BookInstance 類添加 ModelAdmin 類
注釋原始注冊
#admin.site.register(Book)
#admin.site.register(BookInstance)
使用@register 裝飾器來注冊模型(與admin.site.register() 語法作用一樣)
# 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類都是空的 (“pass”),所以管理操作并不會改變
對這些類進行擴展,以定義針對模型的管理行為
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 添加列表過濾器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 控制哪些字段被顯示和詳細視圖布局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 屬性列表只是要顯示在表格上字段
字段默認情況下垂直顯示
將它們分組在元組中(如上述“日期”字段中所示),則會水平顯示
還可以使用exclude屬性來聲明要從表單中排除的屬性列表(將顯示模型中的所有其他屬性)
3.5.2 詳細視圖字段分組
@admin.register(BookInstance)
class BookInstanceAdmin(admin.ModelAdmin):
list_filter = ('status', 'due_back')
fieldsets = (
(None, {
'fields': ('book','imprint', 'id')
}),
('Availability', {
'fields': ('status', 'due_back')
}),
)
每個部分都有自己的標題(或者None如果你不想要一個標題)和字典中的一個相關(guān)的元組 - 描述
3.5.3 關(guān)聯(lián)記錄的內(nèi)聯(lián)編輯
有時,可以同時添加關(guān)聯(lián)記錄是有意義的
例如,將書籍信息和有關(guān)詳細信息頁面上的特定副本的信息同時顯示可能是有意義的
通過聲明 inlines, 類型 TabularInline (水平布局 ) or StackedInline (垂直布局 ,默認布局)
class BooksInstanceInline(admin.TabularInline):
model = BookInstance
@admin.register(Book)
class BookAdmin(admin.ModelAdmin):
list_display = ('title', 'author', 'display_genre')
inlines = [BooksInstanceInline]
4. 構(gòu)建主頁
創(chuàng)建一個url映射器,視圖和模板來顯示這些頁面
URL映射: 根據(jù)支持的URL(以及任何編碼在URL里的信息)跳轉(zhuǎn)到相應(yīng)的View功能函數(shù)
View 函數(shù)從模型中獲取請求的數(shù)據(jù),創(chuàng)建一個顯示數(shù)據(jù)的HTML頁面,并將其返回給用戶在瀏覽器查看
Templates在View視圖中進行數(shù)據(jù)渲染的時候使用
處理HTTP請求/響應(yīng)時需要實現(xiàn)的數(shù)據(jù)和事件的主要流程
4.1 定義資源URL
5個頁面
catalog/ — 主頁
catalog/books/ — 書單頁
catalog/authors/ — 作者頁
catalog/book/<id> — 主鍵字段 ID的具體書 —詳細視圖。如/catalog/book/3,第三本書。
catalog/author/<id> — 主鍵字段 ID的具體作者—詳細視圖。如 /catalog/author/11,第11個作者
4.2 創(chuàng)建索引頁
創(chuàng)建的第一個頁面是索引頁(catalog/)
這會顯示一些靜態(tài)HTML,以及數(shù)據(jù)庫中不同記錄的一些計算的“計數(shù)“
為了使其工作,必須分別創(chuàng)建一個URL映射,視圖和模板
4.2.1 URL映射
在創(chuàng)建的
基礎(chǔ)網(wǎng)站上,更新 /locallibrary/urls.py 文件
以確保接收到以**catalog/**開頭的URL時,URLConf模塊中的catalog.urls會處理剩余的字符串
打開catalog/urls.py
urlpatterns = [
path('', views.index, name='index'), # 檢測到URL模式'',(views.index——在view.py中函數(shù)命名index() )將被調(diào)用
]
name參數(shù),此唯一標識指定 URL 映射
可以使用 "reverse" 映射—去動態(tài)創(chuàng)建指定映射設(shè)計處理的資源的一個URL
例如,可以通過在模板中創(chuàng)建以下鏈接到主頁
<a href="{% url 'index' %}">Home</a>
# 可以硬編碼上面的鏈接(如:<a href="/catalog/">Home</a>)
# 但是如果改變了主頁的模式,模版將不再正確鏈接,使用反向網(wǎng)址映射會更靈活和強大
4.2.2 View (基于函數(shù))
視圖是處理 HTTP 請求,從數(shù)據(jù)庫中獲取所需數(shù)據(jù),使用 HTML 模板在 HTML 頁面中呈現(xiàn)數(shù)據(jù),然后在 HTTP 響應(yīng)中返回生成的 HTML 以向用戶顯示頁面的功能。
索引視圖遵循這個模型——它獲取數(shù)據(jù)庫中擁有的Book、BookInstance、 可用BookInstance 和Author記錄數(shù)量的 信息,并將該信息傳遞給模板進行顯示。
打開catalog/views.py
from .models import Book, Author, BookInstance, Genre # 導入模型類
def index(request):
"""View function for home page of site."""
# Generate counts of some of the main objects
# 使用模型類上的objects.all()屬性獲取記錄數(shù)`objects.all`
num_books = Book.objects.all().count()
num_instances = BookInstance.objects.all().count()
# Available books (status = 'a')
# 獲取BookInstance模型中status字段中值為“a”(可用)的對象列表`objects.filter`
num_instances_available = BookInstance.objects.filter(status__exact='a').count()
# The 'all()' is implied by default.
num_authors = Author.objects.count()
# context變量,是一個 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ù)來創(chuàng)建一個 HTML 頁面并將該頁面作為響應(yīng)返回
return render(request, 'index.html', context=context)
4.2.3 模板
模板是定義文件(例如 HTML 頁面)的結(jié)構(gòu)或布局的文本文件,使用占位符來表示實際內(nèi)容
將在使用startapp創(chuàng)建的 Django 應(yīng)用程序目錄下的templates子目錄中查找模板
在上述索引視圖中,該render()函數(shù)將在/locallibrary/catalog/templates/ 中找到文件index.html,如果該文件不存在,則會引發(fā)錯誤
Django 會在許多地方尋找模板,默認情況下會在應(yīng)用程序(App)中進行搜索
關(guān)于 Django 如何查找模板以及它支持哪些模板格式的信息, 可查看Django 文檔的模板部分
4.2.3.1 擴展模板
索引模板需要
頭部和正文的標準 HTML 標記,以及鏈接到站點其他頁面(尚未創(chuàng)建)的導航部分,以及顯示介紹性文本和書籍數(shù)據(jù)的部分
網(wǎng)站的每個頁面中的大部分 HTML 和導航結(jié)構(gòu)都是相同的。可以使用 Django 模板語言聲明一個基本模板,而不是在每個頁面上復制樣板代碼,然后擴展它以僅替換每個特定頁面不同的位
- base_generic.html
base_generic.html文件的示例基本模板,包含標題、側(cè)邊欄和用命名block和endblock模板標簽標記的主要內(nèi)容的部分
模板標簽可以在模板中用于循環(huán)列表、基于變量值執(zhí)行條件操作等的函數(shù)
除了模板標簽之外,模板語法還允許引用從視圖傳遞到模板的變量,并使用模板過濾器來格式化變量(例如,將字符串轉(zhuǎn)換為小寫)
<!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>
- 擴展模板
- 在為特定視圖定義模板時,首先使用extends模板標簽指定基本模板
- 然后聲明模板中想要替換的基本模板中使用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 主頁構(gòu)建
4.3.1 基礎(chǔ)模板base_generic.html
定義塊title,sidebar和content。有一個默認標題和一個默認側(cè)邊欄,其中包含指向所有書籍和作者列表的鏈接,兩者都包含在塊中,以便將來輕松更改。
還引入了兩個額外的模板標簽:url和load static
模板包括來自Bootstrap的 CSS改進 HTML 頁面的布局和呈現(xiàn)
使用 Bootstrap(或其他客戶端 Web 框架)是一種快速創(chuàng)建有吸引力的頁面的方法,該頁面可以在不同的屏幕尺寸上良好顯示
基本模板還引用了一個提供額外樣式的本地 css 文件 ( styles.css )
在/locallibrary/catalog/static/css/ 中創(chuàng)建一個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)建一個新的 HTML 文件
index.html并將以下代碼粘貼到文件中。
在第一行擴展基本模板,然后替換了模板的默認塊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 %}
在動態(tài)內(nèi)容部分,為要包含的視圖中的信息聲明占位符(模板變量)。變量用雙括號(把手)括起來。
輕松識別模板變量和模板標簽(函數(shù))——變量用雙大括號 ( {{ num_books }}) 括起來,標簽用帶百分號 ( {% extends "base_generic.html" %}) 的單大括號括起來
變量是用在視圖函數(shù)中傳遞給字典的鍵命名的(參見下面的示例), 呈現(xiàn)模板時,變量將替換為其關(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)頁
4.3.3 在模板中引用靜態(tài)文件
- 項目可能會使用靜態(tài)資源,包括 JavaScript、CSS 和圖像
- 由于這些文件的位置可能未知(或可能更改),Django 允許在模板中指定相對于
STATIC_URL全局設(shè)置的位置- 默認骨架網(wǎng)站設(shè)置 STATIC_URL 的值為“ /static/”,但可以選擇將這些內(nèi)容托管在內(nèi)容交付網(wǎng)絡(luò)或其他地方
在模板中,首先調(diào)用load 指定“static”的模板標記來添加模板庫
然后,可以使用static模板標記并指定所需文件的相對 URL
<!-- Add additional CSS in static file -->
{% load static %}
<link rel="stylesheet" href="{% static 'css/styles.css' %}">
可以以類似的方式將圖像添加到頁面中
{% load static %}
<img src="{% static 'catalog/images/local_library_model_uml.png' %}" alt="UML diagram" style="width:555px;height:540px;">
上面的示例指定了文件所在的位置,但 Django 默認不提供
通過修改全局 URL 映射器 (/locallibrary/locallibrary/urls.py)將Web 服務(wù)器配置為提供文件服務(wù),但仍需要在生產(chǎn)中啟用文件服務(wù)(詳見后文)
有關(guān)使用靜態(tài)文件的更多信息,請參閱 Django 文檔中管理靜態(tài)文件
4.3.4 鏈接到 URL
上面的基礎(chǔ)模板引入了
url模板標簽
此標記接受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對象中指定。默認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是最重要的,因為它告訴 Django 在項目中每個應(yīng)用程序的子目錄中搜索模板,命名為“模板”
可以指定 Django 使用的特定位置來搜索目錄'DIRS': [](但這還不是必需的)
有關(guān) Django 如何查找模板以及它支持哪些模板格式的更多信息Django 文檔的模板部分
5. 通用列表和詳細信息視圖
5.1 書本清單頁面
5.1.1 URL 映射
- 打開
/catalog/urls.py- 調(diào)用視圖函數(shù)
views.BookListView.as_view()和一個對應(yīng)這個特定映射的名稱
urlpatterns = [
path('', views.index, name='index'),
path('books/', views.BookListView.as_view(), name='books'),
]
視圖將以類別來實現(xiàn)
對于基于Django類的視圖,通過調(diào)用'類方法as_view()',來訪問適當?shù)囊晥D函數(shù)。這樣做可以創(chuàng)建類的實例,并確保為傳入的 HTTP 請求調(diào)用正確的處理程序方法。
5.1.2 視圖 (基于類)
- 可以很容易地,將
書本列表視圖編寫為常規(guī)函數(shù)(類似于索引視圖),它將查詢數(shù)據(jù)庫中的所有書本,然后調(diào)用render(),將列表傳遞給指定的模板- 然而,此處將使用
基于類的通用列表視圖(ListView) - 一個繼承自現(xiàn)有視圖的類- 因為通用視圖,已經(jīng)實現(xiàn)了需要的大部分功能,將能夠創(chuàng)建更強大的列表視圖,具有代碼更少,重復次數(shù)更少,最終維護更少的優(yōu)點
打開
catalog/views.py, 復制下面的代碼:
from django.views import generic
class BookListView(generic.ListView):
model = Book
- **
通用視圖將查詢數(shù)據(jù)庫,以獲取指定模型(Book)的所有記錄,然后呈現(xiàn)位于/locallibrary/catalog/templates/catalog/book_list.html 的模板(將在下面創(chuàng)建)- 在模板中,可以使用名為
object_list或book_list的模板變量(即通常為“the_model_name_list”),以訪問書本列表
注意: 模板位置路徑不是印刷錯誤 - 通用視圖在應(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 覆蓋基于類的視圖中的方法
- 以覆蓋
get_queryset()方法,來更改返回的記錄列表。這比僅僅設(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 變量傳遞給模板(例如,默認情況下傳遞書本列表)- 下面代碼,顯示了如何將一個名為
some_data的變量添加到上下文中(然后它將作為一個模板變量,而被提供)
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)置的基于類的通用視圖(Django文檔),了解更多可以執(zhí)行的操作示例
5.1.3 創(chuàng)建列表視圖模板
- 創(chuàng)建 HTML 文件
/locallibrary/catalog/templates/catalog/book_list.html- 視圖默認將
context (書本列表)作為object_list和book_list的別名傳遞;任何一個都會奏效
{% 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模板標簽來檢查 是否book_list已定義且不為空
如果book_list為空,則該else子句顯示文本,說明沒有要列出的書籍
如果book_list不為空,則遍歷書籍列表
{% if book_list %}
<!-- code here to list the books -->
{% else %}
<p>There are no books in the library.</p>
{% endif %}
上面的條件只檢查一種情況,但您可以使用
elif模板標記(例如{% elif var2 %})測試其他條件。有關(guān)條件運算符的更多信息,請參閱:如果, ifequal/ifnotequal, 和 如果改變 在 內(nèi)置模板標簽和過濾器
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 訪問變量
循環(huán)內(nèi)的代碼為每本書創(chuàng)建一個列表項,顯示標題(作為指向尚未創(chuàng)建的詳細信息視圖的鏈接)和作者
<a href="{{ book.get_absolute_url }}">{{ book.title }}</a> ({{book.author}})
**使用“點符號”訪問相關(guān)書籍記錄的字段,其中項目后面的文本是字段名稱(如模型中定義的)。book.titlebook.authorbook
5.1.3.4 更新基本模板
打開基本模板 (
/locallibrary/catalog/templates/ base_generic.html) 并將{% url 'books' %}插入到All books的 URL 鏈接中
5.2 圖書詳情頁面
5.2.1 網(wǎng)址映射
打開
/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 高級路徑匹配/正則表達式入門
5.2.1.2 在 URL 映射中傳遞其他選項
5.2.2 視圖 (基于類)
5.2.3 創(chuàng)建詳情視圖模板
5.3 分頁
5.3.1 視圖(基于類)
打開
catalog/views.py,然后添加paginate_by
class BookListView(generic.ListView):
model = Book
paginate_by = 10
通過添加這行,只要超過10條記錄,視圖就會開始對它發(fā)送到模板的數(shù)據(jù),進行分頁
使用 GET 參數(shù)訪問不同的頁面 - 如要訪問第2頁,將使用URL:/catalog/books/?page=2
5.3.2 模板
現(xiàn)在數(shù)據(jù)已經(jīng)分頁,需要添加對模板的支持,以滾動結(jié)果集合
因為需要在所有列表視圖中都執(zhí)行此操作,所以將以基本模板的方式執(zhí)行此操作
打開/locallibrary/catalog/templates/base_generic.html,并復制貼士以下內(nèi)容區(qū)塊下面的分頁區(qū)塊(以粗體突出顯示)
代碼首先檢查當前頁面上,是否啟用了分頁。如果是,則它會根據(jù)需要,添加下一個和上一個鏈接(以及當前頁碼)
{% 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 對象,用于獲取有關(guān)當前頁面,之前頁面,之后頁面,頁面總數(shù)等信息。
使用{{ request.path }},來獲取用于創(chuàng)建分頁鏈接的當前頁面URL, 其獨立于正在分頁的對象。
6. 會話框架
6.1 會話是什么?
- 會話是Django(以及大多數(shù)Internet)用于跟蹤站點和特定瀏覽器之間“狀態(tài)”的機制。會話允許您為每個瀏覽器存儲任意數(shù)據(jù),并在瀏覽器連接時,將該數(shù)據(jù)提供給站點。然后,通過“密鑰”引用與會話相關(guān)聯(lián)的各個數(shù)據(jù)項,“密鑰”用于存儲和檢索數(shù)據(jù)。
- Django使用包含特殊會話ID的cookie,來識別每個瀏覽器,及其與該站點的關(guān)聯(lián)會話。默認情況下,實際會話數(shù)據(jù)存儲在站點數(shù)據(jù)庫中(這比將數(shù)據(jù)存儲在cookie中更安全,因為它們更容易受到惡意用戶的攻擊)。您可以將Django配置為,將會話數(shù)據(jù)存儲在其他位置(緩存,文件,“安全”cookie),但默認位置是一個良好且相對安全的選項
6.2 啟用會話
創(chuàng)建骨架網(wǎng)站時,會自動啟用會話
- 在項目配置文件(
locallibrary / locallibrary / settings.py)的INSTALLED_APPS和MIDDLEWARE部分中設(shè)置,如下所示:
INSTALLED_APPS = [
...
'django.contrib.sessions',
....
MIDDLEWARE = [
...
'django.contrib.sessions.middleware.SessionMiddleware',
....
6.3 使用會話
可以在如何使用會話(Django文檔)中找到完整的API
6.4 保存會話數(shù)據(jù)
默認情況下,Django僅保存到會話數(shù)據(jù)庫,并在會話被修改(分配)或刪除時,將會話cookie發(fā)送到客戶端。
如果您正在更新會話數(shù)據(jù)中的某些信息,那么Django將無法識別您已對會話進行了更改并保存了數(shù)據(jù).。在這種情況下,您需要將會話明確標記為已修改。
# Set session as modified to force data updates/cookie to be saved.
request.session.modified = True
6.5 簡單的例子 - 獲取訪問次數(shù)
作為一個簡單的實際例子,將更新圖書館,告訴當前用戶訪問 LocalLibrary 主頁的次數(shù)
View修改
打開
/locallibrary/catalog/views.py,進行如下修改
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會話密鑰的值,如果之前沒有設(shè)置,則將值設(shè)置為0。
每次收到請求時,該值都會遞增,并將其存回會話中(下次用戶訪問該頁面時)。
然后將num_visits變量,傳遞給模板中的context變量
參閱如何使用會話
index.html修改
將下面的代碼添加到主HTML模板(/locallibrary/catalog/templates/index.html)的 “動態(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 啟用身份驗證
在創(chuàng)建框架網(wǎng)站]時,自動啟用了身份驗證,無需再執(zhí)行任何操作
7.2 創(chuàng)建用戶和分組
超級用戶已經(jīng)過身份驗證,并擁有所有權(quán)限,因此需要創(chuàng)建一個測試用戶,來代表普通網(wǎng)站用戶
使用管理站點,來創(chuàng)建組別和網(wǎng)站登錄,這是最快的方法
還可以用編程方式創(chuàng)建用戶
7.3 設(shè)置身份驗證視圖
Django 提供了創(chuàng)建身份驗證頁面所需的幾乎所有功能,讓處理登錄,注銷和密碼管理等工作,都能直接使用,包括了url 映射器,視圖和表單,但
不包括模板- 必須創(chuàng)建自己的模板!
7.3.1 項目網(wǎng)址
將以下內(nèi)容,添加到項目 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')),
]
打開 URL http://127.0.0.1:8000/accounts/ (注意前面的斜杠?。?,Django將顯示一個錯誤,它無法找到此URL,并列出它嘗試過的所有URL
注意: 使用上面的方法,添加以下帶有方括號中的名稱的 URL,可用于反轉(zhuǎn) URL 映射。
不必實現(xiàn)任何其他內(nèi)容 - 上面的 url 映射,會自動映射下面提到的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)在嘗試打開登錄 URL(http://127.0.0.1:8000/accounts/login/)。這將再次失敗,但顯示錯誤信息:在模板搜索路徑上缺少必需的模板(registration/login.html)。將在頂部的黃色部分中,看到以下文字:
Exception Type: TemplateDoesNotExist
Exception Value: registration/login.html
下一步是在搜索路徑上創(chuàng)建注冊目錄,然后添加 login.html 文件
7.3.2 模板目錄
我們希望在模板搜索路徑中的目錄
/registration/某處,找到剛剛添加的 url(以及隱式視圖)的關(guān)聯(lián)模板。
此站點 HTML 頁面放在templates/registration/目錄中。templates目錄應(yīng)該位于項目的根目錄中,即與 catalog 和 locallibrary 文件夾相同的目錄)。
要使這些目錄對模板加載器可見(即將此目錄放在模板搜索路徑中),打開項目設(shè)置(/locallibrary/locallibrary/settings.py),并更新TEMPLATES部分的DIRS那一行,如下所示:
TEMPLATES = [
{
...
'DIRS': ['./templates',],
'APP_DIRS': True,
...
7.3.3 登錄模板(login.html)
創(chuàng)建一個名為 `/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 %}
如果您嘗試登錄,將會成功,并且被重定向到另一個頁面(默認情況下,這將是 http://127.0.0.1:8000/accounts/profile/)。
這里的問題是,默認情況下,Django希望在登錄后,可能會被帶到個人資料頁面,這可能是,也可能不是。由于還沒有定義此頁面,將收到另一個錯誤!
打開項目設(shè)置(
/locallibrary/locallibrary/settings.py),并將下面的文本添加到底部?,F(xiàn)在登錄時,將重定向到站點主頁。
# Redirect to home URL after login (Default redirects to /accounts/profile/)
LOGIN_REDIRECT_URL = '/'
7.3.4 登出模板(logout.html)
打開登出網(wǎng)址(http://127.0.0.1:8000/accounts/logout/),會看到 - 管理員登出頁面
創(chuàng)建并打開 /locallibrary/templates/registration/logged_out.html。將下面的文字,復制到文檔中:
{% extends "base_generic.html" %}
{% block content %}
<p>Logged out!</p>
<a href="{% url 'login'%}">Click here to login again.</a>
{% endblock %}
7.3.5 密碼重置模板
默認密碼重置系統(tǒng),使用電子郵件向用戶發(fā)送重置鏈接。您需要創(chuàng)建表單,以獲取用戶的電子郵件地址,發(fā)送電子郵件,允許他們輸入新密碼,以及記錄整個過程的完成時間。
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 密碼重置完成
收集您的電子郵件地址后,會顯示此表單
創(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 密碼重置確認
點擊密碼重置電子郵件中的鏈接后,您可以在此頁面輸入新密碼。創(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 密碼重置完成
這是最后一個密碼重置模板,顯示該模板,以在密碼重置成功時通知您。創(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 測試已驗證身份的用戶
Django只會向已存儲在其數(shù)據(jù)庫中的地址(用戶)發(fā)送重置電子郵件!*
密碼重置系統(tǒng),要求您的網(wǎng)站支持電子郵件,這超出了本文的范圍,因此該部分將無法使用。要測試此功能,請將以下一行放在 settings.py 文件的末尾。這會記錄發(fā)送到命令行控制臺的所有電子郵件(因此您可以從命令行控制臺,復制密碼重置鏈接)。
參閱發(fā)送電子郵件(Django文檔)
7.5 示例 - 列出當前用戶的書本
7.5.1 在模板中測試
打開基本模板(
/locallibrary/catalog/templates/base_generic.html),并將以下文本,復制到側(cè)邊欄區(qū)塊sidebar中,緊接在endblock模板標記之前。
<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模板標簽,根據(jù) {{ user.is_authenticated }} 是否為 true ,來有條件地顯示文本。如果用戶已通過身份驗證,那么我們知道,我們擁有有效用戶,因此我們會調(diào)用 {{ user.get_username }} ,來顯示其名稱
使用 url模板標記,和相應(yīng) URL 配置的名稱,創(chuàng)建登錄和登出鏈接 URL。另外請注意,我們?nèi)绾螌?“?next={{request.path}}附加到URL的末尾。這樣做,是將包含當前頁面地址(URL)的URL參數(shù),添加到鏈接URL的末尾。用戶成功登錄/登出后,視圖將使用此“下一個”值,將用戶重定向,回到他們首次單擊登錄/登出鏈接的頁面
7.5.2 在視圖中測試
使用基于函數(shù)的視圖,則限制訪問函數(shù)的最簡單方法,是將login_required裝飾器,應(yīng)用于您的視圖函數(shù),如下所示。如果用戶已登錄,則您的視圖代碼將正常執(zhí)行。
如果用戶未登錄,則會重定向到項目設(shè)置 (settings.LOGIN_URL)中定義的登錄URL,并將當前絕對路徑,作為URL參數(shù)("下一個"next)來傳遞。如果用戶成功登錄,則會返回到此頁面,但這次會進行身份驗證。
from django.contrib.auth.decorators import login_required
@login_required
def my_view(request):
...
7.6 實例
讓用戶可以借用書本實例BookInstance(我們已經(jīng)擁有狀態(tài)status和還書日期due_back,但這個模型和用戶之間,沒有任何關(guān)聯(lián)。我們將使用ForeignKey(一對多)字段,來創(chuàng)建一個。我們還需要一個簡單的機制,來測試借出的書是否過期。
打開 catalog/models.py,然后從 django.contrib.auth.models 導入 User模型(在文件頂部的上一個導入行的正下方添加它,好讓后續(xù)代碼可以使用 User)
from django.contrib.auth.models import User
接下來將借用者字段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
