Flask + AngularJS + Jinja2 實現前後端互動
1.需求
- 做一個網頁,需要一個由後端控制內容的選單。一開始的時候是所有內容都在jinja2模板中進行渲染。後面發現這樣每個檢視都需要傳選單的資料。就想著能不能寫一個介面,前端只要請求這個介面進行渲染就可以了,這樣就可以只在base模板中寫選單,後面的直接繼承即可。
2.框架選擇
-
由上面的需要,一開始還不知道這麼寫前端,只知道用ajax請求選單的介面,能是能拿到資料。但是對於基板小白的筆者來說,怎樣將拿到的資料放在該放的位置就是問題了。
-
好在前幾天在看Spring Could 框架的時候看到了一篇教程,講的是如何用AngularJS 消費RESTful web服務。看到裡面用的AngularJS 很簡單就實現了與Spring Could的互動。只要引入angularjs.js就能用了,其請求後端的
$http
get
方法差不多,最方便的是拿到資料後傳給$scope
就可以嵌入到html的任何地方,就像jinja2。 -
當然也有不足的地方。一是,AngularJS 的變數獲取字元和jinja2的衝突了,都是用的
{{ }}
。二是,在手機上好像不能用,目前還不知道是什麼原因。
3.設計開發
/BookStore/static/js/fronts/get_book_type.js
angular.module('demo', [])
.controller('Hello', function($scope, $http) {
$http.get('http://127.0.0.1:5000/get_book_type' ).
then(function(response) {
$scope.types = response.data;
console.log($scope.types)
});
});
- js檔案這裡就跟ajax差不多,用
$http.get
請求資料,然後儲存到$scope
。
<!doctype html>
<html ng-app="demo">
<head>
<title>Hello AngularJS</title>
< script type="text/javascript" src="{{ url_for('static', filename='js/angular.min.js') }}"></script>
<script type="text/javascript" src="{{ url_for('static', filename='js/fronts/get_book_type.js') }}"></script>
</head>
<body>
<div ng-controller="Hello">
<ul>
<li ng-repeat="type in types"><a href="/get_nav_data?book_type={{'{{type}}'}}">{{ '{{type}}' }}</a></li>
</ul>
</div>
</body>
</html>
- html首先需要匯入angular.min.js檔案,這裡是在官網下載好了的,也可以用國內的cdn加速。還要匯入上面用來獲取後端資料的get_book_type.js檔案。
- 然後就是設定angularjs的html標籤屬性。
ng-app="demo"
是作用域,ng-controller="Hello"
直譯控制器(還沒看過教程),ng-repeat="type in types"
這個是迴圈語句,我從後端傳來的是陣列,可以用迴圈取出來。
4.自測
-
在前端列印後端傳來的資料,ok沒問題
-
在專案外測試的結果ok
-
加入到專案中,將選單放到base.html模板中,結果也ok
5.後端Flask實現
@bp.route('/get_book_type')
def get_book_type():
book_type_list = choice_book_type()
# 解決跨域問題:https://blog.csdn.net/weixin_42902669/article/details/90728697
resp = jsonify(book_type_list)
resp.headers['Access-Control-Allow-Origin'] = '*'
# resp.headers['"Access-Control-Allow-Methods"'] = '"PUT,POST,GET,DELETE,OPTIONS"'
return resp
-
遇到一個坑!
No 'Access-Control-Allow-Origin' header is present on the requested resource.
用AngularJS 請求Flask 資料的時候,會有跨域的問題出現。後面google了一下,分兩種解決方法,一種是在前端解決,在請求頭header中加什麼引數的樣子(沒試過)。另一種是在後端解決,配置Flask關閉跨域的配置項,以及寫一個裝飾器設定允許跨域的IP地址的請求。 -
看了幾篇解決方案,都不太行,要麼場景不符,要麼實現起來太複雜。這裡我就只有一個介面而已,沒必要搞的這麼複雜。
-
好在後面找到了簡單又好用的方法。就是上面用的,在介面的response響應頭中新增
Access-Control-Allow-Origin
允許的的跨域請求就ok了。
6.總結
- 經過這個例子才發現Flask 的jsonify()返回的是一個reponse類物件
<class 'flask.wrappers.Response'>
,之前一直都只知道直接return jsonify()
其功能是可以將python的資料型別轉為json並返回。現在想想,感覺傻了。檢視函式返回的是response響應體,那jsonify返回的不就是response了嘛! - 是前後端分離開發會遇到請求跨域的問題。
- AngularJS用起來真香,不過在手機瀏覽器上AngularJS沒有成功渲染資料,有空的時候可以好好的深入瞭解一下。
完整的專案程式碼庫:https://github.com/caisi35/BookStore