摘要:html
form組件前端
cookie組件git
session組件正則表達式
# views.py # 註冊 def register(request): error_msg = "" if request.method == "POST": username = request.POST.get("name") pwd = request.POST.get("pwd") # 對註冊信息作校驗 if len(username) < 6: # 用戶長度小於6位 error_msg = "用戶名長度不能小於6位" else: # 將用戶名和密碼存到數據庫 return HttpResponse("註冊成功") return render(request, "register.html", {"error_msg": error_msg}) # register.html !DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>註冊頁面</title> </head> <body> <form action="/reg/" method="post"> <p> 用戶名: <input type="text" name="name"> </p> <p> 密碼: <input type="password" name="pwd"> </p> <p> <input type="submit" value="註冊"> <p style="color: red">{{ error_msg }}</p> </p> </form> </body> </html>
校驗數據
使用form組件實現註冊功能:數據庫
from django import forms # 按照Django form組件的要求本身寫一個類 class MyForm(forms.Form): name = forms.CharField(label='用戶名', max_length=6) pwd = forms.CharField(label='密碼', max_length=8, min_length=4) def register(request): form_obj = MyForm() if request.method == 'POST': # 實例化form對象的時候,把post提交過來的數據直接傳進去 form_obj = MyForm(request.POST) # 調用form_obj校驗數據的方法 if form_obj.is_valid(): # 這裏is_valid()若是驗證所有經過,則返回True return HttpResponse('註冊成功') return render(request, 'register.html', {'form_obj': form_obj})
這裏咱們使用PythonConsole來測試:django
依次輸入:(帶#的爲結果) from app01 import views form_obj = views.MyForm({'name': 'hhh', 'pwd': '123'}) form_obj.is_valid() #False form_obj.errors #{'pwd': ['Ensure this value has at least 4 characters (it has 3).']} form_obj.cleaned_data #{'name': 'hhh'}
## form_obj.is_valid() 校驗提交的信息,若是所有經過,則返回True,不然爲False
## from_obj.errors 查看錯誤的信息,結果是一個字典格式,key爲錯誤的字段,value爲錯誤的緣由,注意這裏面是一個列表,說明緣由能夠有多個,這裏須要說明:全部校驗未經過的字段及錯誤信息提示都在這裏放着,以鍵值對的形式存放。
## form_obj.cleaned_data 查看校驗經過的數據,這裏存放這全部校驗經過的字段及其值,以字典形式存放。
特別補充:
若是:多串字段:不進行校驗,因此不會在cleaned_data和errors中
少傳字段: 也會校驗少傳的字段,會在errors中,且該字段描述:{'pwd': ['This field is required.']}
全部Form中的字段默認都是要校驗,可是能夠經過設置required = False來更過。後端
# views from django import forms # 按照Django form組件的要求本身寫一個類 class MyForm(forms.Form): name = forms.CharField(max_length=6) pwd = forms.CharField(max_length=8, min_length=4) def register(request): form_obj = MyForm() if request.method == 'POST': # 實例化form對象的時候,把post提交過來的數據直接傳進去 form_obj = MyForm(request.POST) # 調用form_obj校驗數據的方法 if form_obj.is_valid(): # 這裏is_valid()若是驗證所有經過,則返回True return HttpResponse('註冊成功') return render(request, 'register.html', {'form_obj': form_obj})
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/register/" method="post"> {# .as_p表明將全部的字段都對應input框渲染給前端顯示#} {{ form_obj.as_p }} </form> </body> </html>
能夠看到,前面的Name和Pwd是Django本身渲染加上的,若是想要自定義,能夠在MyForm類的對應字段里加上:label='用戶名'和label='密碼'便可瀏覽器
上面是第一種渲染方式,能夠看出可拓展性較差安全
from django import forms # 按照Django form組件的要求本身寫一個類 class MyForm(forms.Form): name = forms.CharField(max_length=6, label='用戶名') pwd = forms.CharField(max_length=8, min_length=4, label='密碼') email = forms.EmailField(label='郵箱')
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/register/" method="post"> <p>{{ form_obj.name }}</p> <p>{{ form_obj.pwd }}</p> <p>{{ form_obj.email }}</p> </form> </body> </html>
只有input框!
加入input框前的名字:服務器
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/register/" method="post"> <p>{{ form_obj.name.label }}{{ form_obj.name }}</p> <p>{{ form_obj.pwd.label }}{{ form_obj.pwd }}</p> <p>{{ form_obj.email.label }}{{ form_obj.email }}</p> </form> </body> </html>
此種方法仍是有缺點,好比字段若是有100個,難道要100個所有輸嗎?因此應該還有更好的方法:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/register/" method="post"> {% for foo in form_obj %} <p>第三種渲染方式:{{ foo.label }}{{ foo }}</p> {% endfor %} </form> </body> </html>
這裏提一下:若是想要取消前端校驗,能夠在form表單中加入:novalidate
這裏須要知道:
一、若是Django建立的form表單在提交的時候數據不合法(校驗不經過),則會自動保留填寫的信息,不會清空。
二、Django建立的表單是沒有提交按鈕的,須要本身建立。
接下來,添加校驗不經過時候的提示信息:只需在恰當的位置添加
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/register/" method="post" novalidate> {% for foo in form_obj %} <p>第三種渲染方式:{{ foo.label }}{{ foo }}<span>{{ foo.errors }}</span></p> {% endfor %} <input type="submit"> </form> </body> </html>
這裏,提示錯誤信息在下面顯示,若是想讓它在每一個字段的input框後面顯示能夠加個0
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/register/" method="post" novalidate> {% for foo in form_obj %} <p>第三種渲染方式:{{ foo.label }}{{ foo }}<span>{{ foo.errors.0 }}</span></p> {% endfor %} <input type="submit"> </form> </body> </html>
繼續走向個性化:提示的錯誤信息是英文,我看不懂,那就改爲中文:
修改錯誤提示信息爲自定義信息
from django import forms # 按照Django form組件的要求本身寫一個類 class MyForm(forms.Form): name = forms.CharField(max_length=6, label='用戶名', error_messages={ 'max_length': '用戶名最大長度爲6位', 'required': '用戶名必須不能爲空' }) pwd = forms.CharField(max_length=8, min_length=4, label='密碼', error_messages={ 'max_length': '密碼最大長度爲8位', 'min_length': '密碼最小長度爲4位', 'required': '用戶名必須不能爲空' }) email = forms.EmailField(label='郵箱', error_messages={ 'required': '郵箱必須不能爲空', 'invalid': '郵箱格式不合法' })
測試測試:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/register/" method="post" novalidate> {% for foo in form_obj %} <p>第三種渲染方式:{{ foo.label }}{{ foo }}<span>{{ foo.errors.0 }}</span></p> {% endfor %} <input type="submit"> </form> </body> </html>
這裏有個小點須要說明:默認google瀏覽器的表單輸入框若是要求最大6位,就只能輸入6位最大,再多輸入沒有反應,這個爲了測試方便,能夠認爲在每次提交前經過右鍵檢查,人爲刪除限制的html代碼
經常使用字段與插件:
這裏系統的在補充一些Form類在建立的時候會涉及到的字段和插件,自對用於對用戶請求數據的驗證,插件用於自動生成html
初始值,input框裏面的初始值。
class LoginForm(forms.Form): username = forms.CharField( min_length=8, label="用戶名", initial="張三" # 設置默認值 ) pwd = forms.CharField(min_length=6, label="密碼")
重寫錯誤信息。
class LoginForm(forms.Form): username = forms.CharField( min_length=8, label="用戶名", initial="張三", error_messages={ "required": "不能爲空", "invalid": "格式錯誤", "min_length": "用戶名最短8位" } ) pwd = forms.CharField(min_length=6, label="密碼")
pwd = forms.CharField(max_length=8, min_length=4, label='密碼', error_messages={ 'max_length': '密碼最大長度爲8位', 'min_length': '密碼最小長度爲4位', 'required': '用戶名必須不能爲空' }, widget=forms.widgets.PasswordInput(attrs={'type': 'password'})) # 將input改爲password類型,這樣輸入的就不是明文了
將下拉式選擇框轉變成單選形式
gender = forms.ChoiceField( choices=((1, "男"), (2, "女"), (3, "保密")), label="性別", initial=3, widget=forms.widgets.RadioSelect()
class LoginForm(forms.Form): ... hobby = forms.ChoiceField( choices=((1, "籃球"), (2, "足球"), (3, "雙色球"), ), label="愛好", initial=3, widget=forms.widgets.Select() )
class LoginForm(forms.Form): ... hobby = forms.MultipleChoiceField( choices=((1, "籃球"), (2, "足球"), (3, "雙色球"), ), label="愛好", initial=[1, 3], widget=forms.widgets.SelectMultiple() )
class LoginForm(forms.Form): ... keep = forms.ChoiceField( label="是否記住密碼", initial="checked", widget=forms.widgets.CheckboxInput() )
class LoginForm(forms.Form): ... hobby = forms.MultipleChoiceField( choices=((1, "籃球"), (2, "足球"), (3, "雙色球"),), label="愛好", initial=[1, 3], widget=forms.widgets.CheckboxSelectMultiple() )
在使用選擇標籤時,須要注意choices的選項能夠配置從數據庫中獲取,可是因爲是靜態字段 獲取的值沒法實時更新,須要重寫構造方法從而實現choice實時更新。
方式一:
from django.forms import Form from django.forms import widgets from django.forms import fields class MyForm(Form): user = fields.ChoiceField( # choices=((1, '上海'), (2, '北京'),), initial=2, widget=widgets.Select ) def __init__(self, *args, **kwargs): super(MyForm,self).__init__(*args, **kwargs) # self.fields['user'].choices = ((1, '上海'), (2, '北京'),) # 或 self.fields['user'].choices = models.Classes.objects.all().values_list('id','caption')
方式二:
from django import forms from django.forms import fields from django.forms import models as form_model class FInfo(forms.Form): authors = form_model.ModelMultipleChoiceField(queryset=models.NNewType.objects.all()) # 多選 # authors = form_model.ModelChoiceField(queryset=models.NNewType.objects.all()) # 單選
Field required=True, 是否容許爲空 widget=None, HTML插件 label=None, 用於生成Label標籤或顯示內容 initial=None, 初始值 help_text='', 幫助信息(在標籤旁邊顯示) error_messages=None, 錯誤信息 {'required': '不能爲空', 'invalid': '格式錯誤'} 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類型 Django Form內置字段
咱們在Fom類中定義 clean_字段名() 方法,就可以實現對特定字段進行校驗。
# 局部鉤子 def clean_name(self): name = self.cleaned_data.get('name') if '666' in name: # 用add_error添加錯誤提示 self.add_error('name', '666不對') return name
咱們在Fom類中定義 clean() 方法,就可以實現對字段進行全局校驗。
# 輸入兩次密碼一致性的全局鉤子 設置兩個密碼字段 pwd = forms.CharField(max_length=8, min_length=4, label='密碼', error_messages={ 'max_length': '密碼最大長度爲8位', 'min_length': '密碼最小長度爲4位', 'required': '用戶名必須不能爲空' }, widget=forms.widgets.PasswordInput(attrs={'type': 'password'})) confirm_pwd = forms.CharField(max_length=8, min_length=4, label='密碼', error_messages={ 'max_length': '密碼最大長度爲8位', 'min_length': '密碼最小長度爲4位', 'required': '用戶名必須不能爲空' }, widget=forms.widgets.PasswordInput(attrs={'type': 'password'})) # 全局鉤子: def clean(self): pwd = self.cleaned_data.get('pwd') confirm_pwd = self.cleaned_data.get('confirm_pwd') if pwd != confirm_pwd: self.add_error('confirm_pwd', '密碼兩次輸入不一致') return self.cleaned_data
def reg(request): # 生成一個空對象 form_obj = MyForm() if request.method == 'POST': print(request.POST) form_obj = MyForm(request.POST) if form_obj.is_valid(): # print(form_obj.cleaned_data) # 這裏打散傳值須要注意的是模型表字段名要與模型中的字段名相同,否則確定會報錯。 # 因此平時要養成習慣,不少地方須要同樣,以便於代碼的可讀性 # models.User.objects.create(**form_obj.cleaned_data) return render(request,'reg.html',locals())
你們都知道HTTP協議是無狀態的。
無狀態的意思是每次請求都是獨立的,它的執行狀況和結果與前面的請求和以後的請求都無直接關係,它不會受前面的請求響應狀況直接影響,也不會直接影響後面的請求響應狀況。
一句有意思的話來描述就是人生只如初見,對服務器來講,每次的請求都是全新的。
狀態能夠理解爲客戶端和服務器在某次會話中產生的數據,那無狀態的就覺得這些數據不會被保留。會話中產生的數據又是咱們須要保存的,也就是說要「保持狀態」。所以Cookie就是在這樣一個場景下誕生。
Cookie具體指的是一段小信息,它是服務器發送出來存儲在瀏覽器上的一組組鍵值對,下次訪問服務器時瀏覽器會自動攜帶這些鍵值對,以便服務器提取有用信息。
cookie的工做原理是:由服務器產生內容,瀏覽器收到請求後保存在本地;當瀏覽器再次訪問時,瀏覽器會自動帶上Cookie,這樣服務器就能經過Cookie的內容來判斷這個是「誰」了。
咱們使用Chrome瀏覽器,打開開發者工具。
還能夠在這裏查看:
前提:
咱們在後端views中視圖函數的返回參數render(),HttpResponse(),redirect(),經過查看它們的源碼發現加括號後世界上返回的是一個對象,也就是咱們返回到前端的是一個對象,之前咱們是直接返回,如今要用到cookie和session就得在返回前對這個對象進行操做設置Cookie
# views def login(request): if request.method == 'POST': username = request.POST.get('username') password = request.POST.get('password') if username == 'sgt' and password == '123': # 用戶登陸校驗成功,下一步設置cookie,須要知道用哪個網頁使用cookie obj = redirect('/index/') # 設置cookie obj.set_cookie('name', 'sgt', expires=15) # 過時時間15秒 return obj # 這個obj就是進行操做,設置好cookie的redirect('/index/') return render(request, 'login.html') def index(request): return render(request, 'index.html') # 在login.html登陸頁面,進行登陸,若是用戶名和密碼爲sgt和123,則跳轉到inde.html,同時在跳轉以前設置cookie,經過在index頁面右鍵檢查,查看cookie能夠看到cookie也就存在,說明設置成功
固然上面的設置cookie爲了演示建立過程,並無加任何安全措施,在實際使用中咱們確定會對他進行加密處理:作一下更安全性的操做處理:
obj.set_signed_cookie(key,value,salt='加密鹽', max_age=None, ...) 參數: key, 鍵 value='', 值 max_age=None, 超時時間 expires=None, 超時時間(IE requires expires, so set it if hasn't been already.) path='/', Cookie生效的路徑,/ 表示根路徑,特殊的:根路徑的cookie能夠被任何url的頁面訪問 domain=None, Cookie生效的域名 secure=False, https傳輸 httponly=False 只能http協議傳輸,沒法被JavaScript獲取(不是絕對,底層抓包能夠獲取到也能夠被覆蓋)
request.COOKIES['key'] request.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None)
參數:
def logout(request): obj = redirect("/login/") obj.delete_cookie("user") # 刪除用戶瀏覽器上以前設置的usercookie值 return rep
# 登陸頁面視圖函數 def login(request): if request.method == 'POST': username = request.POST.get('username') password = request.POST.get('password') if username == 'jason' and password == '123': old_path = request.GET.get('next') if old_path: # 若是原來頁面有,則自動跳轉 obj = redirect(old_path) else: # 若是是直接進入登陸頁面,不是從其它頁面跳轉的,則默認跳到指定主頁面去 obj = redirect('/home/') # 用戶登陸成功 朝瀏覽器設置一個cookie obj.set_cookie('name','jason',expires=3600) # 這個兼容性更高 # obj.set_cookie('name','jason',max_age=5) return obj return render(request,'login.html') # 登陸驗證裝飾器 from functools import wraps def login_auth(func): @wraps(func) def inner(request,*args,**kwargs): # 校驗cookie # print(request.get_full_path()) old_path = request.get_full_path() # 拿到原來須要登陸的頁面路由 if request.COOKIES.get('name'): return func(request,*args,**kwargs) # 若是未登陸,跳轉到登陸頁面,同時在路由後面拼接老頁面路由地址,用於登陸成功自動跳轉 return redirect('/login/?next=%s'%old_path) return inner @login_auth def index(request): # # print(request.COOKIES.get('name')) # if request.COOKIES.get('name'): return HttpResponse('我是index頁面,只有登陸了才能看') @login_auth def home(request): return HttpResponse('我是home頁面,只有登陸了才能看') @login_auth def xxx(request): return HttpResponse('我是xxx頁面,只有登陸了才能看')
Cookie雖然在必定程度上解決了「保持狀態」的需求,可是因爲Cookie自己最大支持4096字節,以及Cookie自己保存在客戶端,可能被攔截或竊取,所以就須要有一種新的東西,它能支持更多的字節,而且他保存在服務器,有較高的安全性。這就是Session。
問題來了,基於HTTP協議的無狀態特徵,服務器根本就不知道訪問者是「誰」。那麼上述的Cookie就起到橋接的做用。
咱們能夠給每一個客戶端的Cookie分配一個惟一的id,這樣用戶在訪問時,經過Cookie,服務器就知道來的人是「誰」。而後咱們再根據不一樣的Cookie的id,在服務器上保存一段時間的私密資料,如「帳號密碼」等等。
總結而言:Cookie彌補了HTTP無狀態的不足,讓服務器知道來的人是「誰」;可是Cookie以文本的形式保存在本地,自身安全性較差;因此咱們就經過Cookie識別不一樣的用戶,對應的在Session裏保存私密的信息以及超過4096字節的文本。
另外,上述所說的Cookie和Session實際上是共通性的東西,不限於語言和框架。
session基本使用(設置,獲取)
# 設置session:
request.session['name']='jason'
設置session時候Django作了3件事:
①生成一個隨機的字符串
②在Django的session表存儲隨機字符串與數據記錄
③將隨機字符串發送給瀏覽器
# 獲取session:
request.session.get('name')
# Django中session的相關方法:
# 獲取、設置、刪除Session中數據 request.session['k1'] request.session.get('k1',None) request.session['k1'] = 123 request.session.setdefault('k1',123) # 存在則不設置 del request.session['k1'] # 全部 鍵、值、鍵值對 request.session.keys() request.session.values() request.session.items() request.session.iterkeys() request.session.itervalues() request.session.iteritems() # 會話session的key request.session.session_key # 將全部Session失效日期小於當前日期的數據刪除 request.session.clear_expired() # 檢查會話session的key在數據庫中是否存在 request.session.exists("session_key") # 刪除當前會話的全部Session數據 request.session.delete() # 刪除當前的會話數據並刪除會話的Cookie。 request.session.flush() 這用於確保前面的會話數據不能夠再次被用戶的瀏覽器訪問 例如,django.contrib.auth.logout() 函數中就會調用它。 # 設置會話Session和Cookie的超時時間 request.session.set_expiry(value) * 若是value是個整數,session會在些秒數後失效。 * 若是value是個datatime或timedelta,session就會在這個時間後失效。 * 若是value是0,用戶關閉瀏覽器session就會失效。 * 若是value是None,session會依賴全局session失效策略。
# session解析
session版驗證登陸
# session版登陸 def login(request): if request.method == 'POST': username = request.POST.get('username') password = request.POST.get('password') if username == 'sgt' and password == '123456': # 設置session request.session['username'] = username # 跳轉到登陸頁面以前的URL next_url = request.GET.get('next') # 這裏須要判斷一下用戶是不是跳轉過來登陸的仍是直接登陸的 if next_url: # 若是有則跳轉到原頁面 return redirect(next_url) else: # 不然默認指定跳轉到指定頁面 return redirect('/index/') return render(request, 'login.html') # 登陸驗證裝飾器: # 登陸驗證的過程其實是基於已登陸的狀態進行校驗的,也就是說,用戶登陸後, # 會在服務端生成一個cookie存儲下來,同時把一份cookie再發給瀏覽器, # 當用戶在某個跳轉到某個須要登陸次才能訪問的頁面時候,就會進行登陸校驗過程 # 會將瀏覽器的cookie發到服務端,和服務端存儲的cookie進行匹配,若是匹配到,就說明 # 服務端已經記錄這這個用戶的登陸狀態,容許訪問。 from functools import wraps def login_auth(func): def inner(request, *args, **kwargs): # 獲取到驗證登陸的當前頁面的所有路由 next_url = request.get_full_path() # 若是改用戶的session存在,說明已登陸 if request.session.get('username'): return func(request, *args, **kwargs) # 發現未登陸,則跳轉到登陸頁面,同時路由後面拼接當前頁面路由 else: return redirect('/login/?next=%s' % next_url) return inner @login_auth def logout(request): # 刪除全部當前請求相關的session request.session.delete() return redirect("/login/") @login_auth def index(request): current_user = request.session.get("user", None) return render(request, "index.html", {"user": current_user})
# 須要導入一個method_decorator模塊 from django.utils.decorators import method_decorator 其它都同樣,主要在裝飾的方法上有區別: # @method_decorator(login_auth,name='get') # 第二種 name參數必須指定 class MyHome(View): @method_decorator(login_auth) # 第三種 get和post都會被裝飾 def dispatch(self, request, *args, **kwargs): super().dispatch(request,*args,**kwargs) # @method_decorator(login_auth) # 第一種 def get(self,request): return HttpResponse('get') def post(self,request): return HttpResponse('post')