Django–02模型與站點管理
Part 2: Models and the admin site
本教程承接Django–01的內容。我們將設置數據庫、創建你的第一個模型,并快速了解 Django 自動生成的管理站點。
文章目錄
- Django--02模型與站點管理
- 前言
- 一、設置數據庫
- 1.1 參考文檔鏈接
- 1.2 默認設置
- 1.3 極簡主義者
- 二、創建模型
- 2.1 設計理念
- 三、激活模型
- 3.1 設計理念
- 四、調用API
- 五、介紹 Django 管理界面
- 5.1 設計理念
- 5.2 創建管理員用戶
- 5.3 進入管理站點
- 5.4 讓投票應用在管理界面中可修改
- 5.5 探索免費的管理功能
前言
本系列博客內容全部在windows系統實現,本專欄以Django官方文檔為基礎,從零開始,對官方文檔翻譯+修改。例如,運行圖、效果圖添加,不好理解的地方詳細講解,適合0基礎學習。
它包含以下內容
Part 1: Requests and responses
Part 2: Models and the admin site
Part 3: Views and templates
Part 4: Forms and generic views
Part 5: Testing
Part 6: Static files
Part 7: Customizing the admin site
Part 8: Adding third-party packages
一、設置數據庫
1.1 參考文檔鏈接
https://docs.djangoproject.com/en/5.2/topics/install/#database-installation
1.2 默認設置
現在,打開mysite/settings.py。這是一個普通的 Python 模塊,其中包含表示 Django 設置的模塊級變量。
默認情況下,DATABASES配置使用 SQLite。如果你是數據庫新手,或者只是想嘗試 Django,這是最簡單的選擇。SQLite
已包含在 Python 中,因此你無需安裝其他任何東西來支持數據庫。但是,當開始你的第一個實際項目時,你可能希望使用更具可擴展性的數據庫(如
PostgreSQL),以避免日后切換數據庫帶來的麻煩。 如果你想使用其他數據庫,請查看相關細節以自定義并運行你的數據庫。
在編輯mysite/settings.py時,將TIME_ZONE設置為你的時區。中國北京設置為"Asia/Shanghai"
另外,注意文件頂部的INSTALLED_APPS設置。它包含了在這個 Django 實例中激活的所有 Django
應用的名稱。應用可以在多個項目中使用,你還可以打包并分發它們,供其他人在其項目中使用。
默認情況下,INSTALLED_APPS包含以下應用,所有這些應用都隨 Django 一起提供:
django.contrib.admin – 管理站點。你很快就會用到它。
django.contrib.auth – 認證系統。
django.contrib.contenttypes – 內容類型框架。
django.contrib.sessions – 會話框架。
django.contrib.messages – 消息框架。
django.contrib.staticfiles – 管理靜態文件的框架。
這些應用默認包含在內,是為了方便處理常見場景。
不過,這些應用中有些需要至少一個數據庫表才能使用,因此在使用它們之前,我們需要在數據庫中創建這些表。為此,運行以下命令:
py manage.py migrate
migrate命令會查看INSTALLED_APPS設置,并根據mysite/settings.py文件中的數據庫設置以及應用附帶的數據庫遷移文件(我們稍后會介紹),創建所有必要的數據庫表。你會看到它應用的每個遷移的相關消息。如果感興趣,可以運行數據庫的命令行客戶端,輸入\dt(PostgreSQL)、SHOW TABLES;(MariaDB、MySQL)、.tables(SQLite)或SELECT TABLE_NAME FROM USER_TABLES;(Oracle)來查看 Django 創建的表。
1.3 極簡主義者
如前所述,默認應用是為常見場景準備的,但并非所有人都需要它們。如果不需要其中任何一個或全部應用,可以在運行migrate之前,從INSTALLED_APPS中注釋或刪除相應的行。migrate命令只會為INSTALLED_APPS中的應用運行遷移。
二、創建模型
現在我們將定義模型 —— 本質上是你的數據庫布局,附帶額外的元數據。
2.1 設計理念
模型是關于數據的唯一、權威的信息來源。它包含你要存儲的數據的基本字段和行為。Django 遵循 DRY 原則(Don’t Repeat Yourself,即 “不要重復自己”)。目標是在一個地方定義數據模型,并從中自動派生其他內容。
這包括遷移 —— 與 Ruby On Rails 等框架不同,遷移完全源自你的模型文件,本質上是 Django 可以逐步執行的歷史記錄,用于將數據庫架構更新為與當前模型匹配的狀態。
在我們的投票應用中,我們將創建兩個模型:Question和Choice。Question包含一個問題文本和一個發布日期。Choice包含兩個字段:選項文本和投票計數。每個Choice都與一個Question相關聯。
這些概念由 Python 類表示。編輯polls/models.py文件,使其如下所示:
from django.db import modelsclass Question(models.Model):question_text = models.CharField(max_length=200)pub_date = models.DateTimeField("date published")class Choice(models.Model):question = models.ForeignKey(Question, on_delete=models.CASCADE)choice_text = models.CharField(max_length=200)votes = models.IntegerField(default=0)
這里,每個模型都由一個繼承自django.db.models.Model的類表示。每個模型都有多個類變量,每個類變量都代表模型中的一個數據庫字段。
每個字段由Field類的實例表示 —— 例如,CharField用于字符字段,DateTimeField用于日期時間字段。這告訴 Django 每個字段存儲的數據類型。
每個Field實例的名稱(例如question_text或pub_date)是字段的機器可讀名稱。你會在 Python 代碼中使用這個值,數據庫也會將其用作列名。
你可以為Field提供一個可選的第一個位置參數,指定一個人類可讀的名稱。它用于 Django 的一些自省部分,同時也起到文檔的作用。如果沒有提供這個字段,Django 將使用機器可讀的名稱。在這個例子中,我們只為Question.pub_date定義了人類可讀的名稱。對于該模型中的所有其他字段,字段的機器可讀名稱足以作為其人類可讀名稱。
有些Field類有必需的參數。例如,CharField要求你給它一個max_length。這不僅用于數據庫架構,還用于驗證,我們很快就會看到。
Field還可以有各種可選參數;在這種情況下,我們將votes的default值設置為 0。
最后,注意使用ForeignKey定義了一個關系。這告訴 Django 每個Choice都與一個Question相關聯。Django 支持所有常見的數據庫關系:多對一、多對多和一對一。
三、激活模型
那一小段模型代碼為 Django 提供了大量信息。有了它,Django 能夠:
為此應用程序創建數據庫架構 ( statements)。CREATE TABLE創建一個 Python 數據庫訪問 API,用于訪問對象Question和Choice。
但首先我們需要告訴我們的項目應用程序已安裝polls
3.1 設計理念
Django 應用是 “可插拔的”:你可以在多個項目中使用一個應用,并且可以分發應用,因為它們不必綁定到特定的 Django 安裝。
要將應用包含在我們的項目中,我們需要在INSTALLED_APPS設置中添加對其配置類的引用。PollsConfig類位于polls/apps.py文件中,因此其 dotted 路徑是’polls.apps.PollsConfig’。編輯mysite/settings.py文件,將該 dotted 路徑添加到INSTALLED_APPS設置中。修改后如下所示:
類似導包
現在 Django 知道要包含 “polls” 應用了。讓我們運行另一個命令:
py manage.py makemigrations polls
會看到下面的內容
- 通過運行makemigmigrations,你告訴Django你已經對你的模型做了一些改變(在這個例子中,你已經做了一些新的),并且你想把這些改變作為遷移存儲起來。
- 遷移是Django將更改存儲到模型(以及數據庫模式)的方式——它們是磁盤上的文件。 如果愿意,您可以閱讀新模型的遷移;它是文件polls/migrations/eee1_initial.py。
- 別擔心,你不需要每次Django創建一個文件都去閱讀它們,但是如果你想手動調整Django的更改方式,它們被設計為可編輯的。
有一個命令可以為你運行遷移并自動管理數據庫架構 —— 那就是migrate,我們稍后會用到它 —— 但首先,讓我們看看這個遷移會運行什么 SQL。sqlmigrate命令接受遷移名稱并返回它們的 SQL:
py manage.py sqlmigrate polls 0001
請注意以下幾點:
- 具體的輸出結果會因您所使用的數據庫而有所不同。上述示例是針對 PostgreSQL 系統生成的。
- 表名會通過將應用程序名稱(“投票”)與模型問題及選項的首字母小寫形式相結合的方式自動生成。(您可以更改此設置。)
- 主鍵(標識符)會自動添加。(您也可以對其進行更改。)
- 按照慣例,Django會在外鍵字段名稱后加上“_id”(當然,您也可以對其進行修改)。
- 外鍵關系通過“FOREIGNKEY”約束得以明確表示。無需擔心“可撤銷”部分的內容;它所表達的意思是… PostgreSQL在事務結束前不會強制執行外鍵約束。
- 它會根據您所使用的數據庫進行定制,因此諸如自動遞增(MySQL)、大整數主鍵(默認生成且自動作為標識符,PostgreSQL)或整數主鍵自動遞增(SQLite)等特定于數據庫的字段類型都會自動為您處理好。對于字段名稱的引號使用方式也是如此——例如,使用雙引號或單引號。
- “sqlmigrate”命令實際上并不會在您的數據庫上執行遷移操作——相反,它會將遷移內容打印到屏幕上,以便您能夠查看 Django認為需要執行的 SQL 語句。這對于檢查 Django 將要執行的操作非常有用,或者如果您有需要 SQL腳本來完成更改的數據庫管理員,它也非常適用。
如果您感興趣的話,還可以運行python manage.pycheck
命令;此命令可檢查您的項目中是否存在任何問題,且無需進行遷移操作或修改數據庫。
現在,再次運行“遷移”操作,以便在您的數據庫中創建那些模型表:
py manage.py migrate
“migrate”命令會獲取所有尚未應用的遷移文件(Django 通過數據庫中一個名為“django migrations”的特殊表來記錄哪些遷移已應用)并將其應用于您的數據庫——本質上就是將您對模型所做的更改與數據庫中的架構進行同步。
遷移功能非常強大,能夠讓您在項目開發過程中根據需要不斷修改模型,而無需刪除現有的數據庫或表,然后重新創建新的——它專門用于在不丟失數據的情況下實時升級數據庫。
現在請記住進行模型更改的三個步驟指南:
- 修改你的模型(在 models.py 文件中)。
- 運行命令以針對這些更改創建遷移文件。
python manage.py makemigrations
- 運行“python manage.pymigrate”命令以將這些更改應用到數據庫中。
之所以會有專門的命令來執行和應用遷移操作,是因為您會將遷移操作提交到版本控制系統中,并將其與應用程序一同發布;這些遷移不僅能讓您的開發工作更加便捷,而且還能被其他開發人員使用,并在生產環境中發揮作用。
四、調用API
現在,讓我們進入交互式 Python shell,體驗一下 Django 提供的免費 API。要調用 Python shell,請使用以下命令:
py manage.py shell
進入 shell 后,探索數據庫 API:
我們使用這個命令而不是簡單地輸入 “python”,是因為manage.py會設置DJANGO_SETTINGS_MODULE環境變量,該變量為 Django 提供了 Python 導入路徑到你的mysite/settings.py文件。默認情況下,shell命令會自動導入你INSTALLED_APPS中的模型。
進入 shell 后,探索數據庫 API:
# 目前系統中還沒有問題。
>>> Question.objects.all()
<QuerySet []># 默認設置中啟用了時區支持,因此
# Django期望pub_date是一個帶tzinfo的datetime。使用timezone.now()
# 而不是datetime.datetime.now(),它會處理正確的時區。
>>> from django.utils import timezone
>>> q = Question(question_text="What's new?", pub_date=timezone.now())# 要將對象保存到數據庫中,必須顯式調用save()。
>>> q.save()# 現在它有了一個ID。
>>> q.id
1# 通過Python屬性訪問模型字段值。
>>> q.question_text
"What's new?"
>>> q.pub_date
datetime.datetime(2012, 2, 26, 13, 0, 0, 775217, tzinfo=datetime.timezone.utc)# 通過更改屬性值,然后調用save()來修改值。
>>> q.question_text = "What's up?"
>>> q.save()# objects.all()顯示數據庫中的所有問題。
>>> Question.objects.all()
<QuerySet [<Question: Question object (1)>]>
<Question: Question object (1)> 并不是這個對象的有用表示。讓我們通過編輯Question模型(在polls/models.py文件中)并為Question和Choice添加__str__()方法來修復這個問題:
# polls/models.py
from django.db import modelsclass Question(models.Model):# ...def __str__(self):return self.question_textclass Choice(models.Model):# ...def __str__(self):return self.choice_text
為模型添加__str__()方法非常重要,不僅是為了在處理交互式提示時方便自己,還因為對象的表示會在 Django 自動生成的管理界面中使用。
我們還可以為這個模型添加一個自定義方法:
# polls/models.py
import datetime
from django.db import models
from django.utils import timezoneclass Question(models.Model):# ...def was_published_recently(self):return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
總而言之,把polls/models.py修改為下面的樣子
import datetimefrom django.db import models
from django.utils import timezoneclass Question(models.Model):question_text = models.CharField(max_length=200)pub_date = models.DateTimeField("date published")def __str__(self):return self.question_textdef was_published_recently(self):return self.pub_date >= timezone.now() - datetime.timedelta(days=1)class Choice(models.Model):question = models.ForeignKey(Question, on_delete=models.CASCADE)choice_text = models.CharField(max_length=200)votes = models.IntegerField(default=0)def __str__(self):return self.choice_text# Create your models here.
保存這些更改,然后通過運行python manage.py shell再次啟動新的 Python 交互式 shell:
# 確保我們添加的__str__()方法起作用了。
>>> Question.objects.all()
<QuerySet [<Question: What's up?>]># Django提供了豐富的數據庫查詢API,完全由
# 關鍵字參數驅動。
>>> Question.objects.filter(id=1)
<QuerySet [<Question: What's up?>]>
>>> Question.objects.filter(question_text__startswith="What")
<QuerySet [<Question: What's up?>]># 獲取今年發布的問題。
>>> from django.utils import timezone
>>> current_year = timezone.now().year
>>> Question.objects.get(pub_date__year=current_year)
<Question: What's up?># 請求一個不存在的ID,這會引發異常。
>>> Question.objects.get(id=2)
Traceback (most recent call last):...
DoesNotExist: Question matching query does not exist.# 通過主鍵查找是最常見的情況,所以Django為精確的主鍵查找提供了一個快捷方式。
# 以下等同于Question.objects.get(id=1)。
>>> Question.objects.get(pk=1)
<Question: What's up?># 確保我們的自定義方法起作用了。
>>> q = Question.objects.get(pk=1)
>>> q.was_published_recently()
True# 給這個問題添加幾個選項。create調用會構造一個新的
# Choice對象,執行INSERT語句,將選項添加到可用選項集中
# 并返回新的Choice對象。Django創建一個集合(定義為"choice_set")來保存外鍵關系的"另一端"
# (例如,一個問題的選項),可以通過API訪問。
>>> q = Question.objects.get(pk=1)# 顯示相關對象集中的任何選項——目前還沒有。
>>> q.choice_set.all()
<QuerySet []># 創建三個選項。
>>> q.choice_set.create(choice_text="Not much", votes=0)
<Choice: Not much>
>>> q.choice_set.create(choice_text="The sky", votes=0)
<Choice: The sky>
>>> c = q.choice_set.create(choice_text="Just hacking again", votes=0)# Choice對象可以通過API訪問它們相關的Question對象。
>>> c.question
<Question: What's up?># 反之亦然:Question對象可以訪問Choice對象。
>>> q.choice_set.all()
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>
>>> q.choice_set.count()
3# API可以根據需要自動跟蹤關系。
# 使用雙下劃線分隔關系。
# 這可以深入多個層級;沒有限制。
# 查找所有在今年發布的問題的選項
# (重用我們上面創建的'current_year'變量)。
>>> Choice.objects.filter(question__pub_date__year=current_year)
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]># 讓我們刪除其中一個選項。使用delete()方法。
>>> c = q.choice_set.filter(choice_text__startswith="Just hacking")
>>> c.delete()
五、介紹 Django 管理界面
5.1 設計理念
為員工或客戶生成用于添加、修改和刪除內容的管理站點是一項繁瑣的工作,不需要太多創造力。因此,Django 完全自動化了模型管理界面的創建。
Django 是在新聞編輯室環境中編寫的,“內容發布者” 和 “公共” 站點之間有明確的區分。站點管理員使用該系統添加新聞報道、事件、體育比分等,這些內容會顯示在公共站點上。Django 解決了為站點管理員創建統一內容編輯界面的問題。
管理界面并非為站點訪問者設計,而是為站點管理者設計的。
5.2 創建管理員用戶
首先,我們需要創建一個可以登錄管理站點的用戶。運行以下命令:
py manage.py createsuperuser
輸入你想要的用戶名并按回車。
Username: admin
然后會提示你輸入所需的電子郵件地址:
Email address: admin@example.com
最后一步是輸入你的密碼。系統會要求你輸入兩次密碼,第二次是為了確認第一次輸入的密碼。
Password: **********
Password (again): *********
Superuser created successfully.
現在,打開 Web 瀏覽器,訪問你本地域名的 “/admin/” 路徑 —— 例如,http://127.0.0.1:8000/admin/。你應該會看到管理界面的登錄屏幕:
5.3 進入管理站點
現在,嘗試使用你在前面步驟中創建的超級用戶賬戶登錄。你應該會看到 Django 管理索引頁面:
你應該會看到幾種可編輯的內容:組和用戶。它們由django.contrib.auth提供,這是 Django 附帶的認證框架。
5.4 讓投票應用在管理界面中可修改
但是我們的投票應用在哪里呢?它沒有顯示在管理索引頁面上。
只需要再做一件事:我們需要告訴管理界面Question對象有一個管理界面。為此,打開polls/admin.py文件,編輯它如下:
# polls/admin.py
from django.contrib import adminfrom .models import Questionadmin.site.register(Question)
5.5 探索免費的管理功能
現在我們已經注冊了Question,Django 知道它應該顯示在管理索引頁面上:
點擊 “Questions”。現在你在問題的 “更改列表” 頁面。這個頁面顯示數據庫中的所有問題,讓你可以選擇一個進行修改。這里有我們之前創建的 “What’s up?” 問題:
請注意以下幾點:
- 表單是根據Question模型自動生成的。
- 不同的模型字段類型(DateTimeField、CharField)對應相應的 HTML輸入控件。每種類型的字段都知道如何在 Django 管理界面中顯示自己。
- 每個DateTimeField都有免費的 JavaScript快捷方式。日期有 “今天” 快捷方式和日歷彈窗,時間有 “現在” 快捷方式和一個方便的常用時間彈窗。
- 頁面底部為你提供了幾個選項:
1.保存(Save)—— 保存更改并返回到該類型對象的更改列表頁面。
2. 保存并繼續編輯(Save and continue editing)—— 保存更改并重新加載該對象的管理頁面。
3. 保存并添加另一個(Save and add another)——保存更改并加載該類型對象的新空白表單。
4. 刪除(Delete)—— 顯示刪除確認頁面。
如果 “Date published” 的值與你在教程 1 中創建問題的時間不匹配,可能是因為你忘記設置TIME_ZONE的正確值。更改它,重新加載頁面,檢查是否顯示正確的值。
通過點擊 “Today” 和 “Now” 快捷方式更改 “Date published”。然后點擊 “Save and continue editing”。然后點擊右上角的 “History”。你會看到一個頁面,列出通過 Django 管理界面對此對象所做的所有更改,包括更改的時間戳和做出更改的用戶名: