Django實踐2——圖書館系統(tǒng)

簡書文章目錄生成腳本: 左側(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)圖書

UML 關(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è)邊欄和用命名blockendblock 模板標簽標記的主要內(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è)邊欄,其中包含指向所有書籍和作者列表的鏈接,兩者都包含在塊中,以便將來輕松更改。
還引入了兩個額外的模板標簽:urlload 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_listbook_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_listbook_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_APPSMIDDLEWARE 部分中設(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
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容