範例:投票選項
建立資料模型
修改 poll/default/models.py
,增加第 14 - 23 行:
from django.db import models
class Poll(models.Model):
subject = models.CharField(max_length=200, verbose_name='主題')
date_created = models.DateField(auto_now_add=True)
def __str__(self):
return str(self.id) + ")" + self.subject
class Option(models.Model):
poll_id = models.IntegerField()
title = models.CharField(max_length=200)
count = models.IntegerField(default=0)
def __str__(self):
return str(self.id) + ")" + self.title
執行以下指令套用到資料庫:
python manage.py makemigrations
python manage.py migrate
將自訂資料模型也納入內建管理後臺
修改 poll/default/admin.py
,新增第 6 行,將 Option
也加入後臺管理的範圍:
from django.contrib import admin
from .models import *
admin.site.register(Poll)
admin.site.register(Option)
修改完成後重新載入管理介面,應該會看到上面出現 Poll
跟 Option
的管理界面。
接著為投票主題「趕快來投票決定班遊地點!!!」,新增投票選項,記得要指定 Poll id
的值為 1
(因為該投票主題的 id
值為 1
)
- 淡水老街吃吃喝喝養豬行程
- 大稻埕文化巡訪文青行程
- 陽明山賞花趣拈花惹草行程
視圖、網址、範本
投票主題檢視
網址
修改檔案 poll/default/urls.py
,新增第 9 行路徑規則:
urlpatterns = [
path('poll/', views.PollList.as_view()),
path('poll/create/', views.PollCreate.as_view()),
path('poll/<int:pk>/update/', views.PollUpdate.as_view()),
path('poll/<int:pk>/delete/', views.PollDelete.as_view()),
path('poll/<int:pk>/', views.PollDetail.as_view()),
]
視圖
修改 poll/default/views.py
:
from django.shortcuts import render
from django.views.generic import ListView, DetailView
from .models import *
- 修改第 2 行,從
django.views.generic
另外再多引用 DetailView
class PollDetail(DetailView):
model = Poll
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
options = Option.objects.filter(poll_id=self.kwargs['pk'])
context['options'] = options
return context
- 新增第 31-39 行,新增定義一個名為
PollDetail
的類別繼承自 Django 的 DetailView
類別,它所參考的資模型是 Poll
,並定義其 get_context_data()
方法來取得與投票主題相關的選項紀錄。
範本
新增投票選項檢視頁面範本檔案 poll/default/templates/default/poll_detail.html
{% extends "base.html" %}
{% block content %}
<h1>{{ poll.subject }}</h1>
<ul>
{% for option in options %}
<li>{{ option.title }}</li>
{% endfor %}
</ul>
{% endblock %}
啟動網站,在網址列輸入 http://localhost/poll/1/
會出現以下頁面:
投票
這個範例的投票動作很簡單,不記錄投票的其他相關資訊,例:投票者、投票時間…等,僅單純增加票數而已。因此之前在定義資料模型的時候僅透過 Option
中的 count
欄位來記錄選項被投了幾次。
投票的流程簡化如下:在檢視投票主題時,可以直接點選該主題下的投票選項進行投票,投票後自動返回所屬投票主題檢視頁面。
網址
修改 poll/default/urls.py
,新增第 10 行:
urlpatterns = [
path('poll/', views.PollList.as_view()),
path('poll/create/', views.PollCreate.as_view()),
path('poll/<int:pk>/update/', views.PollUpdate.as_view()),
path('poll/<int:pk>/delete/', views.PollDelete.as_view()),
path('poll/<int:pk>/', views.PollDetail.as_view()),
path('option/<int:pk>/', views.PollVote.as_view()),
]
視圖
修改 poll/default/views.py
:
from django.shortcuts import render
from django.views.generic import ListView, DetailView, RedirectView
from .models import *
- 修改第 2 行,從
django.views.generic
額外引用 RedirectView
。
class PollVote(RedirectView):
def get_redirect_url(self, *args, **kwargs):
option = Option.objects.get(id=self.kwargs['pk'])
option.count += 1
option.save()
return "/poll/"+str(option.poll_id)+"/"
- 新增第 41-47 行,自訂
PollVote
繼承自 RedirectView
來實作投票完自動轉址的功能。
範本
在增加了票數之後,就直接轉址回所屬的投票主題檢視頁面,所以這個功能不需要定義頁面範本。
修改投票選項檢視頁面範本檔案 poll/default/templates/default/poll_detail.html
:
{% extends "base.html" %}
{% block content %}
<h1>{{ poll.subject }}</h1>
<ul>
{% for option in options %}
<li><a href="/option/{{ option.id }}">{{ option.title }}</a>--{{ option.count }}</li>
{% endfor %}
</ul>
{% endblock %}
使用者表單
投票選項
新增資料(Create)
路徑
開啟 poll/default/urls.py
,增加第 11 行路徑規則:
urlpatterns = [
path('poll/', views.PollList.as_view()),
path('poll/create/', views.PollCreate.as_view()),
path('poll/<int:pk>/update/', views.PollUpdate.as_view()),
path('poll/<int:pk>/delete/', views.PollDelete.as_view()),
path('poll/<int:pk>/', views.PollDetail.as_view()),
path('option/<int:pk>/', views.PollVote.as_view()),
path('option/create/<int:pid>/', views.OptionCreate.as_view()),
]
視圖
開啟 poll/default/views.py
,增加以下程式碼:
class OptionCreate(CreateView):
model = Option
fields = ['title']
template_name = 'form.html'
def get_success_url(self):
return '/poll/'+str(self.kwargs['pid'])+'/'
def form_valid(self, form):
form.instance.poll_id = self.kwargs['pid']
return super().form_valid(form)
- 新增
OptionCreate
繼承自通用編輯類別 CreateView
來實作新增投票選項的功能
範本
與 PollCreate
, PollUpdate
共用 form.html
即可,不另行定義頁面範本。
因為在 models.py
裡定義 Option
的資料模型時,並未指定 title
這個欄位的標籤文字,所以預設會以欄位名稱當做輸入標籤文字。若想修改的話,可以在定義 title
欄位型態時,如下方程式碼區塊的第 18 行,額外指定 verbose_name
屬性即可,例:
class Option(models.Model):
poll_id = models.IntegerField()
title = models.CharField(max_length=200, verbose_name='投票選項')
count = models.IntegerField(default=0)
有另一種指定方式,在欄位型態的第一個參數直接放上標籤文字也可以,如:
title = models.CharField('投票選項', max_length=200)
修改資料(Update)
網址
開啟 poll/default/urls.py
,增加第 12 行路徑規則:
urlpatterns = [
path('poll/', views.PollList.as_view()),
path('poll/create/', views.PollCreate.as_view()),
path('poll/<int:pk>/update/', views.PollUpdate.as_view()),
path('poll/<int:pk>/delete/', views.PollDelete.as_view()),
path('poll/<int:pk>/', views.PollDetail.as_view()),
path('option/<int:pk>/', views.PollVote.as_view()),
path('option/create/<int:pid>/', views.OptionCreate.as_view()),
path('option/<int:pk>/update/', views.OptionUpdate.as_view()),
]
視圖
開啟 poll/default/views.py
,增加以下程式碼:
class OptionUpdate(UpdateView):
model = Option
fields = ['title']
template_name = 'form.html'
def get_success_url(self):
return '/poll/'+str(self.object.poll_id)+'/'
- 新增
OptionUpdate
繼承自通用編輯視圖 UpdateView
來實作修改投票選項的功能
刪除資料(Delete)
網址
開啟 poll/default/urls.py
,增加第 13 行路徑規則:
urlpatterns = [
path('poll/', views.PollList.as_view()),
path('poll/create/', views.PollCreate.as_view()),
path('poll/<int:pk>/update/', views.PollUpdate.as_view()),
path('poll/<int:pk>/delete/', views.PollDelete.as_view()),
path('poll/<int:pk>/', views.PollDetail.as_view()),
path('option/<int:pk>/', views.PollVote.as_view()),
path('option/create/<int:pid>/', views.OptionCreate.as_view()),
path('option/<int:pk>/update/', views.OptionUpdate.as_view()),
path('option/<int:pk>/delete/', views.OptionDelete.as_view()),
]
另外,請修改投票主題檢視的路徑規則如下:
path('poll/<int:pk>/', views.PollDetail.as_view(), name='poll_view'),
- 加上
name
參數,將此條規則命名為 poll_view
。我們將在視圖中示範另一種指定成功返回路徑的方式,但需要先將欲使用的路徑規則命名。
視圖
修改 poll/default/views.py
,新增第 5 行:
from .models import *
from django.urls import reverse
另外,新增以下內容:
class OptionDelete(DeleteView):
model = Option
template_name = 'confirm_delete.html'
def get_success_url(self):
return reverse('poll_view', kwargs={'pk': self.object.poll_id})
- 新增
OptionDelete
繼承自通用編輯圖視 DeleteView
來實作刪除選項的功能
- 第 78 行,由名為
poll_view
的路徑規則,指定參數 pk
的值為欲被刪除的這筆紀錄的 poll_id
的值,反向產生路徑。
為什麼要用 reverse
來產生路徑?
其實這種反向產生網址路徑的方法才是官方比較建議的做法。
之前所示範的方式是自行組合出目的路徑,這樣比較直覺,但缺點是,日後若需調整路徑規則,就必須將視圖中所有相關的路徑全部修正到才行。
反向產生網址路徑的做法,必須先為路徑規則命名,在視圖中只需指定要透過哪條規則來產生路徑,並提供所需參數即可,剩下的事情 reverse
會處理。例如:要將原本的 poll/<int:pk>/
改為 poll/view/<int:pk>
,僅需修改 urls.py
即可,views.py
就不需要做任何調整。如此一來,跟路徑相關的操作就可以全部集中在 urls.py
處理。
範本
與 PollDelete
共用 confirm_delete.html
即可,不另行定義頁面範本。
更新投票主題檢視頁面範本
開啟 poll/default/templates/default/poll_detail.html
,修改為以下程式碼。
{% extends "base.html" %}
{% block content %}
<h1>{{ poll.subject }}</h1>
<a href="/option/create/{{ poll.id }}">新增選項</a>
<div>小提示!直接按選項文字就可以投票囉!</div>
<ul>
{% for option in options %}
<li>
<a href="/option/{{ option.id }}/">{{ option.title }}</a> : {{ option.count }} 票 |
<a href="/option/{{ option.id }}/update/">修改</a> |
<a href="/option/{{ option.id }}/delete/">刪除</a>
</li>
{% endfor %}
</ul>
{% endblock %}
- 新增第 5 行,加入「新增選項」的連結
- 將原本單行的
<li>
…</li>
拆成多行
- 新增第 11, 12 行的修改與刪除投票選項的連結
根路徑重新導向
先前在測試網站的時候,是使用 http://localhost/poll/
來存取服務。但是若僅以主機名稱 http://localhost/
來存取網站,會看到如下圖 Page not found 的錯誤訊息。
錯誤訊息的頁面上列出目前網站已定義的路徑規則,目前已定義的 10 條規則中,並不包含根路徑(也就是網站主機位址後不加其他路徑)的定義,因為找不到相對應的處理函式,所以產生了錯誤訊息。
在這個範例最主要的功能就是投票,因此,我們希望僅以主機名稱來存取網站時,會直接顯示投票主題列表,所以必須將根路徑重新導向到 poll/
來顯示投票主題列表。
修改 poll/default/urls.py
,新增第 3, 6 行:
from . import views
from django.views.generic import RedirectView
urlpatterns = [
path('', RedirectView.as_view(url='poll/')),
path('poll/', views.PollList.as_view()),
path('poll/create/', views.PollCreate.as_view()),
path('poll/<int:pk>/update/', views.PollUpdate.as_view()),
path('poll/<int:pk>/delete/', views.PollDelete.as_view()),
path('poll/<int:pk>/', views.PollDetail.as_view()),
path('option/<int:pk>/', views.PollVote.as_view()),
path('option/create/<int:pid>/', views.OptionCreate.as_view()),
path('option/<int:pk>/update/', views.OptionUpdate.as_view()),
path('option/<int:pk>/delete/', views.OptionDelete.as_view()),
]
- 新增第 3 行,從
django.views.generic
引用 RedirectView
- 新增第 6 行,定義路徑規則,將根路徑
''
導向到 'poll/'
完成修改後,接下來僅以主機名稱 http://localhost/
來存取網站時,會被重新導向至 http://localhost/poll/
,顯示投票主題列表頁面。
範例:投票選項
建立資料模型
修改
poll/default/models.py
,增加第 14 - 23 行:執行以下指令套用到資料庫:
將自訂資料模型也納入內建管理後臺
修改
poll/default/admin.py
,新增第 6 行,將Option
也加入後臺管理的範圍:修改完成後重新載入管理介面,應該會看到上面出現
Poll
跟Option
的管理界面。接著為投票主題「趕快來投票決定班遊地點!!!」,新增投票選項,記得要指定
Poll id
的值為1
(因為該投票主題的id
值為1
)視圖、網址、範本
投票主題檢視
網址
修改檔案
poll/default/urls.py
,新增第 9 行路徑規則:視圖
修改
poll/default/views.py
:django.views.generic
另外再多引用DetailView
PollDetail
的類別繼承自 Django 的DetailView
類別,它所參考的資模型是Poll
,並定義其get_context_data()
方法來取得與投票主題相關的選項紀錄。範本
新增投票選項檢視頁面範本檔案
poll/default/templates/default/poll_detail.html
啟動網站,在網址列輸入
http://localhost/poll/1/
會出現以下頁面:投票
這個範例的投票動作很簡單,不記錄投票的其他相關資訊,例:投票者、投票時間…等,僅單純增加票數而已。因此之前在定義資料模型的時候僅透過
Option
中的count
欄位來記錄選項被投了幾次。投票的流程簡化如下:在檢視投票主題時,可以直接點選該主題下的投票選項進行投票,投票後自動返回所屬投票主題檢視頁面。
網址
修改
poll/default/urls.py
,新增第 10 行:視圖
修改
poll/default/views.py
:django.views.generic
額外引用RedirectView
。PollVote
繼承自RedirectView
來實作投票完自動轉址的功能。範本
在增加了票數之後,就直接轉址回所屬的投票主題檢視頁面,所以這個功能不需要定義頁面範本。
修改投票選項檢視頁面範本檔案
poll/default/templates/default/poll_detail.html
:使用者表單
投票選項
新增資料(Create)
路徑
開啟
poll/default/urls.py
,增加第 11 行路徑規則:視圖
開啟
poll/default/views.py
,增加以下程式碼:OptionCreate
繼承自通用編輯類別CreateView
來實作新增投票選項的功能範本
與
PollCreate
,PollUpdate
共用form.html
即可,不另行定義頁面範本。因為在
models.py
裡定義Option
的資料模型時,並未指定title
這個欄位的標籤文字,所以預設會以欄位名稱當做輸入標籤文字。若想修改的話,可以在定義title
欄位型態時,如下方程式碼區塊的第 18 行,額外指定verbose_name
屬性即可,例:有另一種指定方式,在欄位型態的第一個參數直接放上標籤文字也可以,如:
修改資料(Update)
網址
開啟
poll/default/urls.py
,增加第 12 行路徑規則:視圖
開啟
poll/default/views.py
,增加以下程式碼:OptionUpdate
繼承自通用編輯視圖UpdateView
來實作修改投票選項的功能刪除資料(Delete)
網址
開啟
poll/default/urls.py
,增加第 13 行路徑規則:另外,請修改投票主題檢視的路徑規則如下:
name
參數,將此條規則命名為poll_view
。我們將在視圖中示範另一種指定成功返回路徑的方式,但需要先將欲使用的路徑規則命名。視圖
修改
poll/default/views.py
,新增第 5 行:另外,新增以下內容:
OptionDelete
繼承自通用編輯圖視DeleteView
來實作刪除選項的功能poll_view
的路徑規則,指定參數pk
的值為欲被刪除的這筆紀錄的poll_id
的值,反向產生路徑。為什麼要用
reverse
來產生路徑?其實這種反向產生網址路徑的方法才是官方比較建議的做法。
之前所示範的方式是自行組合出目的路徑,這樣比較直覺,但缺點是,日後若需調整路徑規則,就必須將視圖中所有相關的路徑全部修正到才行。
反向產生網址路徑的做法,必須先為路徑規則命名,在視圖中只需指定要透過哪條規則來產生路徑,並提供所需參數即可,剩下的事情
reverse
會處理。例如:要將原本的poll/<int:pk>/
改為poll/view/<int:pk>
,僅需修改urls.py
即可,views.py
就不需要做任何調整。如此一來,跟路徑相關的操作就可以全部集中在urls.py
處理。範本
與
PollDelete
共用confirm_delete.html
即可,不另行定義頁面範本。更新投票主題檢視頁面範本
開啟
poll/default/templates/default/poll_detail.html
,修改為以下程式碼。<li>
…</li>
拆成多行根路徑重新導向
先前在測試網站的時候,是使用
http://localhost/poll/
來存取服務。但是若僅以主機名稱http://localhost/
來存取網站,會看到如下圖 Page not found 的錯誤訊息。錯誤訊息的頁面上列出目前網站已定義的路徑規則,目前已定義的 10 條規則中,並不包含根路徑(也就是網站主機位址後不加其他路徑)的定義,因為找不到相對應的處理函式,所以產生了錯誤訊息。
在這個範例最主要的功能就是投票,因此,我們希望僅以主機名稱來存取網站時,會直接顯示投票主題列表,所以必須將根路徑重新導向到
poll/
來顯示投票主題列表。修改
poll/default/urls.py
,新增第 3, 6 行:django.views.generic
引用RedirectView
''
導向到'poll/'
完成修改後,接下來僅以主機名稱
http://localhost/
來存取網站時,會被重新導向至http://localhost/poll/
,顯示投票主題列表頁面。