分頁模塊
原始分頁器
視圖函數
from django.shortcuts import render
from django.http import HttpResponse
from django.urls import reverse
from django.utils.safestring import mark_safe
# Create your views here.
player_list = ['Scholes', 'Keane', 'Beckham', 'Giggs']
def index(request):
name = 'Beckham'
return render(request, 'index.html', {'name': name})
test_list = []
for i in range(100):
test_list.append(i)
def user_list(request):
# 當前頁碼
current_page = request.GET.get('p', 1)
# 由於獲取的是字符串,所以需要轉換成數字
current_page = int(current_page)
# 算頁數
count, remainder = divmod(len(test_list), 10)
if remainder:
count += 1
# 創建頁碼html
page_html_list = []
for i in range(1, count+1):
if i == current_page:
page_html_list.append('%s' % (i, i))
else:
page_html_list.append('%s' % (i, i))
page_str = ''.join(page_html_list)
page_str = mark_safe(page_str)
current_page = int(current_page)
list_start = (current_page - 1) * 10
list_end = current_page * 10
show_list = test_list[list_start:list_end]
return render(request, 'user_list.html', {'test_list': show_list, 'page_str': page_str})
HTML
Title
-
{% for item in test_list %}
- {{ item }} {% endfor %}
知識點:
1、在網頁上為了安全,如果是從后端返回的渲染模板的字符串帶有Html的標簽,則默認情況下是當作字符串處理,而不解釋為Html標簽。

2、解決辦法:
(1)、模板中使用safe函數

(2)、在后端處理


利用cookie定制分頁
可以通過Cookie實現每個分頁顯示的條目數量
HTML
Title
-
{% for item in items_show_list %}
- {{ item }} {% endfor %}
視圖函數
from django.shortcuts import render, redirect
from django.http import HttpResponse
from django.urls import reverse
from django.utils.safestring import mark_safe
import datetime
# Create your views here.
player_list = ['Scholes', 'Keane', 'Beckham', 'Giggs']
class Pagination(object):
def __init__(self, itemcount_per_page, item_count, current_page=1, pagination_show_count=11):
self.itemcount_per_page = itemcount_per_page
self.item_count = item_count
self.current_page = current_page
self.pagination_show_count = pagination_show_count
@property
def start(self):
"""計算條目起始索引"""
return (self.current_page - 1) * self.itemcount_per_page
@property
def end(self):
"""計算條目結束索引"""
return self.current_page * self.itemcount_per_page
@property
def page_count(self):
"""計算總頁數"""
total_count, remainder = divmod(self.item_count, self.itemcount_per_page)
if remainder:
total_count += 1
return total_count
def make_page_str(self):
"""生成頁碼html"""
# 如果總頁數少於要顯示的頁數
page_str_list = []
if self.page_count <= self.pagination_show_count:
pagination_start = 1
pagination_end = self.page_count + 1
else:
# 如果是頁碼在中間的情況
pagination_start = self.current_page - (self.pagination_show_count - 1)/2
pagination_end = self.current_page + (self.pagination_show_count + 1)/2
# 頁碼在頭
if self.current_page <= (self.pagination_show_count + 1)/2:
pagination_start = 1
pagination_end = self.pagination_show_count + 1
# 頁碼在后面
if self.current_page + (self.pagination_show_count - 1)/2 >= self.page_count:
pagination_end = self.page_count + 1
pagination_start = self.page_count - self.pagination_show_count + 1
if self.current_page != 1:
page_str_list.append('上一頁' % (self.current_page - 1))
else:
page_str_list.append('上一頁')
for i in range(int(pagination_start), int(pagination_end)):
if i == self.current_page:
page_str_list.append('%s' % (i, i))
else:
page_str_list.append('%s' % (i, i))
if self.current_page != self.page_count:
page_str_list.append('下一頁' % (self.current_page + 1))
else:
page_str_list.append('下一頁')
page_str = ''.join(page_str_list)
page_str = mark_safe(page_str)
return page_str
items_list = []
for i in range(200):
items_list.append(i)
def user_list(request):
# 當前頁碼
current_page = request.GET.get('p', 1)
# 由於獲取的是字符串,所以需要轉換成數字
current_page = int(current_page)
# 每頁顯示的條目數
itemcount_per_page = request.COOKIES.get('items_count_per_page', 10)
itemcount_per_page = int(itemcount_per_page)
# 顯示的頁碼數
pagination_show_count = 11
page_obj = Pagination(itemcount_per_page, len(items_list), current_page, pagination_show_count)
html_str = page_obj.make_page_str()
items_show_list = items_list[page_obj.start:page_obj.end]
return render(request, 'user_list.html', {'items_show_list': items_show_list, 'page_str': html_str})
auth_db = {'Treelight': 'abc123'}
def login(request):
# 處理get請求
if request.method == 'GET':
return render(request, 'login.html')
# 處理post請求
else:
username = request.POST.get('username', None)
password = request.POST.get('pwd', None)
# 獲取用戶名是否存在的結果
db_pwd = auth_db.get(username)
# 用戶名不存在
if not db_pwd:
return redirect('/login/')
# 用戶存在
else:
# 密碼正確
if password == db_pwd:
res = redirect('/index/')
now = datetime.datetime.utcnow()
expire = now + datetime.timedelta(seconds=10)
res.set_cookie('auth_code', username, expires=expire)
return res
# 密碼錯誤
else:
return redirect('/login/')
def index(request):
username = request.COOKIES.get('auth_code')
if not username:
return redirect('/login/')
return render(request, 'index.html', {'username': username})

但以上的太麻煩了,所以Django提供了分頁模塊,以方便當數據量很大的時候,進行分布處理。
初次使用
使用步驟
一、導入
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
二、實例化
paginator = Paginator(<分頁對象列表>, <每頁的條目數量>) # 生成一個Paginator對象
三、使用page方法
page = paginator.page(<頁碼>):顯示對應頁碼條目,並且生成一個page類
概述
django提供的分布模塊,主要是用到兩個類:Paginator和Page類,有各自的屬性和方法
Paginator
下面介紹此類的常用屬性和方法。
一、創建方法
paginator = Paginator(<分頁對象列表>, <每頁的條目數量>) # 生成一個Paginator對象
二、常用屬性
Paginator對象.count:分頁對象列表的個數
Paginator對象.num_pages:頁碼數
Paginator對象.page_range:頁碼范圍
Page
一、創建方法
page = paginator對象.page(<頁碼>)
二、常用方法
page對象.next_page_number() # 獲取下一頁的頁碼
page對象.previous_page_number() # 獲取上一頁的頁碼
page對象.has_next() # 是否有下一頁
page對象.has_previous() # 是否有上一頁
三、分頁例子
此例子主要是演示分頁器的使用,主要功能
1、點擊頁碼跳轉到相應的頁碼
2、有上一頁、下一頁的功能
3、如果頁碼數量多,則會出現省略號顯示
視圖
from django.shortcuts import render
from django.http import HttpResponse
from app01 import models
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
# Create your views here.
def index(request):
books = models.Book.objects.all()
items_per_page = 6
paginator = Paginator(books, items_per_page)
pagination_num = 11 # 顯示的頁碼個數
try:
num = int(request.GET.get('p', 1)) # 獲取要顯示的頁碼數
# print(paginator.count)
# print(paginator.page_range)
page = paginator.page(num)
except Exception as e:
num = 1
page = paginator.page(num)
page_range = paginator.page_range
if pagination_num < paginator.count:
if num <= (pagination_num + 1) / 2:
# 要顯示的頁碼靠前
page_range = page_range[:pagination_num]
flag = 1 # 用於給模板渲染
elif paginator.num_pages - num < (pagination_num + 1) / 2:
# 要顯示的頁碼靠后
page_range = page_range[paginator.num_pages - pagination_num:]
flag = 2
else:
start = int(num - (pagination_num - 1) / 2 - 1)
end = int(num + (pagination_num - 1) / 2)
page_range = page_range[start:end]
# 顯示的頁碼在中間
flag = 3
# print(page.next_page_number())
# print(page.previous_page_number())
# print(page.has_next())
# print(page.has_previous())
return render(request, 'index.html', locals())
def add(request):
books = []
for i in range(100):
book = models.Book(name='Book' + str(i), price=30 + i * i)
books.append(book)
models.Book.objects.bulk_create(books)
return HttpResponse('OK')
HTML
Title
-
{% for book in page %}
- {{ book.name }} {% endfor %}
認證系統----Cookie和Session
前敘
A用戶登錄淘寶時,會在“購物車”看到A的購物記錄。B登錄,則看到自己的記錄。服務器好像能智能識別並且記住用戶,返回用戶相對應的數據,而且不用每一次連接都需要輸入用戶名密碼。但Http協議是一種無狀態的協議,它不能保存用戶的相關信息。那么以上所說的淘寶的登陸是怎么樣實現的?這就需要Cookie和Session這兩個東西。
Cookie
什么是Cookie?這是一個存放在客戶端瀏覽器的容器。存放什么呢?當你在登錄頁面輸入用戶名密碼時,點提交,會帶着Cookie過去,服務器會驗證。如果驗證通過,服務器會返回一個鍵值對,鍵是sessionID,而值是隨機生成的一串字符串。然后把這個鍵值對發給客戶端瀏覽器,客戶端瀏覽器則把這個鍵值對保存在Cookie里。下一次訪問服務器時,則帶着Cookie訪問。服務器則對Cookie進行驗證。Cookie除了可放登陸信息,也可以把其他的個人信息發給服務器處理。
Session
什么是Session?其實是一個存放在服務器端的容器,這又是存放什么呢?在上述Cookie中已經說過,瀏覽器把用戶名密碼發送,服務器如果驗證通過則會生成鍵值對返回給客戶端。但第二次瀏覽器帶着Cookie過來時,服務器又是怎么樣驗證?其實第一次登陸時,服務器會把生成的Cookie隨機字符串保存在session中。這樣,以后瀏覽器訪問時,可以把瀏覽器的Cookie中sessionID值拿來與保存在Session中的鍵值對進行比對,進行驗證。這個Session默認會保存在django_session的數據庫中,字段包含session_id、session_data、過期時間。
注意:對於同一個服務器,同一個瀏覽器只保存一個用戶的信息。
一般認證流程

Cookie的操作
獲取Cookie
request.COOKIES['key']
request.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None)
#參數:
default: 默認值
salt: 加密鹽
max_age: 后台控制過期時間
設置Cookie
rep = HttpResponse(...) 或 rep = render(request, ...) 或 rep = redirect() rep.set_cookie(key,value,...) rep.set_signed_cookie(key,value,salt='加密鹽',...)
注銷
注銷很簡單,可把session或cookie刪除
request.session.flush() # 刪除session # 刪除cookie rep = HttpResponse(...) 或 rep = render(request, ...) 或 rep = redirect() rep.delete_cookie(鍵)
Session操作
request.session['is_login'] = True # 在數據庫生成一個隨機session_key,並且設置一個鍵為is_login值為True的字典保存在此key中,key同時返回給客戶端 request.session.flush() # 注銷,把數據庫記錄清空 request.session.session_key # 獲取session_key request.session.delete(session_key) # 在表django_session中刪除對應的session,但如果參數為None,則刪除自己的。
用戶認證的例子,功能如下:
1、驗證登錄
2、注銷
3、使用了裝飾器認證
views
from django.shortcuts import render, redirect
from app01 import models
# Create your views here.
def auth(func):
"""
認證裝飾器
:param func:
:return:
"""
def inner(request, *args, **kwargs):
if not request.session.get('is_login'):
return redirect('/login/')
res = func(request, *args, **kwargs)
return res
return inner
@auth
def index(request):
# if not request.session.get('is_login'):
# 上面的語句django幫我們做了兩件事
# 1、從客戶端發過來的字典獲取鍵"sessionID"的值
# 2、然后在對比session的數據:以上面的值作為鍵,獲取此用戶的信息(字典的形式),判斷此用戶是否有is_login的鍵
# return redirect('/login/')
name = request.session['username']
return render(request, 'index.html', locals())
def login(request):
if request.method == 'POST':
username = request.POST.get('username')
pwd = request.POST.get('pwd')
users = models.UserInfo.objects.filter(username=username, pwd=pwd)
if users: # 用戶名密碼正確
request.session['is_login'] = True
# 上面的語句django幫我們做了兩件事
# 1、隨機生成一個{'sessionID:<值>}鍵值對,發送給客戶端
# 2、保存一個鍵值對在服務器的session,形式為{<上面的值>:{'is_login':True'}},默認保存
# 在數據庫中的django_session
request.session['username'] = username
return redirect('/index/')
else:
return redirect('/login/')
return render(request, 'login.html')
def log_out(request):
request.session.flush()
# 相當於models.django_session.filter(session_id = <此次會話鍵為sessionID的值>).delete()
# 把數據庫記錄清空
return redirect('/login/')
@auth # 使用裝飾器
def add_book(request):
return render(request, 'add_book.html')
add_book.html
Title
這是一個添加書本信息的頁面
index.html
Title
歡迎你,{{ name }}
注銷
login.html
Title
auth模塊
Django中已經內置了認證模塊供我們使用。原理是一樣的,相比上面的例子,不同的有以下兩點:
1、auth模塊已經內置了認證功能,簡化了我們的操作。
2、auth模塊不需要新增數據庫,我們只需要使用django自帶的數據表auth_user即可
導入
from django.contrib import auth # 用於認證模塊
from django.contrib.auth.models import User # 提供的auth_user數據庫接口
auth模塊的屬性、方法
# 屬性
request.user.is_authenticated # 判斷請求用戶是否已經驗證
# 方法
auth.logout(request) # 注銷用戶
auth.authenticate(username=username, password=password) # 驗證用戶,驗證通過則返回用戶類;
# 注意:驗證的用戶需用用models.<類名>.objects.create_user()創建,會對密碼加密
auth.login(request, user) # 把用戶信息寫進session
User.objects.create_user(username=username, password=password) # 通過User接口訪問auth_session表,創建用戶
例子
此例子可實現注冊、登錄、注銷的功能
視圖函數
from django.shortcuts import render, redirect
from django.contrib import auth # 用戶認證模塊
from django.contrib.auth.models import User # 數據表auth_user的接口
# Create your views here.
def index(request):
if request.user.is_authenticated: # 判斷是否已經驗證
return render(request, 'index.html')
return redirect('/login/')
def log_out(request):
auth.logout(request) # 相當於request.session.flush()
return redirect('/login/')
def login(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
user = auth.authenticate(username=username, password=password)
# 對用戶名密碼進行認證,認證通過則會返回值
if user:
auth.login(request, user)
# 把記錄寫到django_session
return redirect('/')
else:
return redirect('/login/')
return render(request, 'login.html')
def reg(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
User.objects.create_user(username=username, password=password)
# 把用戶記錄到auth_user表中
return redirect('/login/')
return render(request, 'reg.html')
reg.html
Title
login.html
Title
index.html
Title
<script src="/static/dist/js/bootstrap.js"></script>
auth_user表增加字段
auth模塊使用的是Django提供給我們的auth_user表,但現在我們需要在此表新增一個tel字段,怎么辦呢?按以下步驟即可完成:
步驟一、在models創建一個類,注意需要繼承一個AbstractUser類,而且此類的字段只需要寫新增的字段即可。
步驟二、在settings.py中加上以下配置
AUTH_USER_MODEL = '<App名>.<model名>'
步驟三、python manage.py makemigrations
python manage.py migrate
利用Ajax實現用戶注冊、登錄、注銷
視圖函數
from django.shortcuts import render, redirect
from django.http import HttpResponse
from django.contrib import auth
from django.contrib.auth.models import User
# Create your views here.
def index(request):
if request.user.is_authenticated:
return render(request, 'index.html')
return redirect('/login/')
def login(request):
res = {'is_login': False}
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
user = auth.authenticate(username=username, password=password)
if user:
auth.login(request, user)
res['is_login'] = True
import json
return HttpResponse(json.dumps(res))
return render(request, 'login.html')
def reg(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
User.objects.create_user(username=username, password=password)
import json
return HttpResponse(json.dumps({'res': True}))
# 由於需要和js交換,所以需要把字典序列化成json標准格式
return render(request, 'reg.html')
def log_out(request):
auth.logout(request)
return redirect('/login/')
index.html
Title
<script src="/static/dist/js/bootstrap.js"></script>
reg.html
Title
<script src="/static/dist/js/bootstrap.js"></script>
{% csrf_token %}
這是一個注冊頁面
</div>
</div>
login.html
Title
<script src="/static/dist/js/bootstrap.js"></script>
{% csrf_token %}
這是一個登錄頁面
Form模塊
作用
在模板中生成各種Form表單標簽,然后可以驗證各種在標簽中的輸入,比如注冊時,用戶名的長度是否合適。下面以注冊為例說明怎么使用Form表單驗證。
Form表單類
Form表單的創建
在視圖函數中定義一個繼承Form的類,建議放在py文件里
class RegForm(forms.Form): # 必須繼承此類
# 定義表單
username = forms.CharField(min_length=8, error_messages={'required': '不能為空'})
# 定義了字段的規則,以下類同,同時也定義了錯誤顯示的信息
password = forms.CharField(min_length=2, max_length=12,
widget=widgets.PasswordInput()) # 定義了標簽的屬性
repeat_password = forms.CharField(min_length=2, max_length=12,
widget=widgets.PasswordInput())
email = forms.EmailField()
此類實例化后,可渲染給模板使用。例子如下:
用戶名 {{ reg_form.username }}{{ reg_form.errors.username.0 }}
{{ form.username.label }} # 利用表單中字段對應的label參數渲染,如username = fields.CharField(label='用戶名:')
from django.shortcuts import render, redirect
from django import forms
from django.forms import widgets, fields
class FM(forms.Form):
"""驗證表單"""
# 此名稱必須要與需要驗證的html中的name屬性對應
user = fields.CharField(error_messages={'required': '用戶名不能為空'},
widget=widgets.Textarea(attrs={'class': 'c1'}))
pwd = fields.CharField(
min_length=6,
max_length=12,
error_messages={'required': '密碼不能為空',
'min_length': '密碼至少需要6位',
'max_length': "密碼不多於12位"}
)
email = fields.EmailField(error_messages={'required': '郵箱不能為空'})

內置的字段參數
Field
required=True, 是否允許為空
widget=None, HTML插件
label=None, 用於生成Label標簽或顯示內容
initial=None, 初始值
help_text='', 幫助信息(在標簽旁邊顯示)
error_messages=None, 錯誤信息 {'required': '不能為空', 'invalid': '格式錯誤'}
show_hidden_initial=False, 是否在當前插件后面再加一個隱藏的且具有默認值的插件(可用於檢驗兩次輸入是否一直)
validators=[], 自定義驗證規則
localize=False, 是否支持本地化
disabled=False, 是否可以編輯
label_suffix=None Label內容后綴
CharField(Field)
max_length=None, 最大長度
min_length=None, 最小長度
strip=True 是否移除用戶輸入空白
IntegerField(Field)
max_value=None, 最大值
min_value=None, 最小值
FloatField(IntegerField)
...
DecimalField(IntegerField)
max_value=None, 最大值
min_value=None, 最小值
max_digits=None, 總長度
decimal_places=None, 小數位長度
BaseTemporalField(Field)
input_formats=None 時間格式化
DateField(BaseTemporalField) 格式:2015-09-01
TimeField(BaseTemporalField) 格式:11:12
DateTimeField(BaseTemporalField)格式:2015-09-01 11:12
DurationField(Field) 時間間隔:%d %H:%M:%S.%f
...
RegexField(CharField)
regex, 自定制正則表達式
max_length=None, 最大長度
min_length=None, 最小長度
error_message=None, 忽略,錯誤信息使用 error_messages={'invalid': '...'}
EmailField(CharField)
...
FileField(Field)
allow_empty_file=False 是否允許空文件
ImageField(FileField)
...
注:需要PIL模塊,pip3 install Pillow
以上兩個字典使用時,需要注意兩點:
- form表單中 enctype="multipart/form-data"
- view函數中 obj = MyForm(request.POST, request.FILES)
URLField(Field)
...
BooleanField(Field)
...
NullBooleanField(BooleanField)
...
ChoiceField(Field)
...
choices=(), 選項,如:choices = ((0,'上海'),(1,'北京'),)
required=True, 是否必填
widget=None, 插件,默認select插件
label=None, Label內容
initial=None, 初始值
help_text='', 幫助提示
ModelChoiceField(ChoiceField)
... django.forms.models.ModelChoiceField
queryset, # 查詢數據庫中的數據
empty_label="---------", # 默認空顯示內容
to_field_name=None, # HTML中value的值對應的字段
limit_choices_to=None # ModelForm中對queryset二次篩選
ModelMultipleChoiceField(ModelChoiceField)
... django.forms.models.ModelMultipleChoiceField
TypedChoiceField(ChoiceField)
coerce = lambda val: val 對選中的值進行一次轉換
empty_value= '' 空值的默認值
MultipleChoiceField(ChoiceField)
...
TypedMultipleChoiceField(MultipleChoiceField)
coerce = lambda val: val 對選中的每一個值進行一次轉換
empty_value= '' 空值的默認值
ComboField(Field)
fields=() 使用多個驗證,如下:即驗證最大長度20,又驗證郵箱格式
fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),])
MultiValueField(Field)
PS: 抽象類,子類中可以實現聚合多個字典去匹配一個值,要配合MultiWidget使用
SplitDateTimeField(MultiValueField)
input_date_formats=None, 格式列表:['%Y--%m--%d', '%m%d/%Y', '%m/%d/%y']
input_time_formats=None 格式列表:['%H:%M:%S', '%H:%M:%S.%f', '%H:%M']
FilePathField(ChoiceField) 文件選項,目錄下文件顯示在頁面中
path, 文件夾路徑
match=None, 正則匹配
recursive=False, 遞歸下面的文件夾
allow_files=True, 允許文件
allow_folders=False, 允許文件夾
required=True,
widget=None,
label=None,
initial=None,
help_text=''
GenericIPAddressField
protocol='both', both,ipv4,ipv6支持的IP格式
unpack_ipv4=False 解析ipv4地址,如果是::ffff:192.0.2.1時候,可解析為192.0.2.1, PS:protocol必須為both才能啟用
SlugField(CharField) 數字,字母,下划線,減號(連字符)
...
UUIDField(CharField) uuid類型
...
widget插件參數
TextInput(Input) NumberInput(TextInput) EmailInput(TextInput) URLInput(TextInput) PasswordInput(TextInput) HiddenInput(TextInput) Textarea(Widget) DateInput(DateTimeBaseInput) DateTimeInput(DateTimeBaseInput) TimeInput(DateTimeBaseInput) CheckboxInput Select NullBooleanSelect SelectMultiple RadioSelect CheckboxSelectMultiple FileInput ClearableFileInput MultipleHiddenInput SplitDateTimeWidget SplitHiddenDateTimeWidget SelectDateWidget
常用的選擇插件
# 單radio,值為字符串 # user = fields.CharField( # initial=2, # widget=widgets.RadioSelect(choices=((1,'上海'),(2,'北京'),)) # ) # 單radio,值為字符串 # user = fields.ChoiceField( # choices=((1, '上海'), (2, '北京'),), # initial=2, # widget=widgets.RadioSelect # ) # 單select,值為字符串 # user = fields.CharField( # initial=2, # widget=widgets.Select(choices=((1,'上海'),(2,'北京'),)) # ) # 單select,值為字符串 # user = fields.ChoiceField( # choices=((1, '上海'), (2, '北京'),), # initial=2, # widget=widgets.Select # ) # 多選select,值為列表 # user = fields.MultipleChoiceField( # choices=((1,'上海'),(2,'北京'),), # initial=[1,], # widget=widgets.SelectMultiple # ) # 單checkbox # user = fields.CharField( # widget=widgets.CheckboxInput() # ) # 多選checkbox,值為列表 # user = fields.MultipleChoiceField( # initial=[2, ], # choices=((1, '上海'), (2, '北京'),), # widget=widgets.CheckboxSelectMultiple # )
但以上選擇插件使用時,比如Select插件,只會靜態生成一個選擇列表,當有新數據添加到數據庫時,此列表不會自動更新。解決辦法是重寫構造函數,如下:

插件使用注意事項
使用日期插件
birth_date = forms.DateField(
widget=fwidgets.DateInput(attrs={'type': 'date', 'class': 'form-control'})
)
Form表單類的屬性與方法
# 實例化
reg-form = RegForm() # 實例化,參數為空
reg_form = RegForm(request.POST) # 把要驗證的數據放進表單里
reg_form.is_valid() # 把表單數據分成兩部分:干凈數據(clean_data)和錯誤數據,然后返回是否所有數據通過驗證
reg_form.cleaned_data # 獲取干凈數據
reg_form.errors # 返回錯誤字典,形如:{'username':[errormsg1、errormsg2], 'password':...}
reg_form.add_error(字段名,錯誤提示) # 在字段名中添加錯誤信息
頁面注冊驗證例子
HTML
Title
<script src="/static/jquery.cookie.min.js"></script>
<script src="/static/dist/js/bootstrap.js"></script>
<style>
.error {
color: red,
}
</style>
>這是一個注冊頁面
表單創建
from django import forms # 導入forms模塊
from django.forms import widgets # 導入插件
class RegForm(forms.Form): # 必須繼承此類
# 定義表單
username = forms.CharField(min_length=8, error_messages={'required': '不能為空'})
# 定義了字段的規則,以下類同,同時也定義了錯誤顯示的信息
password = forms.CharField(min_length=2, max_length=12,
widget=widgets.PasswordInput()) # 定義了標簽的屬性
repeat_password = forms.CharField(min_length=2, max_length=12,
widget=widgets.PasswordInput())
email = forms.EmailField()
視圖函數
def reg(request):
if request.method == 'POST':
reg_form = forms.RegForm(request.POST) # 實例化表單,傳了從客戶端返回來的數據
if reg_form.is_valid():
# 把表單數據分成兩部分:干凈數據(clean_data)和錯誤數據,然后返回是否所有數據通過驗證
print('is_valid')
print(reg_form.cleaned_data)
else:
print(reg_form.errors['username'])
# 返回錯誤字典,形如:{'username':[<errormsg>、<errormsg2>], 'password':...}
return render(request, 'reg.html', {'reg_form': reg_form}) # 此類渲染給模板
reg_form = forms.RegForm() # 實例化表單類,參數為空
return render(request, 'reg.html', {'reg_form': reg_form}) # 把此類渲染給模板
Form表單的鈎子
表單提供的驗證規則不一定夠我們使用,這時可自定義規則,需要使用到表單中的鈎子,分為局部鈎子和全局鈎子
局部鈎子
使用方法:
一、引入:from django.core.exception import ValidationError
二、在原來表單類的基礎上新增一個方法def clean_字段名,此名稱不能亂起。
三、添加驗證規則。一般驗證通過返回self.clean_data.get(字段名);不能過則ValidationError(錯誤信息)
局部鈎子例子
自定義驗證規則
django import forms # 導入forms模塊
from django.forms import widgets # 導入插件
from django.core.exceptions import ValidationError
class RegForm(forms.Form): # 必須繼承此類
# 定義表單
username = forms.CharField(min_length=8, error_messages={'required': '不能為空'})
# 定義了字段的規則,以下類同,同時也定義了錯誤顯示的信息
password = forms.CharField(min_length=2, max_length=12,
widget=widgets.PasswordInput()) # 定義了標簽的屬性
repeat_password = forms.CharField(min_length=2, max_length=12,
widget=widgets.PasswordInput())
email = forms.EmailField()
def clean_username(self):
# 定義鈎子函數,此處可添加驗證規則,比如用戶名不能全為數字
# 此函數的名字必須是clean_字段名
if not self.cleaned_data.get('username').isdigit():
# 如果不是全數字,返回干凈的數據
return self.cleaned_data.get('username')
else:
raise ValidationError('不能全是數字') # 返回錯誤信息
全局鈎子
一般用在兩個字段需要比較時,比如說注冊需要兩次輸入的密碼一致時 使用方法: 一、引入:from django.core.exception import ValidationError 二、在原來表單類的基礎上新增一個方法def clean,此名稱不能亂起。 三、添加驗證規則。一般驗證通過返回self.clean_data;不能過則ValidationError(錯誤信息)兩次密碼一致例子
Form表單
django import forms # 導入forms模塊
from django.forms import widgets # 導入插件
from django.core.exceptions import ValidationError
class RegForm(forms.Form): # 必須繼承此類
# 定義表單
username = forms.CharField(min_length=8, error_messages={'required': '不能為空'})
# 定義了字段的規則,以下類同,同時也定義了錯誤顯示的信息
password = forms.CharField(min_length=2, max_length=12,
widget=widgets.PasswordInput()) # 定義了標簽的屬性
repeat_password = forms.CharField(min_length=2, max_length=12,
widget=widgets.PasswordInput())
email = forms.EmailField()
def clean_username(self):
# 定義鈎子函數,此處可添加驗證規則,比如用戶名不能全為數字
# 此函數的名字必須是clean_字段名
if not self.cleaned_data.get('username').isdigit():
# 如果不是全數字
return self.cleaned_data.get('username')
else:
raise ValidationError('不能全是數字')
def clean(self):
# 定義一個判斷兩次密碼輸入是否一致的規則
if self.cleaned_data.get('password') == self.cleaned_data.get('repeat_password'):
return self.cleaned_data
# 此處返回和局部鈎子不同
else:
raise ValidationError('兩次密碼不一致')
注意,由於獲取全局鈎子定義的錯誤信息是需要使用reg_form.errors.get('all'),鍵是__all__,在模板里是不支持的,所以需要在視圖函數中先使用鍵__all__獲取錯誤信息,再渲染。

