1、AJAX的異步示例 1. urls.py
from django.conf.urls import url from apptest import views urlpatterns = [ url(r'^atest/', views.atest), url(r'^ajax1/', views.ajax1), url(r'^ajax2/', views.ajax2), ]
2. atext.HTML
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta http-equiv="content-type" charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Title</title> </head> <body> <div> <input type="text" id="i1"> <button id="b1">按鈕1</button> </div> <div> <input type="text" id="i2"> <button id="b2">按鈕2</button> </div> <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script> <script type="text/javascript"> // 點擊按鈕1給ajax1發送get請求 $("#b1").click(function () { $.ajax({ url: '/ajax1/', type: 'get', success: function (res) { $("#i1").val(res) } }) }); // 點擊按鈕2給ajax2發送get請求 $("#b2").click(function () { $.ajax({ url: '/ajax2/', type: 'get', success: function (res) { $("#i2").val(res) } }) }); </script> </body> </html>
3.views.py
def atest(request): return render(request, 'atest.html') def ajax1(request): import time time.sleep(3) # 模仿網絡堵塞的時候 return HttpResponse('ajax1') def ajax2(request): return HttpResponse('ajax2')
4.結果解析 在頁面中首先點擊按鈕1,而後馬上點擊按鈕2,因爲按鈕1的網絡堵塞(我用time模塊模擬的堵塞),服務端會延遲幾秒才返回響應, 若是AJAX的請求是同步的,那麼按鈕2的請求必需要等到按鈕1響應後纔會被處理,而從咱們這個簡單的實例中能夠看出, 按鈕1沒有獲得響應的時候,按鈕2已經獲得響應結果了,所以能夠看出AJAX的請求是異步的。 2、Sweetalert示例 一、Bootstrap-sweetalert 項目下載 https://github.com/lipis/bootstrap-sweetalert 使用方法 https://lipis.github.io/bootstrap-sweetalert/ 使用步驟 1. 下載插件 2. 解壓 --> 拿到dist目錄下的內容 3. 拷貝到Django項目的static文件夾下 4. 在HTML頁面上導入sweetalert.css和sweetalert.js 二、示例(此處只是實現了刪除的Sweetalert) 1.index頁面代碼
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>index</title> {% load static %} <link rel="stylesheet" href="{% static 'bootstrap-3.3.7/css/bootstrap.css' %}"> <link rel="stylesheet" href="{% static 'sweetalert/sweetalert.css' %}"> <link rel="stylesheet" href="{% static 'font-awesome-4.7.0/css/font-awesome.css' %}"> <style> div.sweet-alert.showSweetAlert h2 { margin-top: 30px; } </style> </head> <body> <div class="container"> <div class="row"> <div class="col-md-6 col-md-offset-3" style="margin-top: 70px"> <a href="/logout/">註銷</a> <table class="table table-bordered table-striped"> <thead> <tr> <th>序號</th> <th>出版社名稱</th> <th>出版社地址</th> <th>操做</th> </tr> </thead> <tbody> {% for publisher in publisher_list %} <tr pid="{{ publisher.id }}"> <td>{{ forloop.counter }}</td> <td>{{ publisher.pname }}</td> <td>{{ publisher.addr }}</td> <td> <button class="btn btn-warning"> <i class="fa fa-pencil"></i> 編輯 </button> <button class="btn btn-danger delete-btn"> <span class="glyphicon glyphicon-remove" aria-hidden="true"></span> 刪除 </button> </td> </tr> {% endfor %} </tbody> </table> </div> </div> </div> {% csrf_token %} <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script> <script src="{% static 'bootstrap-3.3.7/js/bootstrap.min.js' %}"></script> <script src="{% static 'sweetalert/sweetalert.js' %}"></script> <script> $('.delete-btn').click(function () { var deleteId = $(this).parent().parent().attr('pid'); console.log(deleteId,typeof deleteId); swal({ title: "肯定要刪除嗎?", text: "刪除後沒法找回", type: "warning", // success/info/warning/error showCancelButton: true, confirmButtonClass: "btn-danger", confirmButtonText: "刪除", cancelButtonText: "取消", showLoaderOnConfirm: true, // 點擊確認按鈕以後會有一個加載的動畫 closeOnConfirm: false }, function () { // 當點擊確認按鈕的時候會執行這個匿名函數 $.ajax({ url: '/delete_publisher/', type: 'post', data: {id: deleteId, csrfmiddlewaretoken: $('[name="csrfmiddlewaretoken"]').val()}, success: function (res) { if (res.code === 0){ // 刪除成功 // 在頁面上刪除當前行數據 var $currentTr = $('[pid=' + deleteId + ']'); // 更新序號 // 1. 先找到當前行後面全部的tr var nextAllTr = $currentTr.nextAll('tr'); // 2. 每個tr的第一個td 依次 -1 nextAllTr.each(function () { var num = $(this).children().eq(0).text()-1; // 這時候的this是進入循環的那個tr $(this).children().eq(0).text(num); }); // 刪掉當前行 $currentTr.remove(); // 彈框提示 swal('刪除成功', '準備跑路吧!', 'success'); }else { // 刪除失敗 swal('刪除失敗', res.err_msg, 'error'); } } }) }); }) </script> </body> </html>
2.views.py
# 首頁 def index(request): publisher_list = Publisher.objects.all() return render(request, 'index.html', {'publisher_list': publisher_list}) # 刪除出版社 def delete_publisher(request): delete_id = request.POST.get('id') res = {'code': 0} try: Publisher.objects.filter(id=delete_id).delete() except Exception as e: res['code'] = 1 res['err_msg'] = str(e) return JsonResponse(res)
3、Cookie 1、介紹 1.Cookie的由來 你們都知道HTTP協議是無狀態的。 無狀態的意思是每次請求都是獨立的,它的執行狀況和結果與前面的請求和以後的請求都無直接關係,它不會受前面的請求響應狀況直接影響,也不會直接影響後面的請求響應狀況。 一句有意思的話來描述就是人生只如初見,對服務器來講,每次的請求都是全新的。 狀態能夠理解爲客戶端和服務器在某次會話中產生的數據,那無狀態的就覺得這些數據不會被保留。會話中產生的數據又是咱們須要保存的,也就是說要「保持狀態」。所以Cookie就是在這樣一個場景下誕生。 2.什麼是Cookie Cookie具體指的是一段小信息,它是服務器發送出來存儲在瀏覽器上的一組組鍵值對,下次訪問服務器時瀏覽器會自動攜帶這些鍵值對,以便服務器提取有用信息。 簡單點說,Cookie就是服務端給瀏覽器的小紙條!保存在瀏覽器端的鍵值對。 3.Cookie的原理 cookie的工做原理是:由服務器產生內容,瀏覽器收到請求後保存在本地;當瀏覽器再次訪問時,瀏覽器會自動帶上Cookie,這樣服務器就能經過Cookie的內容來判斷這個是「誰」了。 二、Django中操做Cookie(cookie是基於響應對象進行操做的) 1.設置Cookie rep = HttpResponse(...) rep = render(request, ...) rep.set_cookie(key,value, max_age=秒) rep.set_signed_cookie(key, value, max_age=秒, salt='加密鹽',...) 參數: key, 鍵 value='', 值 max_age=None, 超時時間(經常使用瀏覽器使用這個) expires=None, 超時時間(這個參數是針對IE瀏覽器的) path='/', Cookie生效的路徑,/ 表示根路徑,特殊的:根路徑的cookie能夠被任何url的頁面訪問 domain=None, Cookie生效的域名 secure=False, https傳輸 httponly=False 只能http協議傳輸,沒法被JavaScript獲取(不是絕對,底層抓包能夠獲取到也能夠被覆蓋) 2.獲取Cookie set_cookie取值: request.COOKIES --> 是一個大字典 request.COOKIES['key'] 或者 request.COOKIES.get('key', '設置取不到值時默認使用的值') set_signed_cookie取值: request.get_signed_cookie(key='', salt='set_signed_cookie的salt的值', default=獲取不到值的時候默認使用的值, max_age=None) 參數: default: 默認值 salt: 加密鹽 max_age: 後臺控制過時時間 3.刪除Cookie def logout(request): rep = redirect("/login/") rep.delete_cookie("user") # 刪除用戶瀏覽器上以前設置的usercookie值 return rep 三、Cookie登陸驗證示例 1.index頁面代碼就是上面的代碼 2.login頁面代碼
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta http-equiv="content-type" charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Login</title> {% load static %} <link rel="stylesheet" href="{% static 'bootstrap-3.3.7/css/bootstrap.min.css' %}"> </head> <body> <div class="container"> <div class="row"> <div class="col-md-4 col-md-offset-4" style="margin-top: 70px"> <h2 class="text-center">歡迎登陸</h2> <form action="" method="post"> {% csrf_token %} <div class="form-group"> <label for="exampleInputUser">用戶名</label> <input type="text" class="form-control" id="exampleInputUser" placeholder="username" name="username"> </div> <div class="form-group"> <label for="exampleInputPassword1">密碼</label> <input type="password" class="form-control" id="exampleInputPassword1" placeholder="Password" name="password"> </div> <div class="checkbox"> <label> <input type="checkbox" name="remember" value="seven"> 七天記住密碼 </label> </div> <button type="submit" class="btn btn-success btn-block">登陸</button> <p style="color: red;">{{ error_msg }}</p> </form> </div> </div> </div> <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script> <script src="{% static 'bootstrap-3.3.7/js/bootstrap.min.js' %}"></script> </body> </html>
3.views.py
from django.shortcuts import render, HttpResponse, redirect from functools import wraps from django import views from app01.models import * from django.http import JsonResponse # Create your views here. # 用裝飾器作cookie登陸驗證 def check_login(func): @wraps(func) def inner(request, *args, **kwargs): # 先作cookie驗證,若是cookie中有我登陸的信息,則能夠訪問指定的頁面 if request.COOKIES.get('xm') == 'sb': rep = func(request, *args, **kwargs) return rep else: # 不然,讓用戶去登陸 # 拿到當前訪問的url return_url = request.path_info return redirect('/login/?returnUrl={}'.format(return_url)) return inner # 登陸 class LoginView(views.View): def get(self, request): return render(request, 'login.html') def post(self, request): username = request.POST.get('username') pwd = request.POST.get('password') is_rem = request.POST.get('remember', None) is_ok = UserInfo.objects.filter(name=username, password=pwd) if is_ok: # 判斷是否從其餘頁面跳轉到登陸頁面,拿到return_url # 若是取不到returnUrl,默認跳轉到index頁面 return_url = request.GET.get('returnUrl', '/index/') rep = redirect(return_url) # rep就是響應對象 # 判斷是否記住密碼 if is_rem: # 是就保存七天 rep.set_cookie('xm', 'sb', max_age=60*60*24*7) else: # 不是就不保存 rep.set_cookie('xm', 'sb') # 告訴瀏覽器在本身本地保存一個鍵值對 return rep else: return render(request, 'login.html', {'error_msg': '用戶名或者密碼錯誤'}) # 首頁 @check_login def index(request): publisher_list = Publisher.objects.all() return render(request, 'index.html', {'publisher_list': publisher_list}) # 刪除出版社 def delete_publisher(request): delete_id = request.POST.get('id') res = {'code': 0} try: Publisher.objects.filter(id=delete_id).delete() except Exception as e: res['code'] = 1 res['err_msg'] = str(e) return JsonResponse(res) @check_login def home(request): return HttpResponse('home') # 註銷 def logout(request): rep = redirect('/login/') rep.delete_cookie('xm') return rep
4、Session 1、介紹 cookied的缺點: Cookie保存在瀏覽器端,不安全 Cookie的長度不能超過4096字節 Session: Session是用於保持狀態的基於 Web服務器的方法。Session 容許經過將對象存儲在 Web服務器的內存中在整個用戶會話過程當中保持任何對象。 通俗來講,Session就是保存在服務器端的鍵值對,Session的鍵做爲Cookie的值存在瀏覽器中,那麼即便被截取了,也只是取到了Session的鍵, 瀏覽器發送請求時,服務端就能夠根據cookie的傳過來的值,找到Session的鍵,從而去服務器的數據庫(文件等)找到對應的值。 注意: Cookie和Session實際上是共通性的東西,不限於語言和框架。 2、Session的原理 用戶名密碼經過驗證後: 1.生成一個隨機字符串(不一樣用戶的隨機字符串是不一樣的) 2.在後端定義一個大字典,字典的key就是上面的隨機字符串,值是你設置的值 3.在服務器端的數據庫(或者文件等)存儲上面定義的字典(值存儲的時候,session會自動幫咱們加密) 4.把隨機字符串當成cookie的值給瀏覽器返回(瀏覽器收到的cookie默認鍵值對是: {"sessionid": 隨機字符串}) 5.若是使用python的ORM,這個大字典會默認保存在django_session這張表中
1、session設置值的過程 request.session['name'] = 'xiaoming' # 隨機生成一個字符串做爲key,key對應的值又是一個字典,字典裏面的內容纔是你request.session設置的具體值 # session數據 d = { 'qwerioiuytr45421224ew': {'name': 'xiaoming'} } # 過程 import json # 1. 字典序列化成字符串 s1 = json.dumps({'name': 'xiaoming'}) # 2. 加密算法加密一下,獲得 10e1dasdasdadasfsgdvf2rji0d2dqdsa # 3. 存到數據庫 # 數據庫 # session_key session_data expire_date # qwerioiuytr45421224ew 10e1dasdasdadasfsgdvf2rji0d2dqdsa # 而後把這個隨機字符串qwerioiuytr45421224ew做爲cookie的值發送給瀏覽器 2、session取值的過程 # request.session.get('name') # 1. 先從請求攜帶的Cookie數據中拿到隨機字符串 :qwerioiuytr45421224ew # 2. 利用session_key去數據庫查詢,拿到session_data: 10e1dasdasdadasfsgdvf2rji0d2dqdsa # 3. 解密 # 4. 反序列化 --> 獲得一個保存當前此次請求的session數據的字典 # 5. 字典.get('name')
3、Django中Session相關方法 經常使用: # 獲取Session中數據 request.session['k1'] request.session.get('k1',None) # 設置Session的數據 request.session['k1'] = 123 request.session.setdefault('k1',123) # 存在則不設置 # 刪除指定的Session數據 del request.session['k1'] # 會話session的key request.session.session_key # 將全部Session失效日期小於當前日期的數據刪除 request.session.clear_expired() # 刪除當前會話的全部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和cookie不能使用了,可是數據庫仍存着session的值, 而刪除則是從數據庫中把session的值刪除了 不經常使用: # 獲取全部的鍵、值、鍵值對 request.session.keys() request.session.values() request.session.items() request.session.iterkeys() request.session.itervalues() request.session.iteritems() # 檢查會話session的key在數據庫中是否存在 request.session.exists("session_key") 四、Session版的登陸驗證
from django.shortcuts import render, HttpResponse, redirect from functools import wraps from django import views from app01.models import * from django.http import JsonResponse # Create your views here. # 用裝飾器作session登陸驗證 def check_login(func): @wraps(func) def inner(request, *args, **kwargs): # session版 # 驗證 session_user = request.session.get('user', None) if session_user: rep = func(request, *args, **kwargs) return rep else: # 不然,讓用戶去登陸 # 拿到當前訪問的url return_url = request.path_info return redirect('/login/?returnUrl={}'.format(return_url)) return inner # 登陸 class LoginView(views.View): def get(self, request): return render(request, 'login.html') def post(self, request): # session版 username = request.POST.get('username') pwd = request.POST.get('password') is_rem = request.POST.get('remember', None) # 不推薦使用get,由於get取不到值會報錯 user_obj = UserInfo.objects.filter(name=username, password=pwd).first() if user_obj: return_url = request.GET.get('returnUrl', '/index/') request.session['user'] = user_obj.name # 判斷是否記住密碼 if is_rem: # 是就保存七天 request.session.set_expiry(60*60*24*7) else: # 不是的話關閉瀏覽器就失效 request.session.set_expiry(0) return redirect(return_url) else: return render(request, 'login.html', {'error_msg': '用戶名或者密碼錯誤'}) # 首頁 @check_login def index(request): publisher_list = Publisher.objects.all() return render(request, 'index.html', {'publisher_list': publisher_list}) # 註銷 def logout(request): # request.session.delete() # 刪除session request.session.flush() # 刪除session並讓cookie失效 return redirect('/login/')
5、Django中的Session配置 在setting.py裏面設置的關於session的全局變量配置 1. 數據庫Session SESSION_ENGINE = 'django.contrib.sessions.backends.db' # 引擎(默認把session存在數據庫) 2. 緩存Session SESSION_ENGINE = 'django.contrib.sessions.backends.cache' # 引擎(把session存在緩存中) SESSION_CACHE_ALIAS = 'default' # 使用的緩存別名(默認內存緩存,也能夠是memcache),此處別名依賴緩存的設置 3. 文件Session SESSION_ENGINE = 'django.contrib.sessions.backends.file' # 引擎(把session存在文件中) SESSION_FILE_PATH = None # 緩存文件路徑,若是爲None,則使用tempfile模塊獲取一個臨時地址tempfile.gettempdir() 4. 緩存+數據庫 SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db' # 引擎(把session存在數據庫和緩存中) 5. 加密Cookie Session SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies' # 引擎(把session存在瀏覽器中,至關於加鹽的cookie) 其餘公用設置項: SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在瀏覽器上時的key,即:sessionid=隨機字符串(默認) SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)(默認) SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否關閉瀏覽器使得Session過時(默認) SESSION_SAVE_EVERY_REQUEST = False # 每次請求都刷新Session的有效期,默認修改以後才保存(默認) 注意: SESSION_COOKIE_AGE設置的是全局的session失效日期, request.session.set_expiry(value)設置的是某個具體的請求的session失效日期(局部) 不經常使用: SESSION_COOKIE_PATH = "/" # Session的cookie保存的路徑(默認) SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名(默認) SESSION_COOKIE_SECURE = False # 是否Https傳輸cookie(默認) SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http傳輸(默認) 5、使用裝飾器 1、FBV中加裝飾器 首先定義一個裝飾器 而後直接在要被裝飾的函數上一行添加裝飾器 例如: # 裝飾器函數 def check_login(func): @wraps(func) def inner(request, *args, **kwargs): # 先作cookie驗證,若是cookie中有我登陸的信息,則能夠訪問指定的頁面 if request.COOKIES.get('xm') == 'sb': rep = func(request, *args, **kwargs) return rep else: # 不然,讓用戶去登陸 # 拿到當前訪問的url return_url = request.path_info return redirect('/login/?returnUrl={}'.format(return_url)) return inner # 使用裝飾 @check_login def home(request): return HttpResponse('home') 2、CBV中加裝飾器相關 # CBV示例 class UserinfoView(views.View): def get(self, request): return HttpResponse('OK') def post(self, request): return redirect('/index/') 先觀察CBV的函數和裝飾器函數,明顯能夠看到,裝飾器函數的參數和CBV的函數的參數不一致, CBV的參數中多了一個self,那麼傳到裝飾器中使用的時候,裝飾器中inner的參數request就表明CBV中函數的self, 後續CBV的request就會被裝飾器的*args接收,此時是沒有問題的,可是,在裝飾器使用request的時候就出問題了, 由於裝飾器中inner的參數request就表明CBV中函數的self,而self明顯就沒有request的那些方法,因此就會報錯。 Django提供瞭解決這一問題的方法: 1.方法一 # 直接加在CBV視圖的get或post方法上 from django.utils.decorators import method_decorator class UserinfoView(views.View): @method_decorator(check_login) def get(self, request): return HttpResponse('OK') def post(self, request): return redirect('/index/') 2.方法二 # 加在dispatch方法上 from django.utils.decorators import method_decorator class UserinfoView(views.View): @method_decorator(check_login) def dispatch(self, request, *args, **kwargs): return super(UserinfoView, self).dispatch(request, *args, **kwargs) def get(self, request): return HttpResponse('OK') def post(self, request): return redirect('/index/') 由於CBV中首先執行的就是dispatch方法,因此這麼寫至關於給get和post方法都加上了登陸校驗 3.方法三 直接加在視圖類上,但method_decorator必須傳 name 關鍵字參數 # 若是get方法和post方法都須要登陸校驗的話就寫兩個裝飾器。 from django.utils.decorators import method_decorator @method_decorator(check_login, name="get") @method_decorator(check_login, name="post") class UserinfoView(views.View): def dispatch(self, request, *args, **kwargs): return super(UserinfoView, self).dispatch(request, *args, **kwargs) def get(self, request): return HttpResponse('OK') def post(self, request): return redirect('/index/') 6、補充 1、CSRF Token相關裝飾器在CBV只能加到dispatch方法上,或者加在視圖類上而後name參數指定爲dispatch方法。 若是是FBV則直接添加 @csrf_exempt 便可 注意: csrf_protect,爲當前函數強制設置防跨站請求僞造功能,即使settings中沒有設置全局中間件。 csrf_exempt,取消當前函數防跨站請求僞造功能,即使settings中設置了全局中間件。 2、示例 from django.views.decorators.csrf import csrf_exempt, csrf_protect from django.utils.decorators import method_decorator class UserinfoView(views.View): @method_decorator(csrf_exempt) def dispatch(self, request, *args, **kwargs): return super(UserinfoView, self).dispatch(request, *args, **kwargs) def get(self, request): return HttpResponse('OK') def post(self, request): return redirect('/index/') 或者 @method_decorator(csrf_exempt, name='dispatch') class UserinfoView(views.View): def dispatch(self, request, *args, **kwargs): return super(UserinfoView, self).dispatch(request, *args, **kwargs) def get(self, request): return HttpResponse('OK') def post(self, request): return redirect('/index/')