前言 ´・ᴗ・`
- 所謂表單 就是一些要我們填寫的表格 比方註冊網站的登記表
- 本篇帶你用Django 玩玩表單
- 本篇內容將會幫助你學習…
- 1 HTML表單的一般處理方式
- 2 Django forms類 表單處理方式 使用方法
- 3 爲圖書館應用創造一個 續借renew 的表單
HTML表單結構
我們看個簡單的代碼
<form action="/team_name_url/" method="post">
<label for="team_name">Enter name: </label>
<input id="team_name" type="text" name="name_field" value="Default name for team.">
<input type="submit" value="OK">
</form>
- action 就是 我們用戶填完表 submit提交以後 我們提交的url地址
- method 就是 請求類型 是get還是post
- get 適合 不更改數據庫的表單 比如 搜索框
- post 適合 更改數據庫的表單 比如註冊 登錄 錄入個人信息等
處理表單的流程(Django處理的流程)
- 顯示默認表單 編輯框裏的東西 有時稱爲佔位符placeholder
此時表單被稱爲未綁定(un bind) 沒有任何來自用戶的信息注入 綁定啥呢? - 提交請求 服務器接收數據,並將其綁定到表單。
這時 數據綁定到表單了 - 檢查 淨化數據 然後從數據中提取必要信息 轉換成python對象 比如日期對象
所謂檢查內容 避免類似XSS攻擊的惡意代碼 刪除可能用於向服務器發送惡意內容的無效字符 - 根據數據庫模型 對數據進行限制 (例如,在正確的日期範圍內,不是太短或太長等)
因爲前面已經把數據弄成對象了 現在比較值 限制什麼都很簡單
當然現在簡單的限制數據檢查 是讓前端來幹了 分擔服務器工作
複雜的檢查一般是AJAX 也就動態加載 對錶單信息的驗證結果 而不是重新刷新頁面(太low了?) - 驗證檢查值是否適合該字段
- 如果數據無效,重新顯示錶單
- 如果數據都有效,執行必要的操作(例如保存數據,發送表單和發送電子郵件,返回搜索結果,上傳文件等)
- 完成所有操作後,將用戶重定向到另一個頁面
Forms
Django提供了Forms 這個工具來封裝這些表單
其思維是 既然數據最終走向的是數據庫
那麼語法也應該接近ORM的寫法
我們看例子就懂了
from django import forms
class RenewBookForm(forms.Form):
renewal_date = forms.DateField(help_text="Enter a date between now and 4 weeks (default 3).")
除了DateField 還有其他的 如:
BooleanField, CharField, ChoiceField, TypedChoiceField, DateField, DateTimeField, DecimalField, DurationField, EmailField, FileField, FilePathField, FloatField, ImageField, IntegerField, GenericIPAddressField, MultipleChoiceField, TypedMultipleChoiceField, NullBooleanField, RegexField, SlugField, TimeField, URLField, UUIDField, ComboField, MultiValueField, SplitDateTimeField, ModelMultipleChoiceField, ModelChoiceField.
然而我覺得 用到的時候再說是最好的方式
這些field有些共有屬性
- required: 如果爲True,則該字段不能爲空
- label: 在 HTML 中呈現字段時使用的標籤。如果未指定label,則 Django 將通過大寫第一個字母、並用空格替換下劃線(例如續訂日期)的方式,從字段名稱創建一個。
- label_suffix: django連編輯框前的說明文字都包了2333
默認情況下,標籤後面會顯示冒號(例如續借日期: )。此參數允許您指定包含其他字符的不同後綴。 - initial: 顯示錶單時,字段的初始值 就是佔位符的意思
- widget: 要使用的顯示小部件(這個後面會講是什麼“小部件”)
- help_text :可以在表單中顯示的附加文本,用於說明如何使用該字段。
- error_messages: 字段的錯誤消息列表。如果需要,您可以使用自己的消息,覆蓋這些消息。
- validators: 驗證時 調用的驗證函數列表
- localize: 啓用表單數據輸入的本地化 就是語言的問題啦
- disabled: 如果爲True 無法編輯其值 禁用狀態
這裏 對於我們圖書館應用 我們就 設定一個 續借的表單好了
我們命名爲“renewal_date” 作爲 續借日期的字段field 名字
驗證數據
我們想驗證數據 可以採用 覆蓋原有的驗證函數來實現
在view class 視圖那邊 我們可以這麼寫 locallibrary/catalog/forms.py:
from django import forms
from django.core.exceptions import ValidationError
from django.utils.translation import ugettext_lazy as _
import datetime #for checking renewal date range.
class RenewBookForm(forms.Form):
renewal_date = forms.DateField(help_text="Enter a date between now and 4 weeks (default 3).")
def clean_renewal_date(self):
data = self.cleaned_data['renewal_date']
#檢測日期是不是過去的日期
if data < datetime.date.today():
raise ValidationError(_('Invalid date - renewal in past'))
#檢測 還書日期是否在1個月內
if data > datetime.date.today() + datetime.timedelta(weeks=4):
raise ValidationError(_('Invalid date - renewal more than 4 weeks ahead'))
# Remember to always return the cleaned data.
return data
- 注意命名 clean_renewal_date 驗證函數都是clean_<字段名稱> 這種格式的
- 注意 cleaned_data 函數 這玩意太強了 直接淨化數據中那些不合法字段(比如惡意代碼之類的),獲取到有用的信息 然後轉成合法的python對象 這裏就是date日期對象
- ValidationError 這玩意就是說 驗證不通過 然後彈出錯誤信息給客戶看 用
_()
函數
搞定form的設置 我們添加url:locallibrary/catalog/urls.py
path('book/<uuid:pk>/renew/', views.renew_book_librarian, name='renew-book-librarian'),
這句話就是 匹配form action填寫的url地址 利用uuid格式 提取關鍵值(在這裏 就是書的id)
然後存到pk(primary key縮寫)的變量中去
然後我們用view的函數renew_book_librarian處理提交上來的數據
view處理提交的數據
上面把鍋甩給了view 這裏我們view就要面對現實了
大致思路就是區分method 是POST還是GET?兩種上傳數據的方式帶來兩種不同的處理方式
上代碼:
from django.shortcuts import get_object_or_404
from django.http import HttpResponseRedirect
from django.urls import reverse
import datetime
from .forms import RenewBookForm
def renew_book_librarian(request, pk):
#首先找到書的實例(我們是續借具體的書 書都找不到還續借啥?)
book_inst=get_object_or_404(BookInstance, pk = pk)
# 如果是POST方法
if request.method == 'POST':
# 用POST解析 然後用form對象去給數據建模 也就是格式化 結構化數據
form = RenewBookForm(request.POST)
#然後調用 clean_renewal_date()
if form.is_valid():
book_inst.due_back = form.cleaned_data['renewal_date']
book_inst.save()
# redirect to a new URL:
return HttpResponseRedirect(reverse('all-borrowed') )
# If this is a GET (or any other method) create the default form.
else:
proposed_renewal_date = datetime.date.today() + datetime.timedelta(weeks=3)
form = RenewBookForm(initial={'renewal_date': proposed_renewal_date,})
return render(request, 'catalog/book_renew_librarian.html', {'form': form, 'bookinst':book_inst})
-
RenewBookForm 這裏 首先是 這個就是我們之前forms.py 那個類
這裏涉及幾個概念
一個是 這就是典型的 結構化 也就是裸數據弄成python對象以後 讓對比值 限制值 so easy
第二是 這也是稱爲“綁定”binding數據操作 -
return HttpResponseRedirect(reverse(‘all-borrowed’) )
這就是之前說的 表單成功提交 數據ok的話 我們重定向到另一個頁面 (受view管理的當然) -
get_object_or_404(): 根據模型的主鍵值,從模型返回指定的對象,如果記錄不存在,則引發Http404 異常(未找到)。
-
HttpResponseRedirect: 這將創建指向指定URL的重定向(HTTP狀態代碼 302)。
-
reverse(): 反向定位 之前也講過 通過映射的名字“all-borrow” 得到url值 然後作爲參數讓HTTP重定向
然後 如果GET方式 或者POST數據不合法 一樣render打包數據回去 送你一個頁面
加上上一節 我們限定了 只有圖書管理員纔能有的權限“set_book_as_returned”
所以對於這個“all borrow”頁面 我們可以加裝飾器來限定:
@permission_required('catalog.can_mark_returned')
模板編輯
/catalog/templates/catalog/book_renew_librarian.html
{% extends "base_generic.html" %}
{% block content %}
<h1>Renew: {{bookinst.book.title}}</h1>
<p>Borrower: {{bookinst.borrower}}</p>
<p{% if bookinst.is_overdue %} class="text-danger"{% endif %}>Due date: {{bookinst.due_back}}</p>
<form action="" method="post">
{% csrf_token %}
<table>
{{ form }}
</table>
<input type="submit" value="Submit" />
</form>
{% endblock %}
這裏注意:在表單標籤內添加的{% csrf_token %} ,是 Django 跨站點僞造(XSS攻擊)保護的一部分。
然後 我們再簡單限制上一節 有關圖書管理員的管理頁面 “續借按鈕”的設計 bookinstance_staff_management.html
{% extends "base_generic.html" %}
{% block content %}
<h1>Borrowed books</h1>
{% if bookinstance_list %}
<ul>
{% for bookinst in bookinstance_list %}
<li class="{% if bookinst.is_overdue %}text-danger{% endif %}">
<a href="{% url 'book-detail' bookinst.book.pk %}">{{bookinst.book.title}}</a> ({{ bookinst.due_back }}) - {{bookinst.borrower}} - {% if perms.catalog.set_book_as_returned %}- <a href="{% url 'renew-book-librarian' bookinst.id %}">Renew</a> {% endif %}
</li>
{% endfor %}
</ul>
{% else %}
<p>There are no books borrowed.</p>
{% endif %}
{% endblock %}
總結 ´◡`
runserver http://127.0.0.1:8000/catalog/borrowed/
invalidate input:
下一節我們簡要複習並拓展之前學習的內容 完善我們的圖書館應用
服務端編程(十四)- Django - 視圖 模板設計的補充
我的專欄 希望能夠幫到你 ( •̀ ω •́ )✧
-
本文專欄
手把手帶你學後端(服務端) -
想學習數據庫嘛? 不妨從MySQL入手
MySQL專欄 -
python這麼火 想要深入學習python 玩一下簡單的應用嘛?
python應用 -
謝謝大佬支持! 萌新有禮了:)