用 Django 構建一個照片共享應用程式

Django是 Web 開發中最常用的 Python 框架。其內建功能和健壯的結構使其成為構建 Web 應用程式的絕佳選擇。但是那裡有太多的資源,有時將這些知識應用於現實世界的專案會讓人不知所措。在本教程中,我們將構建一個全棧 Web 應用程式,在後端使用 Django,在前端使用 Bootstrap 風格化的 Django 模板。

要求

為了充分利用本教程,您最好掌握以下內容:

Python的基礎知識

Python中的面向物件程式設計

Django Web 框架的基礎知識

如果您之前沒有使用 Django 的經驗,請不要害怕繼續學習本教程。這將是一個循序漸進的過程,並且將解釋每個步驟。

在開始之前,我想向您介紹您最好的新盟友Django 文件。我們將在整篇文章中引用它,所以一定要熟悉它。

一個 Django 照片共享應用程式

本教程的所有原始碼均可在此GitHub 儲存庫上找到。

專案的複雜性取決於我們想要包含的所有功能。我們想要為使用者提供的功能越多,我們需要花費越多的時間來構建和整合所有內容到一個獨特的專案中。

考慮到這一點,我們將看到我們將要構建的和我們不構建的之間的快速區別。

我們要構建什麼

在本教程中,我們將構建一個全棧(後端和前端開發)照片共享應用程式。我們的應用程式將包括以下功能:

CRUD(建立、讀取、更新、刪除)資料庫功能

使用者管理系統,使使用者能夠建立帳戶、上傳照片、檢視其他人的照片以及編輯或刪除

自己的

照片

使用 Bootstrap 製作的簡單 Web 介面

注意:雖然這個應用程式看起來很像一個社交網路,但它不是一個。像 Instagram 或 Twitter 這樣的應用程式具有很多複雜性,無法在一篇文章中涵蓋。

技術棧

讓我們定義我們將要使用的技術。當我們需要使用它時,我們將涵蓋每一個的安裝過程。

後端

,Django 將是應用程式的核心框架。它允許我們透過 Django ORM(物件關係對映器)定義 URL、定義邏輯、管理使用者身份驗證和控制所有資料庫操作。

此外,我們將使用幾個第三方軟體包來加速某些功能的開發。

Django-taggit為我們提供了通過幾個步驟設定簡單標籤系統的能力。Pillow是一個 Python 包,提供 Django 影象處理功能。最後,Django-crispy-forms為我們提供了一種顯示 Bootstrap 表單的簡單方法。

前端

,我們將使用Django 模板語言,它由動態顯示資料的 HTML 檔案組成。

我們還將使用Bootstrap 5(撰寫本文時的最新版本)來設計站點。

注意:您可以隨時在requirements。txt檔案中檢查此專案中使用的依賴項。

建立一個 Django 專案

讓我們從 Django 開始吧!

首先,確保你已經安裝了 Python 3。大多數 Linux 和 macOS 系統已經安裝了 Python,但如果您使用 Windows,您可以檢視Python 3 安裝指南。

注意:我們將在本教程中使用 Unix 命令(macOS 和 Linux)。如果您因任何原因無法執行它們,您可以使用圖形檔案管理器。

在某些 linux 發行版中,該

python

命令指的是 Python 2。在其他發行版中,

python

根本不存在。

讓我們看看你需要使用什麼 Python 命令來跟隨。開啟您的終端(在 Unix 上)或命令列視窗(在 Windows 上)並輸入

python ——version

python ——version# My resultPython 3。9。5

如果你有一個高於 3。6 的 Python 版本,你就可以開始了。如果您沒有正確版本的 Python,您可能會收到如下訊息之一:

Command ‘python’ not found

Python 2。7。18

跟隨本教程需要執行的 Python 命令將是

python3

python3 ——versionPython 3。9。5

虛擬環境

一個虛擬環境是一個孤立的Python環境,其中包括所有你需要執行一個Python程式檔案。

虛擬環境是任何 Python(和 Django)專案的重要組成部分,因為它們讓我們可以與其他人管理和共享依賴項(專案依賴的外部包)。

為了在本地建立虛擬環境,我們將使用

venv

Python 3。6 或更高版本提供的內建模組。

以下命令將建立一個具有該名稱的虛擬環境

。venv

(如果您願意,可以選擇其他名稱):

python -m venv 。venv

如果您使用的是 Ubuntu Linux 或任何其他基於 Debian 的發行版,您可能會收到以下訊息:

The virtual environment was not created successfully because pip is not available 。。。

要解決此問題,您可以執行以下命令:

sudo apt-get install python3-venv

如果上面的命令不起作用,您可以使用virtualenv,這是另一個用於虛擬環境的庫:

virtualenv 。venv

執行此命令後,

。venv

將出現一個名為(或您選擇的名稱)的資料夾。

我們安裝的所有軟體包都將放置在該目錄中。

要啟用虛擬環境,您需要根據作業系統執行特定命令。您可以參考下表(摘自 Python 文件)。

平臺

貝殼

啟用虛擬環境的命令

POSIX

bash/zsh

$ 源。venv/bin/activate

$ 源。venv/bin/activate。fish

csh/tcsh

$ 源。venv/bin/activate。csh

PowerShell 核心

$ 。venv/bin/Activate。ps1

視窗

命令列工具

C:> 。venv\Scripts\activate。bat

電源外殼

PS C:> 。venv\Scripts\Activate。ps1

由於我在 POSIX 作業系統上使用 bash shell,因此我將使用以下命令:

source 。venv/bin/activate

請注意,

。venv

一旦我激活了

virtualenv

用 Django 構建一個照片共享應用程式

安裝 Django

Django 是一個外部包,所以我們需要使用 pip 安裝它:

pip install django# Use pip3 if the command above doesn‘t workpip3 install django

注意:我們可以隨時檢視我們的

venv

with 中安裝的軟體包

pip freeze

接下來,讓我們

config

使用命令列實用程式django-admin啟動一個名稱為 Django 的專案。

django-admin startproject config

這裡

config

是專案的名稱,它用作命名約定以保持所有專案具有相同的結構。例如,Django cookiecutter使用這個約定名稱來啟動一個專案。

話雖如此,您可以使用任何其他名稱建立專案。

執行這些命令後,您應該擁有 Django 專案的常規檔案結構。您可以使用命令列實用程式樹或任何檔案管理器進行檢查。

注意:如果您無法執行

tree

,則需要安裝它。

$ tree config/└── config ├── config │ ├── asgi。py │ ├── __init__。py │ ├── settings。py │ ├── urls。py │ └── wsgi。py └── manage。py

現在讓我們用 進入專案資料夾

cd

,並執行伺服器以檢查一切是否正確設定:

cd config/python manage。py runserver

您將看到一條警告訊息,指出存在未應用的遷移。這是一條完全正常的訊息,我們將在“建立照片模型”部分學習如何執行遷移。

現在,在瀏覽器中訪問localhost:8000。您應該會看到標誌性的 Django 祝賀頁面。

用 Django 構建一個照片共享應用程式

啟動照片共享應用程式

該manage。py檔案具有完全相同的功能為

django-admin

,所以我們將在本教程中使用了很多次。

它的位置在專案的根資料夾中,每次我們想用它執行一個命令時,都需要進入專案目錄。

請記住始終列出您所在目錄的檔案

ls

,以檢查我們是否在正確的位置:

$ lsAnother-files。。 manage。py

記住這些提示後,是時候啟動專案的主應用程式了。為此,我們開啟一個新的 shell(因此本地伺服器仍在執行),並使用

manage。py

命令

startapp

注意:每次我們開啟一個新的 shell 會話時,我們都需要再次啟用虛擬環境。

source 。venv/bin/activatecd configpython manage。py startapp photoapp

在這種情況下,應用程式的名稱是

photoapp

。再一次,您可以使用您想要的任何名稱建立它。

每次我們建立一個應用程式時,我們都必須安裝它。我們可以

config/settings。py

透過新增

photoapp

INSTALLED_APPS

變數來在檔案中執行此操作:

# config/settings。pyINSTALLED_APPS = [ ’django。contrib。admin‘, 。。。 # Custom apps ’photoapp‘,]

接下來,我們將進入 app 目錄並建立一個空

urls。py

檔案。我們可以透過執行

touch

或使用圖形檔案管理器建立它來做到這一點:

cd photoapp/touch urls。py

最後,讓我們在整個專案中包含照片共享應用程式的所有 URL 模式。為此,我們將使用該

django。urls。include

函式:

# config/urls。pyfrom django。urls import path, include # Import this functionurlpatterns = [ path(’admin/‘, admin。site。urls), # Main app path(’‘, include(’photoapp。urls‘)),]

上面的程式碼將包含專案的所有 URL 模式

photoapp/urls。py

如果您檢視執行伺服器的 shell,您會看到一個錯誤:

raise ImproperlyConfigured(msg。format(name=self。urlconf_name)) 。。。。

那是因為我們還沒有在檔案中建立

urlpatterns

列表

photopp/urls。py

要解決此問題,請建立一個名為 的空列表

urlpatterns

。我們稍後將使用 Django 路徑填充該變數:

# photoapp/urls。py# Empty patternsurlpatterns = []

注意:使用這種方法的優點是我們可以透過在其中包含所有需要的程式碼來使 photoapp 可重用。

建立照片模型

在本節中,我們將構建應用程式的資料庫模式。為此,我們將使用 Django ORM。

Django ORM 允許建立和管理資料庫表,而無需手動使用 SQL。

當我們寫一個模型時,它代表一個數據庫表,其中的每個屬性代表一個列。

由於我們將使用 Django 內建身份驗證系統,我們可以開始關注應用程式的核心功能。這樣,我們就可以避免構建自定義使用者管理系統。

在開始之前,我們將安裝一些第三方軟體包,

django-taggit

以及

Pillow

。 我們可以使用以下命令執行此操作:

pip install django-taggit Pillow

django-taggit是一個 Django 應用程式,所以我們需要像安裝

photoapp

一樣安裝它:

# config/settings。pyINSTALLED_APPS = [ 。。。 # 3rd party apps ’taggit‘, # Custom apps ’photoapp‘,]# Django taggitTAGGIT_CASE_INSENSITIVE = True

TAGGIT_CASE_INSENSITIVE

變數將標籤配置為不區分大小寫。這意味著

PYTHON

並且

python

將是相同的。

讓我們定義

Photo

模型,它將成為應用程式的主要模型。開啟

photoapp/models。py

檔案並使用以下程式碼:

# photoapp/models。pyfrom django。db import modelsfrom django。contrib。auth import get_user_modelfrom taggit。managers import TaggableManagerclass Photo(models。Model): title = models。CharField(max_length=45) description = models。CharField(max_length=250) created = models。DateTimeField(auto_now_add=True) image = models。ImageField(upload_to=’photos/‘) submitter = models。ForeignKey(get_user_model(), on_delete=models。CASCADE) tags = TaggableManager() def __str__(self): return self。title

在上面的程式碼塊中,我們定義了

Photo

模型。讓我們看看每個欄位的作用。

title

欄位是一個CharField,限制為 45 個字元。

description

是另一個 CharField 但限制為 250 個字元。

created

是一個DateTimeField,顧名思義,它儲存建立照片時的日期和小時。

image

是一個ImageField。它將影象上傳到

media/photos

並存儲檔案所在的 URL。稍後我們將看到如何設定媒體檔案。

submitter

是一個ForeignKey,這意味著它與使用者和上傳的照片有關。這樣我們就可以過濾哪個使用者上傳了一張照片。

最後,

tags

是一個TaggableManager,允許我們透過標籤對主題進行分類。

另一方面,該

__str__

方法指示每個物件將如何顯示在管理區域中。稍後,我們將設定管理員並建立我們的第一個物件。

要基於我們建立的模型建立資料庫,我們首先需要進行遷移,然後執行它們。

進入專案根目錄並使用

manage。py

帶有以下引數的指令碼:

python manage。py makemigrationspython manage。py migrate

makemigrations

命令將根據

Photo

模型建立一個遷移檔案。

注意:遷移是基於模型在資料庫中產生更改的 Python 指令碼。

我們可以透過開啟

photoapp/migrations/0001_initial。py

檔案確切地看到遷移發生了什麼:

# photoapp/migrations/0001_initial。py# imports 。。。class Migration(migrations。Migration): initial = True dependencies = [ (’taggit‘, ’0003_taggeditem_add_unique_index‘), migrations。swappable_dependency(settings。AUTH_USER_MODEL), ] operations = [ migrations。CreateModel( name=’Photo‘, fields=[ (’id‘, models。BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name=’ID‘)), 。。。。。

提示:切勿手動修改遷移檔案。所有遷移都必須由 Django 自動生成。

migrate

命令透過執行所有遷移來建立資料庫表。

執行這兩個命令後,您應該會在專案根資料夾中看到一個 SQLite 資料庫。如果我們使用DB Browser檢查它,我們將看到與

Photo

模型相關的所有欄位。

用 Django 構建一個照片共享應用程式

管理開發中的媒體檔案

照片共享應用在很大程度上依賴於媒體檔案。這完全是關於共享影象,不是嗎?

Django 中的媒體檔案是使用者上傳的所有檔案。現在,我們將在開發中設定媒體檔案,因為我們只會透過本地伺服器與應用程式互動。

為了在開發中啟用媒體檔案,我們在設定檔案中建立MEDIA_URL和MEDIA_ROOT變數。此外,我們需要修改

urlpatterns

整個專案的 以從本地伺服器提供媒體檔案。

首先,我們需要編輯

config/settings。py

檔案並在檔案末尾附加以下程式碼:

# config/settings。py# Other settings 。。。MEDIA_URL = ’/media/‘MEDIA_ROOT = BASE_DIR / ’media/‘

MEDIA_URL

是處理上傳到

MEDIA_ROOT

資料夾的所有媒體的 URL 。在這種情況下,絕對媒體 URL 將如下所示:

http://localhost:8000/media/

另一方面,

MEDIA_ROOT

是指向放置所有媒體的資料夾的路徑。

請記住,由於我們使用的是pathlib庫,因此我們可以將路徑與

/

我們可以

MEDIA_ROOT

將影象視為上傳影象的物理儲存,以及

MEDIA_URL

指向該儲存的 URL。

如果我們想讓 Django 管理媒體檔案,我們需要修改專案 URL:

# config/urls。py# New importsfrom django。conf import settingsfrom django。conf。urls。static import staticurlpatterns = [ path(’admin/‘, admin。site。urls), # Main app path(’‘, include(’photoapp。urls‘)),] + static(settings。MEDIA_URL, document_root=settings。MEDIA_ROOT)

考慮到這一點,上傳照片的絕對 URL 將是:

http://localhost:8000/media/photos/

。這是因為我們將

upload_to

屬性設定為

photos/

注意:接受使用者上傳的檔案可能很危險。檢視此安全注意事項列表。

在使用公開可用的應用程式時,我們必須小心處理媒體檔案。我們可能會遭受DoS 攻擊。使用者也可能上傳惡意內容,因此推薦的方法是始終使用CDN來解決此類問題。

現在,您可以忘記安全問題,因為我們正在處理一個開發專案,並且

ImageField

只接受一組預先確定的擴充套件。

您可以透過在 Django shell 中執行以下程式碼來檢查那些有效的擴充套件(確保您的

venv

已啟用):

$ python manage。py shell>>> from django。core。validators import get_available_image_extensions>>> get_available_image_extensions()[’blp‘, ’bmp‘, ’dib‘, ’bufr‘, ’cur‘, ’pcx‘, ’dcx‘, ’dds‘, ’ps‘, ’eps‘, ’fit‘, ’fits‘, ’fli‘, ’flc‘, ’ftc‘, ’ftu‘, ’gbr‘, ’gif‘, ’grib‘, ’h5‘, ’hdf‘, ’png‘, ’apng‘, ’jp2‘, ’j2k‘, ’jpc‘, ’jpf‘, ’jpx‘, ’j2c‘, ’icns‘, ’ico‘, ’im‘, ’iim‘, ’tif‘, ’tiff‘, ’jfif‘, ’jpe‘, ’jpg‘, ’jpeg‘, ’mpg‘, ’mpeg‘, ’mpo‘, ’msp‘, ’palm‘, ’pcd‘, ’pdf‘, ’pxr‘, ’pbm‘, ’pgm‘, ’ppm‘, ’pnm‘, ’psd‘, ’bw‘, ’rgb‘, ’rgba‘, ’sgi‘, ’ras‘, ’tga‘, ’icb‘, ’vda‘, ’vst‘, ’webp‘, ’wmf‘, ’emf‘, ’xbm‘, ’xpm‘]

使用 Django Admin 測試模型

Django admin 是一個內建介面,管理使用者可以在其中使用專案的註冊模型進行 CRUD 操作。

現在我們已經建立了照片模型並設定了媒體檔案,是時候

Photo

透過管理頁面建立我們的第一個物件了。

為此,我們必須將

Photo

模型註冊到管理頁面。讓我們開啟

photoapp/admin。py

,匯入 Photo 模型,並將其作為引數傳遞給

admin。site。register

函式:

# photoapp/admin。pyfrom django。contrib import adminfrom 。models import Photo # We import the photo model# Register your models here。admin。site。register(Photo)

接下來,是時候建立一個能夠訪問管理頁面的超級使用者了。我們可以使用以下命令執行此操作:

python manage。py createsuperuserUsername: daniel Email address: Password: Password (again): Superuser created successfully

由於我們使用的是預設的 auth 使用者,因此您現在可以不使用電子郵件離開超級使用者。

建立超級使用者後,跳轉到瀏覽器並導航到http://localhost:8000/admin。

它會將您重定向到登入頁面,您需要在其中填寫您的憑據(建立使用者時使用的憑據)。

用 Django 構建一個照片共享應用程式

輸入憑據後,我們將可以訪問一個簡單的儀表板,在那裡我們可以開始建立照片。只需點選照片部分,然後點選

新增

按鈕。

用 Django 構建一個照片共享應用程式

下面是填充建立欄位的樣子。

用 Django 構建一個照片共享應用程式

只需拖放即可上傳影象。

用 Django 構建一個照片共享應用程式

點選

儲存

按鈕後,我們將看到一個包含所有建立照片的儀表板。

用 Django 構建一個照片共享應用程式

使用檢視處理 Web 響應

我們已經定義了一個工作應用程式的資料庫架構,甚至使用 Django 管理員建立了一些物件。但是我們還沒有觸及任何網路應用程式最重要的部分——與使用者的互動!

在本節中,我們將構建照片共享應用程式的檢視。

從廣義上講,

檢視

是接受請求並返回響應的 Python 可呼叫(類或函式)。

根據Django 文件,我們應該將所有檢視

views。py

放在每個應用程式內命名的檔案中。這個檔案在我們啟動應用程式時已經建立。

我們有兩種主要的方法來建立檢視:使用基於函式的檢視 (FBV) 或基於類的檢視 (CBV)。

CBV是重用程式碼的最佳方式——透過將 Python 類繼承的強大功能應用到我們的檢視中。

在我們的應用程式中,我們將使用通用檢視,它允許我們透過繼承 Django預構建類來建立簡單的 CRUD 操作。

在開始之前,我們將匯入構建檢視所需的所有內容。開啟

photoapp/views。py

檔案並貼上以下程式碼:

# photoapp/views。pyfrom django。shortcuts import get_object_or_404from django。core。exceptions import PermissionDeniedfrom django。views。generic import ListView, DetailView, CreateView, UpdateView, DeleteViewfrom django。contrib。auth。mixins import LoginRequiredMixin, UserPassesTestMixinfrom django。urls import reverse_lazyfrom 。models import Photo

讓我們看看我們在這裡匯入了什麼:

get_object_or_404

是一種快捷方式,允許我們從資料庫中檢索物件,防止

DoesNotExists

錯誤並引發 HTTP 404 異常。

PermissionDenied

呼叫時引發 HTTP 403 異常。

預構建的

generic

檢視幫助我們用幾行程式碼構建 CRUD 功能。

我們將使用

LoginRequiredMixin

UserPassesTestMixin

來斷言使用者在訪問檢視時具有正確的許可權。

reverse_lazy

在 CBV 中用於將使用者重定向到特定 URL。

我們需要匯入

Photo

以檢索和更新資料庫行(照片物件)。

注意:您可以訪問GitHub 上的views。py檔案。

照片列表檢視

通用列表檢視將幫助我們顯示模型的許多物件。我們將與

DetailView

後者進行比較。

在本節中,我們將構建兩個主要檢視。將

PhotoListView

任何使用者上傳的所有照片作為上下文傳遞,並

PhotoTagListView

以標籤 slug 作為引數來顯示照片。

下面的程式碼定義了

PhotoListView

繼承自

ListView

# photoapp/views。pyclass PhotoListView(ListView): model = Photo template_name = ’photoapp/list。html‘ context_object_name = ’photos‘

首先,我們繼承

ListView

並因此從該類接收所有行為。

請記住,您始終可以在官方 GitHub 儲存庫中檢視任何 Django 類的原始碼。

然後我們定義我們從中讀取資料的模型、我們將使用的模板(我們稍後將構建前端)以及我們可以用來訪問模板中的資料的上下文物件的名稱。

現在,是時候宣告

PhotoTagListView

。 這個檢視有點複雜,因為我們必須使用

get_queryset()

get_context_data()

方法:

# photoapp/views。pyclass PhotoListView(ListView): 。。。class PhotoTagListView(PhotoListView): template_name = ’photoapp/taglist。html‘ # Custom method def get_tag(self): return self。kwargs。get(’tag‘) def get_queryset(self): return self。model。objects。filter(tags__slug=self。get_tag()) def get_context_data(self, **kwargs): context = super()。get_context_data(**kwargs) context[“tag”] = self。get_tag() return context

在這裡,我們繼承了

PhotoListView

。 這意味著我們使用相同的

model

and

context_object_name

,但我們正在更改

template_name

此檢視可能與前一個檢視相同,只是我們處理的是自定義方法。

我們正在建立一個自定義方法

get_tag

來從 Django 將要接受的響應中接收標籤 slug 並返回它。我們這樣做是因為我們將在兩個地方使用該函式。

get_queryset

方法

self。model。objects。all()

預設設定為返回。我們對其進行了修改,使其僅返回帶有傳遞給 URL 的 slug 標記的照片物件。

最後,

get_context_data

修改為還返回傳遞給 URL 的標記。這是因為我們稍後會在模板中顯示它。

照片細節檢視

此檢視是一個簡單的檢視

DetailView

,顯示與唯一照片相關的所有資料。這包括所需照片的標題、描述和標籤:

# photoapp/views。pyclass PhotoListView(ListView): 。。。class PhotoTagListView(PhotoListView): 。。。class PhotoDetailView(DetailView): model = Photo template_name = ’photoapp/detail。html‘ context_object_name = ’photo‘

我們執行的過程與我們對列表檢視所做的過程幾乎相同。唯一的區別是我們返回的是單個物件而不是多個物件,並且使用了不同的模板。

建立照片檢視

此檢視僅允許使用者在登入後建立照片物件。我們不希望匿名使用者能夠將內容上傳到我們的平臺。那會很可怕!

保護Django的這一功能最簡單的方法是建立一個類繼承

CreateView

和LoginRequiredMixin。該

LoginRequiredMixin

測試使用者是否登入如果使用者沒有在,他們將被重定向到登入頁面(我們將在以後的版本)登入:

# photoapp/views。pyclass PhotoListView(ListView): 。。。class PhotoTagListView(PhotoListView): 。。。class PhotoDetailView(DetailView): 。。。class PhotoCreateView(LoginRequiredMixin, CreateView): model = Photo fields = [’title‘, ’description‘, ’image‘, ’tags‘] template_name = ’photoapp/create。html‘ success_url = reverse_lazy(’photo:list‘) def form_valid(self, form): form。instance。submitter = self。request。user return super()。form_valid(form)

按照這種觀點,Django會建立一個表單

title

description

image

tags

領域。

我們也在使用該

sucess_url

屬性。如果照片建立成功,使用者將被重定向到照片儀表板。

如果我們仔細檢視該

form_valid

方法,我們會注意到它將發出請求的使用者設定為照片表單的提交者。

更新和刪除照片檢視

我們希望使用者

只有

在提交者才能修改或刪除照片。

如果我們使用 CBV,處理條件身份驗證可能會很困難。但是,我們可以利用TestMixins來完成此任務。

讓我們建立一個測試 mixin

UserIsSubmitter

來檢查嘗試更新或刪除照片的使用者是否實際提交了它:

# photoapp/views。pyclass PhotoListView(ListView): 。。。class PhotoTagListView(PhotoListView): 。。。class PhotoDetailView(DetailView): 。。。class PhotoCreateView(LoginRequiredMixin, CreateView): 。。。class UserIsSubmitter(UserPassesTestMixin): # Custom method def get_photo(self): return get_object_or_404(Photo, pk=self。kwargs。get(’pk‘)) def test_func(self): if self。request。user。is_authenticated: return self。request。user == self。get_photo()。submitter else: raise PermissionDenied(’Sorry you are not allowed here‘)

首先,我們建立了一個自定義方法

get_photo

,該方法返回一個 Photo 物件,其主鍵在 URL 中指定。如果照片不存在,則會引發 HTTP 404 錯誤。

然後我們定義了測試函式。如果使用者已登入並且是照片提交者,它只會返回 true。

如果使用者未登入,則會引發PermissionDenied異常。

在另一方面,

PhotoUpdateView

並且

PhotoDeleteView

是我們建立的混入的孩子,也

UpdateView

DeleteView

分別為:

# photoapp/views。pyclass PhotoListView(ListView): 。。。class PhotoTagListView(PhotoListView): 。。。class PhotoDetailView(DetailView): 。。。class PhotoCreateView(LoginRequiredMixin, CreateView): 。。。class UserIsSubmitter(UserPassesTestMixin): 。。。class PhotoUpdateView(UserIsSubmitter, UpdateView): template_name = ’photoapp/update。html‘ model = Photo fields = [’title‘, ’description‘, ’tags‘] success_url = reverse_lazy(’photo:list‘)class PhotoDeleteView(UserIsSubmitter, DeleteView): template_name = ’photoapp/delete。html‘ model = Photo success_url = reverse_lazy(’photo:list‘)

PhotoUpdateView

繼承了測試功能

UserIsSubmitter

混入,並從更新功能

UpdateView

fields

屬性定義了使用者將能夠編輯的欄位。我們不希望更改影象,也不希望更改建立日期或提交者。

另一方面,

PhotoDeleteView

也繼承了測試功能,但刪除了照片而不是更新它。

如果一切順利,兩個檢視都將使用者重定向到列表 URL。

這就是所有的意見。現在,讓我們建立一個簡單的身份驗證應用程式並完成專案。

網址模式

我們快到了。我們已經定義了資料庫架構以及使用者將如何建立和更新照片。讓我們看看如何處理照片共享應用程式的 URL 配置。

還記得我們在

urlpatterns

專案開始時建立了一個空變數嗎?是時候填充它了!

首先,讓我們匯入我們需要的所有檢視和函式:

# photoapp/urls。pyfrom django。urls import pathfrom 。views import ( PhotoListView, PhotoTagListView, PhotoDetailView, PhotoCreateView, PhotoUpdateView, PhotoDeleteView)

的路徑函式接收兩個引數,

route

以及

view

,和一個可選的引數,

name

,其被用作所述名稱空間的一部分:

# photoapp/urls。pyapp_name = ’photo‘urlpatterns = [ path(’‘, PhotoListView。as_view(), name=’list‘), path(’tag//‘, PhotoTagListView。as_view(), name=’tag‘), path(’photo//‘, PhotoDetailView。as_view(), name=’detail‘), path(’photo/create/‘, PhotoCreateView。as_view(), name=’create‘), path(’photo//update/‘, PhotoUpdateView。as_view(), name=’update‘), path(’photo//delete/‘, PhotoDeleteView。as_view(), name=’delete‘),]

解釋這個配置,

app_name

變數聲明瞭應用程式的名稱空間。

這意味著無論我們是

reverse

在檢視中使用函式,還是

{% url %}

在模板中使用標籤,我們都需要使用以下名稱空間:

photo:<>

如果您想了解有關 Django URL 排程程式如何工作的更多資訊,請隨時閱讀文件。

認證系統

在這個專案中,我們將使用預設的Django 身份驗證系統。

這是因為我們的主要重點是儘快擁有功能性應用程式。但是,我們將建立一個自定義應用程式,因為我們希望向專案添加註冊功能。

首先,我們建立一個

users

應用程式並執行所有與我們相同的安裝過程

photoapp

python manage。py startapp users# config/settings。pyINSTALLED_APPS = [ 。。。 # 3rd party apps ’taggit‘, # Custom apps ’photoapp‘, ’users‘,]

接下來,我們

urls。py

像使用照片應用程式一樣建立檔案:

cd users/touch urls。py

然後我們在整個專案中包含使用者的 URL:

# config/urls。pyurlpatterns = [ path(’admin/‘, admin。site。urls), # Main app path(’‘, include(’photoapp。urls‘)), # Auth app path(’users/‘, include(’users。urls‘)),] + static(settings。MEDIA_URL, document_root=settings。MEDIA_ROOT)

然後我們寫一個

SignUpView

允許使用者透過站點註冊:

# users/views。pyfrom django。views。generic import CreateViewfrom django。contrib。auth import authenticate, loginfrom django。contrib。auth。forms import UserCreationFormfrom django。urls import reverse_lazyclass SignUpView(CreateView): template_name = ’users/signup。html‘ form_class = UserCreationForm success_url = reverse_lazy(’photo:list‘) def form_valid(self, form): to_return = super()。form_valid(form) user = authenticate( username=form。cleaned_data[“username”], password=form。cleaned_data[“password1”], ) login(self。request, user) return to_return

這個檢視是一個CreateView並與內建的UserCreationForm 一起工作來建立一個新使用者。

form_valid

在將使用者重定向到照片儀表板之前,我們使用該方法登入使用者。

我們將建立一個登入檢視,因為我們想要使用自定義模板來顯示登入頁面。為此,我們將匯入內建

LoginView

函式並從中繼承:

# Previous importsfrom django。contrib。auth。views import LoginViewclass SignUpView(CreateView): 。。。class CustomLoginView(LoginView): template_name = ’users/login。html‘

最後,是時候建立 URL 路由了:

# users/urls。pyfrom django。urls import pathfrom django。contrib。auth。views import LogoutViewfrom 。views import SignUpView, CustomLoginViewapp_name = ’user‘urlpatterns = [ path(’signup/‘, SignUpView。as_view(), name=’signup‘), path(’login/‘, CustomLoginView。as_view(), name=’login‘), path(’logout/‘, LogoutView。as_view(), name=’logout‘),]

再一次,我們正在使用

app_name

變數。所以使用者應用程式的名稱空間將是這樣的:

user:<>

我們正在設定三個 URL。該

signup/

login/

使用我們所建立的自定義檢視,但

logout/

URL是使用Django的內建

LogoutView

在繼續之前,讓我們在

config/settings。py

檔案中配置身份驗證重定向:

# Other settings 。。。USE_TZ = True# Django AuthenticationLOGIN_URL = ’user:login‘LOGIN_REDIRECT_URL = ’photo:list‘LOGOUT_REDIRECT_URL = ’photo:list‘

這告訴 Django 登入 URL 是自定義使用者登入 URL,並且當用戶登入時,他們必須重定向到照片儀表板。

前端

在用 Django 構建後端(使用者看不到的)之後,是時候構建前端(使用者看到的)了。

為此,我們將使用Django 模板語言和Bootstrap 5。這允許我們動態生成 HTML 並根據資料庫的狀態生成不同的輸出。透過使用模板繼承,我們可以節省大量程式碼。使用 Bootstrap 5 意味著我們不會使用靜態檔案。

編寫基本模板

在本節中,我們將構建

base。html

檔案,該檔案是所有其他檔案都將繼承的模板。

為此,我們必須更改位於設定檔案中

DIRS

TEMPLATES

變數內的鍵:

# config/settings。pyTEMPLATES = [ { # Options 。。 ’DIRS‘: [BASE_DIR / ’templates‘], ’APP_DIRS‘: True, # More options },]

Django 的預設行為是在

templates/

每個應用程式的資料夾中搜索模板檔案。

例如,可以在 中找到照片共享應用程式的模板

photoapp/templates

。使用者應用程式 (

users/templates

) 也是如此。

透過將

DIRS

鍵分配給

[BASE_DIR / ’templates‘]

,我們告訴 Django 也在名為 的資料夾中搜索模板

templates

templates

在專案的根目錄(

manage。py

檔案所在的位置)建立一個目錄並觸控

base。html

navbar。html

模板:

ls# manage。pymkdir templates && cd templatestouch base。html navbar。html

總結我們專案的模板可以在這三個目錄中的任何一箇中找到:

。├── photoapp│ └── templates│ └── photoapp├── templates└── users └── templates └── users

請記住,您可以隨時檢視GitHub 儲存庫上的專案結構。

base。html

模板中,我們將設定基本的 HTML 結構、一些元標記、引導 CDN 的連結以及其他模板將使用的塊:

<!—— templates/base。html ——><!DOCTYPE html> Django Photo Sharing app {% include ’navbar。html‘ %}

{% block body %} {% endblock body %}

{% include %}

標籤(顧名思義)包括內選定模板的所有程式碼

base。html

檔案。

因此,存在於 中的所有程式碼

navbar。html

都將放置在正文的開頭。

注意:這裡有很多 HTML 和 Bootstrap。隨意複製所有內容,因為這不是本教程的主要重點。

下面是導航欄的 HTML 模板程式碼。此導航欄將包含一些邏輯以顯示登入頁面的連結,以防使用者未登入:

<!—— templates/navbar。html ——>

以下是使用者登入時模板的顯示方式。

用 Django 構建一個照片共享應用程式

以下是使用者未登入時顯示的內容。

用 Django 構建一個照片共享應用程式

如果您的瀏覽器出現錯誤,請不要擔心。我們還沒有構建照片共享模板。

照片分享模板

我們將編寫照片共享應用程式中所需的所有檔案。這包括用於完成 CRUD 操作的模板。

所有這些模板都將擴充套件

base。html

模板並將位於

photoapp/templates/photoapp

目錄中。

但在使用模板中的表單之前,我們將使用Django 脆皮表單來風格化我們的應用程式:

pip install django-crispy-forms

再一次,

crispy_forms

是一個 Django 應用程式,我們需要將它包含在

INSTALLED_APPS

列表中:

# config/settings。pyINSTALLED_APPS = [ 。。。 # 3rd party apps ’taggit‘, ’crispy_forms‘, # Custom apps ’photoapp‘, ’users‘,]# Indicates the frontend framework django crispy forms will useCRISPY_TEMPLATE_PACK = ’bootstrap4‘

我們使用 Bootstrap 4 的模板包,因為 Bootstrap 表單類在第 4 版和第 5 版之間相容(在撰寫本文時)。

您可能還記得我們在 上使用了以下模板名稱

photoapp/views。py

’photoapp/list。html‘ ’photoapp/taglist。html‘ ’photoapp/detail。html‘ ’photoapp/create。html‘ ’photoapp/update。html‘ ’photoapp/delete。html‘

這意味著所有這些模板都將位於

photoapp/templates/photoapp

要建立此資料夾,請轉到照片共享應用程式並建立一個目錄

templates/

,然後在其中建立另一個名為 的資料夾

photoapp/

cd photoapp/mkdir -p templates/photoapp/cd templates/photoapp/

現在建立我們在檢視上宣告的所有模板:

touch list。html taglist。html detail。html create。html update。html delete。html

列出模板

list。html

會從繼承

base。html

模板,因此所有的HTML結構將出現在原始碼中:

<!—— photoapp/templates/photoapp/list。html ——>{% extends ’base。html‘ %} {% block body %}

{% for photo in photos %} {% endfor %}
{% endblock body %}

我們使用模板標籤for loop,它迭代照片並用 Bootstrap 行和列顯示它們。

不要忘記在 Django 管理中建立多個照片物件。

訪問localhost:8000/以檢視模板的外觀。

用 Django 構建一個照片共享應用程式

taglist。html

模板將從繼承

list。html

剛剛建立我們:

<!—— photoapp/templates/photoapp/taglist。html ——>{% extends ’photoapp/list。html‘ %}{% block body %}

Photos with the tag {{tag}}

{{ block。super }}{% endblock body %}

我們只是稍微修改了這個模板。這就是我們呼叫 的原因

{{ block。super }}

,它包含

list。html

模板主體塊中的所有程式碼。

code

在繼續之前建立幾個帶有標籤的物件。

轉到localhost:8000/tag/code/,其中程式碼是標籤的 slug。

用 Django 構建一個照片共享應用程式

請記住,該

taglist

URL 具有以下形式:

’localhost://8000/tag//‘

這裡,

指的是標籤的名稱。

細節照片模板

讓我們編輯

detail。html

模板,以便能夠詳細檢視我們的照片:

<!—— photoapp/templates/photoapp/detail。html ——>{% extends ’base。html‘ %} {% block body %}

{{ photo。title }}

Uploaded on: {{photo。created}}
By {{photo。submitter。username}}

{% if user == photo。submitter %}

Update Delete

{% endif %}
用 Django 構建一個照片共享應用程式

More about this photo:

{{ photo。description }}

{% endblock body %}

在深入研究功能之前,讓我們看看模板的外觀。按照localhost:8000/photo/1。

用 Django 構建一個照片共享應用程式

在這裡,我們透過點符號從模板訪問照片屬性。那是因為

photo。submitter。username

等於

daniel

我們實現了一些邏輯來顯示更新或刪除照片的連結,以防使用者也是提交者。

最後,我們顯示迭代的照片的所有標籤

photo。tags。all

建立照片模板

下一個模板將包含一個清晰的表單,因此我們不必手動顯示錶單。Django 會為我們做到這一點:

<!—— photoapp/templates/photoapp/create。html ——>{% extends ’base。html‘ %}{% load crispy_forms_tags %}{% block body %}

Add photo

{% csrf_token %} {{ form|crispy }}
{% endblock body %}

每次我們使用脆皮表單時,我們都需要載入帶有

{% load crispy_forms_tags %}

包含 非常重要

enctype=“multipart/form-data”

,因為如果我們不包含,檔案將不會被上傳。這是對在 forms 中使用它的影響的一個很好的迴應。

每個 Django 表單都必須包含一個

{% csrf_token %}

inside。您可以在“跨站點請求偽造保護”頁面上了解有關此標籤的更多資訊。

請注意我們如何簡單地使用

{{form|crispy}}

。 如果您知道 Linux 中的管道是什麼,我們正是透過將檢視提供的表單重定向到

crispy

過濾器來做到這一點的。

轉到新增照片URL 以檢查照片是否已上傳。

用 Django 構建一個照片共享應用程式

如果一切順利,我們應該會在儀表板中看到新增的照片。

用 Django 構建一個照片共享應用程式

更新和刪除模板

在前往身份驗證模板之前,讓我們完成照片共享應用程式。

下面的

update

模板是一個簡單的形式,其中使用者可以更新

title

description

tags

照片的:

<!—— photoapp/templates/photoapp/update。html ——>{% extends ’base。html‘ %}{% load crispy_forms_tags %}{% block body %}

Edit photo {{photo}}

{% csrf_token %} {{ form|crispy }}
{% endblock body %}

我們可以看看它在localhost:8000/photo/1/update 上的樣子。

用 Django 構建一個照片共享應用程式

我們還希望為使用者提供刪除照片的選項。使用以下模板,他們可以決定是否刪除照片:

<!—— photoapp/templates/photoapp/delete。html ——>{% extends ’base。html‘ %} {% block body %}

You are going to delete: “{{ photo }}

Are you sure, you want to delete the photo ?

{% csrf_token %}

This action is irreversible

{% endblock body %}

刪除頁面將如下所示。

用 Django 構建一個照片共享應用程式

如果使用者決定取消,他們將被重定向到該照片的詳細資訊頁面。

使用者認證模板

本節的目的是編寫與身份驗證相關的所有模板。我們將編寫

signup。html

login。html

模板。

與照片共享應用程式類似,以下所有模板都將位於雙資料夾結構中:

users/templates/users/

進入使用者應用程式並建立模板所在的資料夾:

# Enter to the project root directorycd 。。/。。/。。/cd users/mkdir -p templates/users/

在該資料夾中建立註冊和登入模板檔案:

cd templates/users/touch signup。html login。html

下面是模板的模板程式碼

signup。html

<!—— users/templates/users/signup。html ——>{% extends ’base。html‘ %} {% load crispy_forms_tags %}{% block body %}

{% csrf_token %} {{ form|crispy }}
{% comment %} Already Registered {% endcomment %}

Already Registered? Login

{% endblock body %}

我們可以在瀏覽器中檢視localhost:8000/users/signup。

用 Django 構建一個照片共享應用程式

最後但並非最不重要的是,編寫登入模板:

<!—— users/templates/users/login。html ——>{% extends ’base。html‘ %} {% load crispy_forms_tags %}{% block body %}

{% csrf_token %} {{ form|crispy }}
{% comment %} Already Registered {% endcomment %}

Don’t have an account? Create account

{% endblock body %}

用 Django 構建一個照片共享應用程式

Django 模板允許我們透過多次重用相同的 HTML 來節省大量時間。只需想象一遍又一遍地複製和貼上相同的 HTML 會花費多少時間。

完美的!現在你有一個完全可用的應用程式。嘗試使用它、修改它,甚至擴充套件它的功能。

加起來

恭喜!您已經從頭開始建立了一個全棧專案。

Django 是最常用的 Python Web 框架。它允許您快速構建複雜的 Web 應用程式。

它具有許多可加速開發過程的內建功能,例如伺服器端模板渲染、基於類的檢視和模型表單。

Django 還提供了幾個第三方包,讓您可以選擇使用其他人的應用程式。例如,該專案使用 Django taggit 和 Django 脆皮形式。

在本教程中,我們介紹了以下內容:

Django CRUD 操作

Django 內建身份驗證系統

如何在 Django 中管理媒體檔案

使用 Django taggit 對內容進行分類

用脆皮形式實現 Django 表單

使用 Bootstrap 5 編寫 Django 模板

最好的方法是不斷學習和推進它,將您獲得的知識應用到新的和具有挑戰性的專案中。祝你好運!