使用Django2快速開發(fā)Web項目的詳細(xì)步驟
Django 是一款基于 Python 編寫并且采用 MVC 設(shè)計模式的開源的 Web 應(yīng)用框架,早期是作為勞倫斯出版集團(tuán)新聞網(wǎng)站的 CMS 內(nèi)容管理系統(tǒng)而開發(fā),后于 2005 年 7 月在 BSD 許可協(xié)議下開源,并于 2017 年 12 月 2 日 發(fā)布 2.0 正式版。

本文基于《Django 官方 Tutorials》以及《Django REST framework 官方 Tutorials》編寫,發(fā)稿時所使用的 Django 版本為 2.1.4,Python 版本為 3.6.6,文中涉及的代碼都已經(jīng)由筆者驗證運(yùn)行通過,最終形成了一個簡單項目并推送至筆者Github上的jungle項目當(dāng)中,需要的朋友可以基于此來逐步步完善成為一個產(chǎn)品化的項目。
新建 Django 項目
下面的命令行展示了在 Windows 操作系統(tǒng)下,基于 venv 虛擬環(huán)境搭建一個 Django 項目的步驟:
# 建立虛擬環(huán)境 C:\Workspace\django λ python -m venv venv # 激活虛擬環(huán)境 C:\Workspace\django λ .\venv\Scripts\activate.bat (venv) λ # 安裝Django C:\Workspace\django (venv) λ pip install Django Looking in indexes: https://mirrors.aliyun.com/pypi/simple/ Collecting Django Using cached https://mirrors.aliyun.com/pypi/packages/fd/9a/0c028ea0fe4f5803dda1a7afabeed958d0c8b79b0fe762ffbf728db3b90d/Django-2.1.4-py3-none-any.whl Collecting pytz (from Django) Using cached https://mirrors.aliyun.com/pypi/packages/f8/0e/2365ddc010afb3d79147f1dd544e5ee24bf4ece58ab99b16fbb465ce6dc0/pytz-2018.7-py2.py3-none-any.whl Installing collected packages: pytz, Django Successfully installed Django-2.1.4 pytz-2018.7 # 進(jìn)入虛擬環(huán)境目錄,新建一個Django項目 C:\Workspace\django (venv) λ django-admin startproject mysite C:\Workspace\django (venv) λ ls mysite/ venv/ # 進(jìn)入新建的Django項目,建立一個應(yīng)用 C:\Workspace\django (venv) λ cd mysite\ C:\Workspace\django\mysite (venv) λ python manage.py startapp demo C:\Workspace\django\mysite (venv) λ ls demo/ manage.py* mysite/ # 同步數(shù)據(jù)庫 C:\Workspace\django\mysite (venv) λ python manage.py migrate Operations to perform: Apply all migrations: admin, auth, contenttypes, sessions Running migrations: Applying contenttypes.0001_initial... OK Applying auth.0001_initial... OK Applying admin.0001_initial... OK Applying admin.0002_logentry_remove_auto_add... OK Applying admin.0003_logentry_add_action_flag_choices... OK Applying contenttypes.0002_remove_content_type_name... OK Applying auth.0002_alter_permission_name_max_length... OK Applying auth.0003_alter_user_email_max_length... OK Applying auth.0004_alter_user_username_opts... OK Applying auth.0005_alter_user_last_login_null... OK Applying auth.0006_require_contenttypes_0002... OK Applying auth.0007_alter_validators_add_error_messages... OK Applying auth.0008_alter_user_username_max_length... OK Applying auth.0009_alter_user_last_name_max_length... OK Applying sessions.0001_initial... OK # 啟動開發(fā)服務(wù) (venv) λ python manage.py runserver 8080 Performing system checks... System check identified no issues (0 silenced). January 03, 2019 - 21:31:48 Django version 2.1.4, using settings 'mysite.settings' Starting development server at http://127.0.0.1:8080/ Quit the server with CTRL-BREAK. # 返回uinika虛擬環(huán)境目錄,并將當(dāng)前虛擬環(huán)境的依賴導(dǎo)入至requirements.txt C:\Workspace\django\mysite (venv) λ cd .. C:\Workspace\django (venv) λ pip freeze > requirements.txt C:\Workspace\django (venv) λ ls mysite/ requirements.txt venv/
通過 django-admin startproject 命令創(chuàng)建的外部 mysite/ 目錄是 Web 項目的容器,而 manage.py 文件是用于與 Django 項目交互的命令行工具,更多的使用方式可以參閱 django-admin 文檔 。。
mysite/ manage.py mysite/ __init__.py settings.py urls.py wsgi.py
內(nèi)部嵌套的 mysite/ 目錄是用于放置項目中具體的 Python 包,它的名稱是您需要用來導(dǎo)入其中任何內(nèi)容的 Python 包名稱,例如 mysite.urls 。
mysite/__init__.py: 空文件,用于提示系統(tǒng)將當(dāng)前目錄識別為一個 Python 包。mysite/settings.py: Django 項目的配置文件,更多配置請查閱 Django settings 。mysite/urls.py: 當(dāng)前 Django 項目的 URL 聲明,更多內(nèi)容請參閱 URL dispatcher 。mysite/wsgi.py: 兼容 WSGI 規(guī)范的當(dāng)前項目入口點,更多細(xì)節(jié)可以閱讀 如果使用 WSGI 進(jìn)行部署 。
建立 mysite 項目之后,上面的命令行還通過了 py manage.py startapp 建立了一個 demo/ 應(yīng)用目錄,Django 當(dāng)中一個項目( mysite )可以擁有多個應(yīng)用( demo ), demo/ 目錄下的文件結(jié)構(gòu)如下:
demo/ __init__.py admin.py apps.py migrations/ __init__.py models.py tests.py views.py
請求與響應(yīng)
首先進(jìn)入 Python 虛擬環(huán)境并進(jìn)入 mysite 目錄后,執(zhí)行如下命令:
C:\Workspace\django\mysite (master -> origin) (venv) λ python manage.py startapp polls
新建一個 polls 應(yīng)用之后,打開該目錄下的 polls/views.py 源碼文件,輸入以下代碼:
from django.http import HttpResponse
def index(request):
return HttpResponse("你好,這是一個投票應(yīng)用!")
接下來,我們需要將上面修改的視圖文件 views.py 映射到一個 URL,先在 polls/ 目錄下新建一個 urls.py 文件,然后鍵入下面這段代碼:
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
]
最后,將上面定義的應(yīng)用的 URL 聲明文件 polls/urls.py 包含至項目的 mysite/urls.py 當(dāng)中,
from django.contrib import admin
from django.urls import include, path
urlpatterns = [
path('polls/', include('polls.urls')),
path('admin/', admin.site.urls),
]
上面代碼中出現(xiàn)的 include() 函數(shù)主要用于引入其它 URL 配置文件,這樣我們就可以通過 http://localhost:8080/polls/ 路徑訪問到如下信息了:

模型和管理頁面
mysite/settings.py 文件包含了項目的基本配置,該文件通過如下聲明默認(rèn)使用 Django 內(nèi)置的 SQLite 作為項目數(shù)據(jù)庫。
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
如果使用其它數(shù)據(jù)庫,則可以將配置書寫為下面的格式:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql', # 數(shù)據(jù)庫引擎名稱
'NAME': 'db', # 數(shù)據(jù)庫連接名稱
'USER': 'uinika', # 數(shù)據(jù)庫連接用戶名
'PASSWORD': 'test', # 數(shù)據(jù)庫連接密碼
'HOST': 'localhost', # 數(shù)據(jù)庫主機(jī)地址
'PORT': '3306', # 數(shù)據(jù)庫端口
}
}
其中 ENGINE 屬性可以根據(jù)項目所使用數(shù)據(jù)庫的不同而選擇如下值:
- SQLite:django.db.backends.sqlite3
- MySQL:django.db.backends.mysql
- PostgreSQL:django.db.backends.postgresql
- Oracle:django.db.backends.oracle
接下來繼續(xù)修改 mysite/settings.py ,設(shè)置 TIME_ZONE 屬性為項目使用國家的時區(qū)。
LANGUAGE_CODE = 'zh-hans' TIME_ZONE = 'Asia/Chongqing'
mysite/settings.py 文件頭部的 INSTALLED_APPS 屬性定義了當(dāng)前項目使用的應(yīng)用程序。
INSTALLED_APPS = [ 'django.contrib.admin', # 管理員站點 'django.contrib.auth', # 認(rèn)證授權(quán)系統(tǒng) 'django.contrib.contenttypes', # 內(nèi)容類型框架 'django.contrib.sessions', # 會話框架 'django.contrib.messages', # 消息框架 'django.contrib.staticfiles', # 靜態(tài)文件管理 ]
在前面命令行中執(zhí)行的 python manage.py migrate 命令會檢查 INSTALLED_APPS 屬性的設(shè)置,并為其中的每個應(yīng)用創(chuàng)建所需的數(shù)據(jù)表,實際上 migrate 命令只會為對 INSTALLED_APPS 里聲明了的應(yīng)用進(jìn)行數(shù)據(jù)庫遷移 。
了解項目配置文件的一些設(shè)置之后,現(xiàn)在來編輯 polls/models.py 文件新建 Question(問題) 和 Choice(選項) 兩個數(shù)據(jù)模型:
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.db.models.Model 的子類,模型里的類變量都表示一個數(shù)據(jù)庫字段,每個字段實質(zhì)都是 Field 類的實例。注意在 Choice 使用了 ForeignKey 屬性定義了一個與 Question 的外鍵關(guān)聯(lián)關(guān)系,Django 支持所有常用的多對一、多對多和一對一數(shù)據(jù)庫關(guān)系。
數(shù)據(jù)庫模型建立完成之后,由于 PollsConfig 類位于 polls/apps.py 文件當(dāng)中,所以其對應(yīng)的點式路徑為 polls.apps.PollsConfig ,現(xiàn)在我們需要將該路徑添加至 mysite/settings.py 文件的 INSTALLED_APPS 屬性:
INSTALLED_APPS = [ 'polls.apps.PollsConfig', # 添加PollsConfig 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', ]
通過 manage.py 提供的 makemigrations 命令,將模型的修改遷移到 SQLite 數(shù)據(jù)庫當(dāng)中。
C:\Workspace\django\mysite (master -> origin) (venv) λ python manage.py makemigrations polls Migrations for 'polls': polls\migrations\0001_initial.py - Create model Choice - Create model Question - Add field question to choice
我們還可以通過 manage.py 提供的 sqlmigrate 命令,查看數(shù)據(jù)遷移過程中執(zhí)行了哪些 SQL 語句,該命令并不會實質(zhì)性執(zhí)行 Django 模型到數(shù)據(jù)庫的遷移任務(wù)。
C:\Workspace\django\mysite (master -> origin)
(venv) λ python manage.py sqlmigrate polls 0001
BEGIN;
--
-- Create model Choice
--
CREATE TABLE "polls_choice" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "choice_text" varchar(200) NOT NULL, "v
otes" integer NOT NULL);
--
-- Create model Question
--
CREATE TABLE "polls_question" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "question_text" varchar(200) NOT NULL
, "pub_date" datetime NOT NULL);
--
-- Add field question to choice
--
ALTER TABLE "polls_choice" RENAME TO "polls_choice__old";
CREATE TABLE "polls_choice" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "choice_text" varchar(200) NOT NULL, "v
otes" integer NOT NULL, "question_id" integer NOT NULL REFERENCES "polls_question" ("id") DEFERRABLE INITIALLY DEFERR
ED);
INSERT INTO "polls_choice" ("id", "choice_text", "votes", "question_id") SELECT "id", "choice_text", "votes", NULL FR
OM "polls_choice__old";
DROP TABLE "polls_choice__old";
CREATE INDEX "polls_choice_question_id_c5b4b260" ON "polls_choice" ("question_id");
COMMIT;
Django 模型的數(shù)據(jù)庫主鍵 ID 會被自動創(chuàng)建, 并會在外鍵字段名稱后追加 _id 字符串作為后綴。
接下來運(yùn)行 manage.py 提供的 migrate 命令,在根據(jù)新定義的模型創(chuàng)建相應(yīng)的數(shù)據(jù)庫表。
C:\Workspace\django\mysite (master -> origin) (venv) λ python manage.py migrate Operations to perform: Apply all migrations: admin, auth, contenttypes, polls, sessions Running migrations: Applying polls.0001_initial... OK
為了便于在版本管理系統(tǒng)提交遷移數(shù)據(jù),Django 將模型的修改分別獨(dú)立為 生成 和 應(yīng)用 兩個命令,因此修改 Django 模型會涉及如下 3 個步驟:
- 編輯models.py文件修改模型。
- 運(yùn)行python manage.py makemigrations為模型的改變生成遷移文件。
- 運(yùn)行python manage.py migrate來應(yīng)用數(shù)據(jù)庫遷移。
完成上述 Django 模型與數(shù)據(jù)庫的同步之后,接下來可以通過 manage.py 提供的 shell 命令,在命令行工具內(nèi)運(yùn)行 Django 提供的交互式 API。
C:\Workspace\django\mysite (master -> origin) (venv) λ python manage.py shell Python 3.6.6 (v3.6.6:4cf1f54eb7, Jun 27 2018, 03:37:03) [MSC v.1900 64 bit (AMD64)] on win32 Type "help", "copyright", "credits" or "license" for more information. (InteractiveConsole) >>> from polls.models import Choice, Question >>> Question.objects.all() <QuerySet []> >>> from django.utils import timezone >>> q = Question(question_text="What's new?", pub_date=timezone.now()) >>> q.save() >>> q.id 1 >>> q.question_text "What's new?" >>> q.pub_date datetime.datetime(2019, 1, 4, 9, 10, 1, 955820, tzinfo=<UTC>) >>> q.question_text = "What's up?" >>> q.save() >>> Question.objects.all() <QuerySet [<Question: Question object (1)>]>
上面命令行執(zhí)行結(jié)果中的 <Question: Question object (1)> 對于實際開發(fā)沒有意義,因此可以考慮為上面建立的 Django 模型增加 __str__() 方法直接打印模型對象的屬性數(shù)據(jù)。為了便于進(jìn)一步測試,這里還為 Question 類添加一個自定義的 was_published_recently() 方法:
import datetime
from django.db import models
from django.utils import timezone
class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
# 自定義was_published_recently()方法
def was_published_recently(self):
return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
# 添加__str__()方法
def __str__(self):
return self.question_text
class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)
# 添加__str__()方法
def __str__(self):
return self.choice_text
完成修改工作之后,再一次運(yùn)行 python manage.py shell 命令:
C:\Workspace\django\mysite (master -> origin)
(venv) λ python manage.py shell
Python 3.6.6 (v3.6.6:4cf1f54eb7, Jun 27 2018, 03:37:03) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from polls.models import Choice, Question
>>> Question.objects.all()
<QuerySet [<Question: What's up?>]>
>>> 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?>
>>> Question.objects.get(id=2)
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "C:\Workspace\django\venv\lib\site-packages\django\db\models\manager.py", line 82, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "C:\Workspace\django\venv\lib\site-packages\django\db\models\query.py", line 399, in get
self.model._meta.object_name
polls.models.Question.DoesNotExist: Question matching query does not exist.
>>> Question.objects.get(pk=1)
<Question: What's up?>
>>> q = Question.objects.get(pk=1)
>>> q.was_published_recently()
True
>>> 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)
>>> c.question
<Question: What's up?>
>>> q.choice_set.all()
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>
>>> q.choice_set.count()
3
>>> Choice.objects.filter(question__pub_date__year=current_year)
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>
>>> c = q.choice_set.filter(choice_text__startswith='Just hacking')
>>> c.delete()
(1, {'polls.Choice': 1})
管理站點
Django 能夠根據(jù)模型自動創(chuàng)建后臺管理界面, 這里我們執(zhí)行 manage.py 提供的 createsuperuser 命令創(chuàng)建一個管理用戶:
C:\Workspace\django\mysite (master -> origin) (venv) λ python manage.py createsuperuser Username (leave blank to use 'zhenghang'): hank Email address: uinika@outlook.com Password: ******** Password (again): ******** Superuser created successfully.
啟動 Django 服務(wù)之后,就可以通過 URL 地址 http://localhost:8080/admin/login 并使用上面新建的用戶名和密碼進(jìn)行登陸管理操作:

登陸后默認(rèn)只能對權(quán)限相關(guān)的 User 和 Group 進(jìn)行管理,如果我們需要將 Question 數(shù)據(jù)模型納入管理,那么必須要在 polls/admin.py 文件對其進(jìn)行注冊。
from django.contrib import admin from .models import Question admin.site.register(Question)
完成注冊之后,刷新管理站點頁面即可查看到 Question 管理選項:

視圖與模板
Django 使用 URLconfs 配置將 URL 與視圖關(guān)聯(lián),即將 URL 映射至視圖,下面我們將向 polls/views.py 文件添加一些能夠接收參數(shù)的視圖:
from django.http import HttpResponse
def index(request):
return HttpResponse("你好,這是一個投票應(yīng)用!")
def detail(request, question_id):
return HttpResponse("你正在查看問題 %s 。" % question_id)
def results(request, question_id):
response = "你看到的是問題 %s 的結(jié)果。"
return HttpResponse(response % question_id)
def vote(request, question_id):
return HttpResponse("你正在對問題 %s 進(jìn)行投票。" % question_id)
然后將這些新的視圖添加至 polls.urls 模塊:
from django.urls import path
from . import views
urlpatterns = [
# 訪問 http://localhost:8080/polls/
path('', views.index, name='index'),
# 訪問 http://localhost:8080/polls/5/
path('<int:question_id>/', views.detail, name='detail'),
# 訪問 http://localhost:8080/polls/5/results/
path('<int:question_id>/results/', views.results, name='results'),
# 訪問 http://localhost:8080/polls/5/vote/
path('<int:question_id>/vote/', views.vote, name='vote'),
]
Django 的每個視圖只會完成兩個任務(wù):第 1 是返回一個包含被請求頁面內(nèi)容的 HttpResponse 對象,或者拋出一個 Http404 這樣的異常。這里為了展示數(shù)據(jù)庫里按照發(fā)布日期排序的最近五個投票問題,我們再向 polls/views.py 代碼文件的 index() 函數(shù)添加如下內(nèi)容:
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)
這樣直接將數(shù)據(jù)庫查詢結(jié)果輸出到頁面的方式并不優(yōu)雅,實際開發(fā)環(huán)境當(dāng)中我們通常會使用模板頁面來展示數(shù)據(jù),首先在 polls 應(yīng)用目錄下創(chuàng)建一個用來存放模板文件的 templates 目錄。由于站點配置文件 mysite/settings.py 里 TEMPLATES 屬性的默認(rèn)設(shè)置,能夠讓 Django 在每個 INSTALLED_APPS 文件夾中自動尋找 templates 子目錄,從而正確定位出模板的位置。
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',
],
},
},
]
接下來繼續(xù)在 templates 下面新建一個 polls 目錄,然后在里邊放置一個 index.html 文件,此時通過 URL 地址 http://localhost:8080/polls/ 就可以訪問到這個模板文件,模板文件會將按照發(fā)布日期排序了的 Question 列表 latest_question_list 放置到 HttpResponse 上下文,并在 polls/index.html 模板當(dāng)中完成數(shù)據(jù)綁定。
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))
事實上,通過使用 render() 方法,Django 能夠以更加簡化的方式完成載入模板、填充上下文、返回 HttpResponse 對象這一系列步驟:
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)
接下來處理投票詳情頁面,這里會有一個新原則,即如果指定 ID 所對應(yīng)的 Question 不存在,那么視圖就會拋出一個 Http404 異常。在 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("問題不存在!")
return render(request, 'polls/detail.html', {'question': qu
然后暫時向 polls/templates/polls/detail.html 添加一行簡單的 代碼便于測試上面的代碼。
Django 提供了諸如 get_object_or_404() 、 get_list_or_404() 這樣的快捷函數(shù)語法糖來解決 Http404 判斷的問題,因而上一步的代碼依然可以進(jìn)一步簡化為下面這樣:
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})
讓我們進(jìn)一步完善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 首先會嘗試對question對象使用字典查找(既obj.get(str)),如果失敗再嘗試屬性查找(既obj.str),如果依然失敗就會嘗試列表查找(即obj[int])。另外循環(huán)for中的question.choice_set.all語句會被解析為question.choice_set.all()的 Python 的函數(shù)調(diào)用,完成后將返回一個可迭代的Choice對象,該對象僅限于for循環(huán)標(biāo)簽內(nèi)部使用。
在polls/templates/polls/index.html編寫的投票鏈接里使用了諸如<a href="/polls//" rel="external nofollow" ></a>這樣的硬編碼,但是這樣容易造成視圖與后端業(yè)務(wù)的耦合,因此 Django 提供了url標(biāo)簽來解決這個問題。
<a href="{% url 'detail' question.id %}" rel="external nofollow" >{{ question.question_text }}</a>
實際上在mysite/polls/urls.py內(nèi)的函數(shù)調(diào)用path('<int:question_id>/', views.detail, name='detail')當(dāng)中,path()的name屬性就是作用于url標(biāo)簽中的這個特性的。
為了避免項目當(dāng)中各種應(yīng)用的 URL 重名,避免url標(biāo)簽被使用時產(chǎn)生歧義,需要在polls/urls.py上添加應(yīng)用的命名空間作為區(qū)分。
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/templates/polls/index.html文件,為每個url標(biāo)簽添加上面聲明的polls:命名空間。
<li><a href="{% url 'polls:detail' question.id %}" rel="external nofollow" >{{ question.question_text }}</a></li>
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
pandas 數(shù)據(jù)索引與選取的實現(xiàn)方法
這篇文章主要介紹了pandas 數(shù)據(jù)索引與選取的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-06-06
python使用pandas實現(xiàn)數(shù)據(jù)分割實例代碼
這篇文章主要介紹了python使用pandas實現(xiàn)數(shù)據(jù)分割實例代碼,介紹了使用pandas實現(xiàn)對dataframe格式的數(shù)據(jù)分割成時間跨度相等的數(shù)據(jù)塊,分享了相關(guān)代碼示例,小編覺得還是挺不錯的,具有一定借鑒價值,需要的朋友可以參考下2018-01-01
pycharm中使用pyplot時報錯MatplotlibDeprecationWarning
最近在使用Pycharm中matplotlib作圖處理時報錯,所以這篇文章主要給大家介紹了關(guān)于pycharm中使用pyplot時報錯MatplotlibDeprecationWarning的相關(guān)資料,需要的朋友可以參考下2023-12-12
Python使用pyautogui模塊實現(xiàn)自動化鼠標(biāo)和鍵盤操作示例
這篇文章主要介紹了Python使用pyautogui模塊實現(xiàn)自動化鼠標(biāo)和鍵盤操作,簡單描述了pyautogui模塊的功能,并結(jié)合實例形式較為詳細(xì)的分析了Python使用pyautogui模塊實現(xiàn)鼠標(biāo)與鍵盤自動化操作相關(guān)技巧,需要的朋友可以參考下2018-09-09
在Python中使用itertools模塊中的組合函數(shù)的教程
這篇文章主要介紹了在Python中使用itertools模塊中的組合函數(shù)的教程,來自IBM官方技術(shù)文檔,需要的朋友可以參考下2015-04-04

