Django中文文檔
編寫你的第一個Django應用程序,第1部分
本教程中,我們將引導您完成基本輪詢應用程序的創建。
它由兩部分組成:
一個公共站點,允許人們查看民意調查並在其中投票。
一個管理站點,允許您添加,更改和刪除民意調查。
我們假設你已經安裝了Django。您可以通過在shell提示符中運行以下命令(由$前綴表示)來告知Django已安裝以及哪個版本:
py -m django --version
通過在pycharm下方的Terminal裏輸入這段代碼,或者在管理員命令提示符輸入即可查詢你的Django版本:如果成功就會先顯示類似如下字樣:
創建項目
如果這是你第一次使用Django,你將不得不處理一些初始設置。也就是說,您需要自動生成一些建立Django 項目的代碼- Django實例的設置集合,包括數據庫配置,Django特定選項和特定於應用程序的設置。
從命令行cd進入要存儲代碼的目錄,然後運行以下命令:
django-admin startproject mysit
此時在當前目錄就算創建好了一個項目,項目名字叫:mysit
打開mysite文件夾就會發現裏面有幾個自帶文件:
mysite/
manage.py
mysite/
__init__.py
settings.py
urls.py
wsgi.py
這就是樹狀圖:
這些文件是:
外部mysite/根目錄只是項目的容器。它的名字對Django來說無關緊要; 你可以將它重命名爲你喜歡的任何東西。
manage.py:一個命令行實用程序,允許您以各種方式與此Django項目進行交互。您可以manage.py在django-admin和manage.py中閱讀有關的所有詳細信息 。
內部mysite/目錄是項目的實際Python包。它的名稱是您需要用來導入其中任何內容的Python包名稱(例如mysite.urls)。
mysite/init.py:一個空文件,告訴Python該目錄應該被視爲Python包。如果您是Python初學者,請閱讀官方Python文檔中有關包的更多信息。
mysite/settings.py:此Django項目的設置/配置。 Django設置將告訴您有關設置如何工作的所有信息。
mysite/urls.py:這個Django項目的URL聲明; 您的Django支持的站點的“目錄”。您可以在URL調度程序中閱讀有關URL的更多信息。
mysite/wsgi.py:與WSGI兼容的Web服務器的入口點,用於爲您的項目提供服務。有關更多詳細信息,請參閱如何使用WSGI進行部署。
開發服務器
讓我們驗證您的Django項目是否有效。mysite如果尚未更改到外部目錄,請運行以下命令:
py manage.py runserver
輸入上面的代碼後,命令行就會顯示:
Performing system checks...
System check identified no issues (0 silenced).
You have unapplied migrations; your app may not work properly until they are applied.
Run 'python manage.py migrate' to apply them.
December 21, 2018 - 16:08:11
Django version 1.9.7, using settings 'todo.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.
此時已經啓動了Django開發服務器,這是一個純粹的用這是一個純粹用Python編寫的輕量級Web服務器。我們已經將它包含在Django中,因此您可以快速開發,而無需處理配置生產服務器(如Apache),直到您準備好進行生產。
現在是時候注意了:不要在類似生產環境的任何地方使用這個服務器。它僅用於開發時使用。(我們的業務是製作Web框架,而不是Web服務器。)
現在服務器正在運行,請使用瀏覽器訪問 http://127.0.0.1:8000/。你會看到一個“祝賀!”頁面,火箭起飛。有效!
更換端口
默認情況下,runserver 命令會將服務器設置爲監聽本機內部 IP 的 8000 端口。
如果你想更換服務器的監聽端口,請使用命令行參數。舉個例子,下面的命令會使服務器監聽 8080 端口:
python manage.py runserver 8080
如果你想要修改服務器監聽的IP,在端口之前輸入新的。比如,爲了監聽所有服務器的公開IP(這你運行 Vagrant 或想要向網絡上的其它電腦展示你的成果時很有用),使用:
python manage.py runserver 0:8000
創建投票應用
現在你的開發環境——這個“項目” ——已經配置好了,你可以開始幹活了。
在 Django 中,每一個應用都是一個 Python 包,並且遵循着相同的約定。Django 自帶一個工具,可以幫你生成應用的基礎目錄結構,這樣你就能專心寫代碼,而不是創建目錄了。
你的應用可以存放在任何 Python path 中定義的路徑。在這個教程中,我們將在你的 manage.py 同級目錄下創建投票應用。這樣它就可以作爲頂級模塊導入,而不是 mysite 的子模塊。
請確定你現在處於 manage.py 所在的目錄下,然後運行這行命令來創建一個應用:
python manage.py startapp polls
這將會創建一個 polls 目錄,它的目錄結構大致如下:
polls/
init.py
admin.py
apps.py
migrations/
init.py
models.py
tests.py
views.py
這個目錄結構包括了投票應用的全部內容
編寫第一個視圖
讓我們開始編寫第一個視圖吧。打開 polls/views.py,把下面這些 Python 代碼輸入進去:
polls/views.py ps :這是文件路徑
from django.http import HttpResponse
def index(request):
return HttpResponse("Hello, world. You're at the polls index.")
這是 Django 中最簡單的視圖。如果想看見效果,我們需要將一個 URL 映射到它——這就是我們需要 URLconf 的原因了。
爲了創建 URLconf,請在 polls 目錄裏新建一個 urls.py 文件。你的應用目錄現在看起來應該是這樣:
polls/
__init__.py
admin.py
apps.py
migrations/
__init__.py
models.py
tests.py
urls.py
views.py
在 polls/urls.py 中,輸入如下代碼:
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
]
下一步是要在根 URLconf 文件中指定我們創建的 polls.urls 模塊。在 mysite/urls.py 文件的 urlpatterns 列表裏插入一個 include(), 如下:
mysite/urls.py
from django.contrib import admin
from django.urls import include, path
urlpatterns = [
path('polls/', include('polls.urls')),
path('admin/', admin.site.urls),
]
你現在把 index 視圖添加進了 URLconf。可以驗證是否正常工作,運行下面的命令:
python manage.py runserver
編寫你的第一個 Django 應用,第 2 部分
課外
編輯 mysite/settings.py 文件前,先設置 TIME_ZONE 爲你自己時區。
中國的一般默認爲上海:
TIME_ZONE = 'Asia/Shanghai'
但是TIME_ZONE官方默認是UTC
數據庫配置
現在,打開 mysite/settings.py 。這是個包含了 Django 項目設置的 Python 模塊。通常,這個配置文件使用 SQLite 作爲默認數據庫。如果你不熟悉數據庫,或者只是想嘗試下 Django,這是最簡單的選擇。Python 內置 SQLite,所以你無需安裝額外東西來使用它。當你開始一個真正的項目時,你可能更傾向使用一個更具擴展性的數據庫,例如 PostgreSQL,避免中途切換數據庫這個令人頭疼的問題。
如果你想使用其他數據庫,你需要安裝合適的 database bindings ,然後改變設置文件中 DATABASES ‘default’ 項目中的一些鍵值:
ENGINE – 可選值有 ‘django.db.backends.sqlite3’,‘django.db.backends.postgresql’,‘django.db.backends.mysql’,或 ‘django.db.backends.oracle’。其它 可用後端。
NAME - 數據庫的名稱。如果使用的是 SQLite,數據庫將是你電腦上的一個文件,在這種情況下, NAME 應該是此文件的絕對路徑,包括文件名。默認值 os.path.join(BASE_DIR, ‘db.sqlite3’) 將會把數據庫文件儲存在項目的根目錄。
如果你不使用 SQLite,則必須添加一些額外設置,比如 USER 、 PASSWORD 、 HOST 等等。想了解更多數據庫設置方面的內容,請看文檔:DATABASES 。
settings爲配置文件
默認開啓的某些應用需要至少一個數據表,所以,在使用他們之前需要在數據庫中創建一些表。請執行以下命令:
python manage.py migrate
創建模型
在 Django 裏寫一個數據庫驅動的 Web 應用的第一步是定義模型 - 也就是數據庫結構設計和附加的其它元數據。
在這個簡單的投票應用中,需要創建兩個模型:問題 Question 和選項 Choice。Question 模型包括問題描述和發佈時間。Choice 模型有兩個字段,選項描述和當前得票數。每個選項屬於一個問題。
這些概念可以通過一個簡單的 Python 類來描述。按照下面的例子來編輯 polls/models.py 文件:
polls/models.py
from django.db import models
class 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 很多信息,通過這些信息,Django 可以:
爲這個應用創建數據庫 schema(生成 CREATE TABLE 語句)。
創建可以與 Question 和 Choice 對象進行交互的 Python 數據庫 API。
但是首先得把 polls 應用安裝到我們的項目裏。
爲了在我們的工程中包含這個應用,我們需要在配置類 INSTALLED_APPS 中添加設置。因爲 PollsConfig 類寫在文件 polls/apps.py 中,所以它的點式路徑是 ‘polls.apps.PollsConfig’。在文件 mysite/settings.py 中 INSTALLED_APPS 子項添加點式路徑後,它看起來像這樣:
mysite/settings.py
INSTALLED_APPS = [
'polls.apps.PollsConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
現在你的 Django 項目會包含 polls 應用。接着運行下面的命令:
python manage.py makemigrations poll
你將會看到類似於下面這樣的輸出:
Migrations for 'polls':
polls/migrations/0001_initial.py:
- Create model Choice
- Create model Question
- Add field question to choice
通過運行 makemigrations 命令,Django 會檢測你對模型文件的修改(在這種情況下,你已經取得了新的),並且把修改的部分儲存爲一次 遷移。
遷移是 Django 對於模型定義(也就是你的數據庫結構)的變化的儲存形式 - 沒那麼玄乎,它們其實也只是一些你磁盤上的文件。如果你想的話,你可以閱讀一下你模型的遷移數據,它被儲存在 polls/migrations/0001_initial.py 裏。別擔心,你不需要每次都閱讀遷移文件,但是它們被設計成人類可讀的形式,這是爲了便於你手動修改它們。
Django 有一個自動執行數據庫遷移並同步管理你的數據庫結構的命令 - 這個命令是 migrate,我們馬上就會接觸它 - 但是首先,讓我們看看遷移命令會執行哪些 SQL 語句。sqlmigrate 命令接收一個遷移的名稱,然後返回對應的 SQL:
python manage.py sqlmigrate polls 0001
(上方代碼是遷移數據庫的命令0001即代表第一次遷移)
你將會看到類似下面這樣的輸出(我把輸出重組成了人類可讀的格式):
BEGIN;
–
– Create model Choice
–
CREATE TABLE “polls_choice” (
“id” serial NOT NULL PRIMARY KEY,
“choice_text” varchar(200) NOT NULL,
“votes” integer NOT NULL
);
–
– Create model Question
–
CREATE TABLE “polls_question” (
“id” serial NOT NULL PRIMARY KEY,
“question_text” varchar(200) NOT NULL,
“pub_date” timestamp with time zone NOT NULL
);
–
– Add field question to choice
–
ALTER TABLE “polls_choice” ADD COLUMN “question_id” integer NOT NULL;
ALTER TABLE “polls_choice” ALTER COLUMN “question_id” DROP DEFAULT;
CREATE INDEX “polls_choice_7aa0f6ee” ON “polls_choice” (“question_id”);
ALTER TABLE “polls_choice”
ADD CONSTRAINT “polls_choice_question_id_246c99a640fbbd72_fk_polls_question_id”
FOREIGN KEY (“question_id”)
REFERENCES “polls_question” (“id”)
DEFERRABLE INITIALLY DEFERRED;
COMMIT;
如果你感興趣,你也可以試試運行
python manage.py check ;
這個命令幫助你檢查項目中的問題,並且在檢查過程中不會對數據庫進行任何操作。
現在,再次運行 migrate 命令,在數據庫裏創建新定義的模型的數據表,你就會看到以下代碼:
python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, polls, sessions
Running migrations:
Rendering model states… DONE
Applying polls.0001_initial… OK
遷移是非常強大的功能,它能讓你在開發過程中持續的改變數據庫結構而不需要重新刪除和創建表 - 它專注於使數據庫平滑升級而不會丟失數據。我們會在後面的教程中更加深入的學習這部分內容,現在,你只需要記住,改變模型需要這三步:
編輯 models.py 文件,改變模型。 運行 python manage.py makemigrations 爲模型的改變生成遷移文件。
運行 python manage.py migrate 來應用數據庫遷移。
初試 API
現在讓我們進入交互式 Python 命令行,嘗試一下 Django 爲你創建的各種 API。通過以下命令打開 Python 命令行:
python manage.py shell
我們使用這個命令而不是簡單的使用 “Python” 是因爲 manage.py 會設置 DJANGO_SETTINGS_MODULE 環境變量,這個變量會讓 Django 根據 mysite/settings.py 文件來設置 Python 包的導入路徑。
當你成功進入命令行後,來試試 database API 吧:
等等。<Question: Question object (1)> 對於我們瞭解這個對象的細節沒什麼幫助。讓我們通過編輯 Question 模型的代碼(位於 polls/models.py 中)來修復這個問題。給 Question 和 Choice 增加 str() 方法。
polls/models.py
rom django.db import models
class Question(models.Model):
# ...
def __str__(self):
return self.question_text
class Choice(models.Model):
# ...
def __str__(self):
return self.choice_text
給模型增加 str() 方法是很重要的,這不僅僅能給你在命令行裏使用帶來方便,Django 自動生成的 admin 裏也使用這個方法來表示對象。
注意:這些都是常規的 Python方法。讓我們添加一個自定義的方法,這只是爲了演示:
polls/models.py
import datetime
from django.db import models
from django.utils import timezone
class Question(models.Model):
# ...
def was_published_recently(self):
return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
創建一個管理員賬號:
首先,我們得創建一個能登錄管理頁面的用戶。請運行下面的命令:
python manage.py createsuperuser
鍵入你想要使用的用戶名,然後按下回車鍵:
Username: admin
然後提示你輸入想要使用的郵件地址:
Email address: [email protected]
最後一步是輸入密碼。你會被要求輸入兩次密碼,第二次的目的是爲了確認第一次輸入的確實是你想要的密碼。
Password: **********
Password (again): *********
Superuser created successfully.
ps:建議密碼起自己好記的也可以和username一樣
啓動開發服務器
Django 的管理界面默認就是啓用的。讓我們啓動開發服務器,看看它到底是什麼樣的。
如果開發服務器未啓動,用以下命令啓動它:
python manage.py runserver
現在,打開瀏覽器,轉到你本地域名的 “/admin/” 目錄, – 比如 “http://127.0.0.1:8000/admin/” 。你應該會看見管理員登錄界面:
因爲 翻譯 功能默認是開着的,所以登錄界面可能會使用你的語言,取決於你瀏覽器的設置和 Django 是否擁有你語言的翻譯。
進入管理站點頁面:
現在,試着使用你在上一步中創建的超級用戶來登錄。然後你將會看到 Django 管理頁面的索引頁:
你將會看到幾種可編輯的內容:組和用戶。它們是由 django.contrib.auth 提供的,這是 Django 開發的認證框架。
向管理頁面中加入投票應用
但是我們的投票應用在哪呢?它沒在索引頁面裏顯示。
只需要做一件事:我們得告訴管理頁面,問題 Question 對象需要被管理。打開 polls/admin.py 文件,把它編輯成下面這樣:
polls/admin.py
from django.contrib import admin
from .models import Question
admin.site.register(Question)
體驗便捷的管理功能
現在我們向管理頁面註冊了問題 Question 類。Django 知道它應該被顯示在索引頁裏:
點擊 “Questions” 。現在看到是問題 “Questions” 對象的列表 “change list” 。這個界面會顯示所有數據庫裏的問題 Question 對象,你可以選擇一個來修改。這裏現在有我們在上一部分中創建的 “What’s up?” 問題。
點擊 “What’s up?” 來編輯這個問題(Question)對象:
通過點擊 “今天(Today)” 和 “現在(Now)” 按鈕改變 “發佈日期(Date Published)”。然後點擊 “保存並繼續編輯(Save and add another)”按鈕。然後點擊右上角的 “歷史(History)”按鈕。你會看到一個列出了所有通過 Django 管理頁面對當前對象進行的改變的頁面,其中列出了時間戳和進行修改操作的用戶名:
編寫更多視圖
現在讓我們向 polls/views.py 裏添加更多視圖。這些視圖有一些不同,因爲他們接收參數:
polls/views.py
def detail(request, question_id):
return HttpResponse("You're looking at question %s." % question_id)
def results(request, question_id):
response = "You're looking at the results of question %s."
return HttpResponse(response % question_id)
def vote(request, question_id):
return HttpResponse("You're voting on question %s." % question_id)
把這些新視圖添加進 polls.urls 模塊裏,只要添加幾個 url() 函數調用就行:
polls/urls.py
from django.urls import path
from . import views
urlpatterns = [
# ex: /polls/
path('', views.index, name='index'),
# ex: /polls/5/
path('<int:question_id>/', views.detail, name='detail'),
# ex: /polls/5/results/
path('<int:question_id>/results/', views.results, name='results'),
# ex: /polls/5/vote/
path('<int:question_id>/vote/', views.vote, name='vote'),
]
爲每個 URL 加上不必要的東西,例如 .html ,是沒有必要的。不過如果你非要加的話,也是可以的:
path('polls/latest.html', views.index),
但是,別這樣做,這太傻了
寫一個真正有用的視圖
但是,別這樣做,這太傻了。
寫一個真正有用的視圖¶
每個視圖必須要做的只有兩件事:返回一個包含被請求頁面內容的 HttpResponse 對象,或者拋出一個異常,比如 Http404 。至於你還想幹些什麼,隨便你。
你的視圖可以從數據庫裏讀取記錄,可以使用一個模板引擎(比如 Django 自帶的,或者其他第三方的),可以生成一個 PDF 文件,可以輸出一個 XML,創建一個 ZIP 文件,你可以做任何你想做的事,使用任何你想用的 Python 庫。
Django 只要求返回的是一個 HttpResponse ,或者拋出一個異常。
因爲 Django 自帶的數據庫 API 很方便,我們曾在 教程第 2 部分 中學過,所以我們試試在視圖裏使用它。我們在 index() 函數裏插入了一些新內容,讓它能展示數據庫裏以發佈日期排序的最近 5 個投票問題,以空格分割:
polls/views.py
from django.http import HttpResponse
from .models import Question
def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:5]
output = ', '.join([q.question_text for q in latest_question_list])
return HttpResponse(output)
# Leave the rest of the views (detail, results, vote) unchanged
這裏有個問題:頁面的設計寫死在視圖函數的代碼裏的。如果你想改變頁面的樣子,你需要編輯 Python 代碼。所以讓我們使用 Django 的模板系統,只要創建一個視圖,就可以將頁面的設計從代碼中分離出來。
首先,在你的 polls 目錄裏創建一個 templates 目錄。Django 將會在這個目錄裏查找模板文件。
你項目的 TEMPLATES 配置項描述了 Django 如何載入和渲染模板。默認的設置文件設置了 DjangoTemplates 後端,並將 APP_DIRS 設置成了 True。這一選項將會讓 DjangoTemplates 在每個 INSTALLED_APPS 文件夾中尋找 “templates” 子目錄。這就是爲什麼儘管我們沒有像在第二部分中那樣修改 DIRS 設置,Django 也能正確找到 polls 的模板位置的原因。
在你剛剛創建的 templates 目錄裏,再創建一個目錄 polls,然後在其中新建一個文件 index.html 。換句話說,你的模板文件的路徑應該是 polls/templates/polls/index.html 。因爲 Django 會尋找到對應的 app_directories ,所以你只需要使用 polls/index.html 就可以引用到這一模板了。
將下面的代碼輸入到剛剛創建的模板文件中:
polls/templates/polls/index.html
from django.http import HttpResponse
from django.template import loader
from .models import Question
def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:5]
template = loader.get_template('polls/index.html')
context = {
'latest_question_list': latest_question_list,
}
return HttpResponse(template.render(context, request))
上述代碼的作用是,載入 polls/index.html 模板文件,並且向它傳遞一個上下文(context)。這個上下文是一個字典,它將模板內的變量映射爲 Python 對象。
一個快捷函數: render()
載入模板,填充上下文,再返回由它生成的 HttpResponse 對象」是一個非常常用的操作流程。於是 Django 提供了一個快捷函數,我們用它來重寫 index() 視圖:
from django.shortcuts import render
from .models import Question
def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:5]
context = {'latest_question_list': latest_question_list}
return render(request, 'polls/index.html', context)
拋出 404 錯誤
現在,我們來處理投票詳情視圖——它會顯示指定投票的問題標題。下面是這個視圖的代碼:
polls/views.py
from django.http import Http404
from django.shortcuts import render
from .models import Question
# ...
def detail(request, question_id):
try:
question = Question.objects.get(pk=question_id)
except Question.DoesNotExist:
raise Http404("Question does not exist")
return render(request, 'polls/detail.html', {'question': question})
這裏有個新原則。如果指定問題 ID 所對應的問題不存在,這個視圖就會拋出一個 Http404 異常。
我們稍後再討論你需要在 polls/detail.html 裏輸入什麼,但是如果你想試試上面這段代碼是否正常工作的話,你可以暫時把下面這段輸進去:
polls/templates/polls/detail.html
{{ question }}
這樣你就能測試了
一個快捷函數: get_object_or_404()
嘗試用 get() 函數獲取一個對象,如果不存在就拋出 Http404 錯誤也是一個普遍的流程。Django 也提供了一個快捷函數,下面是修改後的詳情 detail() 視圖代碼:
polls/views.py
from django.shortcuts import get_object_or_404, render
from .models import Question
# ...
def detail(request, question_id):
question = get_object_or_404(Question, pk=question_id)
return render(request, 'polls/detail.html', {'question': question})
使用模板系統
回過頭去看看我們的detail()視圖。它向模板傳遞了上下文變量question。下面是polls/detail.html模板里正式的代碼:
polls/templates/polls/detail.html ¶
<h1>{{ question.question_text }}</h1>
<ul>
{% for choice in question.choice_set.all %}
<li>{{ choice.choice_text }}</li>
{% endfor %}
</ul>
模板系統統一使用點符號來訪問變量的屬性。在示例中,首先Django嘗試對 對象使用字典查找(也就是使用obj.get(str)操作),如果失敗了就嘗試屬性查找(也就是obj.str操作),結果是成功了。如果這一操作也失敗的話,將會嘗試列表查找(也就是obj[int]操作)。{{ question.question_text }}question
在 循環中發生的函數調用:被解釋爲Python代碼,將會返回一個可迭代的對象,這一對象可以在 標籤內部使用。{% for %}question.choice_set.allquestion.choice_set.all()Choice{% for %}
查看模板指南可以瞭解關於模板的更多信息。
去除模板中的硬編碼URL
還記得嗎,我們在polls/index.html裏編寫投票鏈接時,鏈接是硬編碼的:
<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
問題在於,硬編碼和強耦合的鏈接,對於一個包含很多應用的項目來說,修改起來是十分困難的。然而,因爲你在polls.urls的url()函數中通過name參數爲URL定義了名字,你可以使用 標籤代替它:{% url %}
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
這個標籤的工作方式是在polls.urls模塊的URL定義中尋具有指定名字的條目。你可以回憶一下,具有名字’detail’的URL是在如下語句中定義的:
...
# the 'name' value as called by the {% url %} template tag
path('<int:question_id>/', views.detail, name='detail'),
...
如果你想改變投票詳情視圖的URL,比如想改成polls/specifics/12/,你不用在模板裏修改任何東西(包括其它模板),只要在polls/urls.py裏稍微修改一下就行:
...
# added the word 'specifics'
path('specifics/<int:question_id>/', views.detail, name='detail'),
...
爲URL名稱添加命名空間¶
教程項目只有一個應用,polls。在一個真實的Django項目中,可能會有五個,十個,二十個,甚至更多應用。Django如何分辨重名的URL呢?舉個例子,polls 應用有detail視圖,可能另一個博客應用也有同名的視圖。Django如何知道標籤到底對應哪一個應用的URL呢?{% url %}
答案是:在根URLconf中添加命名空間。在polls/urls.py文件中稍作修改,加上app_name設置命名空間:
polls/urls.py
from django.urls import path
from . import views
app_name = 'polls'
urlpatterns = [
path('', views.index, name='index'),
path('<int:question_id>/', views.detail, name='detail'),
path('<int:question_id>/results/', views.results, name='results'),
path('<int:question_id>/vote/', views.vote, name='vote'),
]
現在,編輯polls/index.html文件,從:
polls/templates/polls/index.html ¶
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
修改爲指向具有命名空間的詳細視圖:
polls/templates/polls/index.html ¶
<li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>
當你對你寫的視圖感到滿意後,請閱讀教程的第4部分了解簡單的表單處理和通用視圖。
編寫你的第一個Django應用,第4部分
一個關係編寫簡單的表單
讓我們更新一下在上一個教程中編寫的投票詳細頁面的模板(“polls / detail.html”),讓它包含一個HTML 元素:
polls/templates/polls/detail.html
<h1>{{ question.question_text }}</h1>
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
<form action="{% url 'polls:vote' question.id %}" method="post">
{% csrf_token %}
{% for choice in question.choice_set.all %}
<input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}">
<label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br>
{% endfor %}
<input type="submit" value="Vote">
</form>
現在,讓我們來創建一個Django視圖來處理提交的數據。記住,在教程第3部分中,我們爲投票應用創建了一個URLconf,包含這一行:
polls/urls.py
path('<int:question_id>/vote/', views.vote, name='vote'),
我們還創建了一個 vote() 函數的虛擬實現。讓我們來創建一個真實的版本。 將下面的代碼添加到 polls/views.py :
> polls/views.py
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.urls import reverse
from .models import Choice, Question
# ...
def vote(request, question_id):
question = get_object_or_404(Question, pk=question_id)
try:
selected_choice = question.choice_set.get(pk=request.POST['choice'])
except (KeyError, Choice.DoesNotExist):
# Redisplay the question voting form.
return render(request, 'polls/detail.html', {
'question': question,
'error_message': "You didn't select a choice.",
})
else:
selected_choice.votes += 1
selected_choice.save()
# Always return an HttpResponseRedirect after successfully dealing
# with POST data. This prevents data from being posted twice if a
# user hits the Back button.
return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))
在這個例子中,我們在 HttpResponseRedirect 的構造函數中使用 reverse() 函數。這個函數避免了我們在視圖函數中硬編碼 URL。它需要我們給出我們想要跳轉的視圖的名字和該視圖所對應的 URL 模式中需要給該視圖提供的參數。 在本例中,使用在 教程第 3 部分 中設定的 URLconf, reverse() 調用將返回一個這樣的字符串:
'/polls/3/results/'
其中 3 是 question.id 的值。重定向的 URL 將調用 ‘results’ 視圖來顯示最終的頁面。
正如在 教程第 3 部分 中提到的,HttpRequest 是一個 HttpRequest 對象。更多關於 HttpRequest 對象的內容,請參見 請求和響應的文檔 。
當有人對 Question 進行投票後, vote() 視圖將請求重定向到 Question 的結果界面。讓我們來編寫這個視圖: