我的第一個python web開發框架(18)——前臺頁面與接口整合
由於我們前後臺系統沒有分開,所以前臺頁面調用接口時,可以直接使用後臺管理系統已經完成的接口,不過後臺管理系統接口的訪問加上了登錄驗證,所以需要將前臺要用到的接口進行處理,讓它們設置到白名單當中
我們打開main.py文件,在勾子函數中@hook(‘before_request‘)中找到下面代碼
# 過濾不用做任何操作的路由(即過濾不用進行判斷是否登錄和記錄日誌的url) if path_info in [‘/favicon.ico‘, ‘/‘, ‘/api/verify/‘]: return
這裏前面已講過,是跳過那些需要權限判斷和進行日誌記錄的訪問,對於後臺上傳的圖片來說,我們不需要進行日誌記錄和權限判斷,所以在這裏添加上日誌訪問的路由
# 過濾不用做任何操作的路由(即過濾不用進行判斷是否登錄和記錄日誌的url) if path_info in [‘/favicon.ico‘, ‘/‘, ‘/api/verify/‘] or path_info.find(‘/upload/‘) > -1: return
path_info是當前客戶端訪問的url,通常url是固定的話,我們可以通過in的方式直接進行判斷
因為上傳的圖片統一存放在/upload/這個目錄中,而訪問圖片的路由是/upload/xxxx/xxxxxxxxx.jpg,每張圖片訪問路徑都不一樣,新上傳的圖片就會生成新的鏈接,url是動態變化的,所以我們使用查找的方式來進行判斷當前url是否是圖片,如果是的話,則不執行下面的操作。
同樣在勾子函數@hook(‘before_request‘)中找到下面代碼
# 過濾不用進行登錄權限判斷的路由(登錄與退出登錄不用檢查是否已經登錄) url_list = ["/api/login/", "/api/logout/"] if path_info in url_list: pass
為了方便出現問題時及時排查,所以我們會將客戶端對接口的訪問,以及提交的參數記錄到日誌中,保存一段時間,所以我們會將一些訪問頻繁但對分析無關的接口添加到前面過濾處理中。
因為對後臺管理系統操作時,我們需要對用戶權限進行驗證,所以會在勾子中統一進行驗證用戶是否已經登錄成功。但有一些接口我們是不必要進行驗證的,比如登錄和退出登錄接口,如果它們不排除在外的話,那麽用戶將無法登錄,因為每次訪問登錄接口都會返回你未登錄不能訪問,這樣就會出現死循環,未登錄不能訪問接口,而不能訪問接口則無法進行登錄的怪圈當中,所以我們需要對一些無需登錄就可以訪問的接口進行例外處理。
對於前臺獲取公司介紹、聯系我們、產品分類、產品列表和產品信息的接口,我們可以將它們添加到這裏來,進行過濾。
# 過濾不用進行登錄權限判斷的路由(登錄與退出登錄不用檢查是否已經登錄) url_list = ["/api/login/", "/api/logout/", "/api/about/", "/api/contact_us/", "/api/product_class/"] if path_info in url_list or (request.method == ‘GET‘ and path_info.find(‘/api/product/‘) > -1): pass
因為我們使用的是RESTful風格的路由,獲取產品信息、修改產品信息和刪除產品信息路由url是一樣的,只是通過get/put/delete來進行區分,所以我們在處理時,需要獲取客戶端的提交方式是GET還是PUT或DELETE,然後進行區分處理。
我們知道獲取產品信息的接口路由是:@get(‘/api/product/<id:int>/‘) ,它會根據產品id的不同而不同,所以我們可以通過request.method == ‘GET‘ 來判斷當前訪問提交的是GET方式,而且訪問的路徑是/api/product/時,我們就不做權限判斷處理。
點擊main.py運行debug,然後在瀏覽器上輸入:http://127.0.0.1:81/api/about/ 就可以看到已經可以取到數據了
打開index.html頁面代碼,將公司介紹那部分html代碼刪掉,替換成下面加上id標簽的代碼
<img id="about_img" width="600" height="150"> <br><br> <span id="about"></span>
然後我們在底部javascript腳本中添加下面ajax代碼,就可以看到展示效果了
//讀取服務器記錄
$.ajax({
url: "/api/about/",
type: "GET",
dataType: ‘json‘,
success: function (data) {
$("#about_img").attr(‘src‘, data.data.front_cover_img);
$("#about").text(data.data.content);
}
});
產品中心這裏需要顯示四個產品,所以我們先登錄後臺管理系統,在產品中心那裏可以先錄入好產品,如下圖
然後打開index.html,找到顯示產品的html代碼,將它們全部刪除,替換成下面內容,用來接收到服務器端記錄以後,替換成對應的html
<div class="panel-body" style="height:460px" id="productsDiv"></div>
將代碼拉到底部,在javascript中,添加下面代碼,它會讀取到產品信息以後,對html內容重新進行組合
$.ajax({ url: "/api/product/?rows=4&page=1", type: "GET", dataType: ‘json‘, success: function (data) { if (data.rows != null && data.rows.length > 0) { for (var i in data.rows) { if (i == 4){ break; } var item = data.rows[i]; var html = ‘ <div style="float:left; padding-right:6px; padding-bottom:10px"><a href="/product_details.html?id=‘ + item.id + ‘"><div><img style="width:290px; height:200px" src=‘ + item.front_cover_img + ‘ alt="..." class="thumbnail"></div><div class="text-c" style="padding-top:5px;"><strong>‘ + item.name + ‘</strong></div></a></div>‘ $("#productsDiv").append(html); } } } });
由於前後臺合用一個接口,前臺接口調用的產口列表是啟用狀態的,不顯示禁用狀態的,而後臺需要獲取所有產品,所以我們要對接口數據處理一下才行,在接口添加一個參數進行判斷處理,是否是後臺獲取數據,前臺默認返回啟用狀態數據
在product.py中找到接口@get(‘/api/product/‘),添加下面處理
# 判斷是否是前臺提交獲取數據 if type != ‘backstage‘: # 判斷是否已經存在查詢條件了,是的話在原查詢條件後面拼接 if wheres: wheres = wheres + ‘ and is_enable=1‘ else: wheres = ‘where is_enable=1‘
在後臺產品中心頁面的html中,訪問/api/product/接口時,也添加上這個參數,大家在products_list.html頁面中查找/api/product/,將它改為:/api/product/?type=backstage 或 /api/product/?type=backstage&product_class_id=
這樣再刷新首頁,就會出現下面效果了:
關於我們頁面和聯系我們頁面比較簡單,只需要將頁面中間顯示的內容刪除,替換成<span id="content"></span>
在頁面底部的javascript中添加下面代碼,效果就可以直接看到了。註:聯系我們頁面只需要將/api/about/替換成/api/contact_us/就可以了
$.ajax({ url: "/api/about/", type: "GET", dataType: ‘json‘, success: function (data) { $("#content").html(data.data.content); } });
效果圖:
打開產品中心products.html頁面,這個頁面有兩個位置需要從服務器端讀取數據的,一是分類列表,一是產品列表,需要寫兩個ajax。另外,用戶從菜單欄或首頁進來時,有可能沒有帶分類id,所以在寫js時,需要進行專門的處理,沒有id的,需要從分類列表的ajax中獲取一個id,用作產品列表查詢,具體大家直接看javascript代碼就知道了
首先將分類列表項刪除,替換成<ol class="linenums" id="product_class"></ol>,將產品列表全部html代碼刪除,替換成<div class="panel-body" id="products"></div>
在頁面底部的javascript中添加下面代碼,效果就可以直接看到了。
由於前後臺合用一個接口,需要和產品列表接口做樣的處理,區分前後臺獲取數據
var id = getQueryString(‘id‘); if (id != ‘‘){ get_product_list(id); } $.ajax({ url: "/api/product_class/", type: "GET", dataType: ‘json‘, success: function (data) { if (data.rows != null && data.rows.length > 0) { for (var i in data.rows) { var item = data.rows[i]; if (id == ‘‘) { id = item.id; get_product_list(id); } var html = ‘ <li><a href="/products.html?id=‘ + item.id + ‘">‘ + item.name + ‘</a></li>‘; $("#product_class").append(html); } } } }); function get_product_list(id) { $.ajax({ url: "/api/product/?product_class_id=" + id, type: "GET", dataType: ‘json‘, success: function (data) { if (data.rows != null && data.rows.length > 0) { for (var i in data.rows) { var item = data.rows[i]; var html = ‘<div style="float:left; padding-right:20px; padding-bottom:20px"><a href="/product_details.html?id=‘ + item.id + ‘"><div><img style="width:290px; height:200px" src="‘ + item.front_cover_img + ‘" alt="‘ + item.name + ‘" class="thumbnail"></div><div class="text-c" style="padding-top:5px;"><strong>‘ + item.name + ‘</strong></div></a></div>‘ $("#products").append(html); } } } }); } /*獲取url中的參數*/ function getQueryString(name) { var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i"); var r = window.location.search.substr(1).match(reg); if (r != null) return r[2]; return ‘‘; }
我們打開產品詳情頁面product_details.html,從這個頁面的原型就可以看到,它也有兩個地方需要與服務器接口交互,一個是產品分類列表,這個同產品中心的代碼一樣,復制過來就可以了。另一個是產品信息的展示,需要通過ajax從服務器端獲取指定的產品信息,然後再寫入到頁面中。
我們可以先在後臺編輯好一個產品內容,如下圖
將分類列表項刪除,替換成<ol class="linenums" id="product_class"></ol>,為產品圖片加上id:<img style="width:400px; height:300px" src="" alt="..." class="thumbnail" id="front_cover_img">
刪除產品信息展示內容,替換成:<div style="float:left; font-size: 16px" id="product_info"></div>
刪除產品描述替換成:<div class="panel-body" id="content"></div>
在頁面底部的javascript中添加下面代碼,效果就可以直接看到了。
$.ajax({ url: "/api/product_class/", type: "GET", dataType: ‘json‘, success: function (data) { if (data.rows != null && data.rows.length > 0) { for (var i in data.rows) { var item = data.rows[i]; var html = ‘ <li><a href="/products.html?id=‘ + item.id + ‘">‘ + item.name + ‘</a></li>‘; $("#product_class").append(html); } } } }); var id = getQueryString(‘id‘); if (id != ‘‘) { $.ajax({ url: "/api/product/" + id + "/", type: "GET", dataType: ‘json‘, success: function (data) { if (data.state == 0) { $("#front_cover_img").attr(‘src‘, data.data.front_cover_img); var html = ‘產品名稱:‘ + data.data.name + ‘<br><br>產品編號:‘ + data.data.code + ‘<br><br>產品規格:‘ + data.data.standard + ‘<br><br>保 質 期:‘ + data.data.quality_guarantee_period + ‘<br><br>產 地:‘ + data.data.place_of_origin + ‘<br><br>‘; $("#product_info").append(html); $("#content").append(data.data.content); } } }); } /*獲取url中的參數*/ function getQueryString(name) { var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i"); var r = window.location.search.substr(1).match(reg); if (r != null) return r[2]; return ‘‘; } </script>
到此,我們整個代碼部分就全部完成了,接下來要做的就是服務器的部署工作了
本文對應的源碼下載(完整代碼)
版權聲明:本文原創發表於 博客園,作者為 AllEmpty 本文歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則視為侵權。
python開發QQ群:669058475 作者博客:http://www.cnblogs.com/EmptyFS/
我的第一個python web開發框架(18)——前臺頁面與接口整合