就要面對本章的一個難點了,說是難點可能僅僅對於我來講,畢竟我是一個js渣,既然首頁打算使用動態加載的形式,那麼與後臺交互的方式就要進行選擇,目前比較流行的爲RESTful的形式,關於RESTful的文章目前多不勝數,這裏也不作太多介紹,在我理解這種方式簡單來講就是僅僅把服務端做爲一個資源池,來對資源池進行刪除(Delete),修改(PUT),建立(POST)和獲取(GET)的操做,全部操做都是在一種無狀態的狀況下進行的。javascript
通常來講,應用程序的RESTful操做都是設計爲一個獨立的模塊,對於flask來講,即一個獨立的藍本,這裏也不能免俗,建立1.0版本的api(api_1_0)html
from flask import Blueprint api=Blueprint("api",__name__) from . import posts,errors
這裏僅僅是爲首頁的分頁提供內容,並無打算寫一成天RESTful的系統,因此,只有一個posts和一個error的視圖模型。前端
在api中,返回的狀態碼其實就是http中的狀態碼,能夠說與普通html是一直的,好比經常使用的幾個:vue
好比在代碼中寫一個403錯誤的樣例(api_1_0\errors.py):java
from flask import jsonify def forbidden(message): response=jsonify({'error':'forbidden','message':message}) response.status_code=403 return response
同時,其餘的錯誤也能夠經過讀取響應的元數據來決定響應格式,好比(main\errors.py):react
@main.app_errorhandler(404) def page_not_found(e): if (request.accept_mimetypes.accept_json and not request.accept_mimetypes.accept_html): response=jsonify({'error':'not found'}) response.status_code=404 return response return render_template("404.html") ,404
接下來就是獲取post的API了,首先咱們想一下應用場景,進入應用首頁,這時候首頁只顯示一頁的分享內容(html),而後,前端經過js判斷,若滾動條託底,則再次動態增長一頁的內容(api),以此類推,直到加載完成爲止。angularjs
根據這個場景,首先修改首頁的視圖模型,將所有查詢改成獲取前20項:json
@main.route("/",methods=["GET","POST"]) def index(): ... posts=Post.query.order_by(Post.createtime.desc()).limit(20) #首頁顯示已有博文 按時間排序 ...
而後修改Post.py,以實現json轉換的功能:flask
def to_json(self): json={ "body":self.body, "body_html":self.body_html, "id":self.id, "createtime":self.createtime, "author":User.query.get(self.author_id).to_json() } return json;
其中做者項引用的是user的一個json轉換方法,內容以下:api
def to_json(self): json = { "id": self.id, "username": self.username, "nickname": self.nickname, "email": self.email, "birthday": self.birthday, "gender": self.gender, "headimg": self.headimg, "remark":self.remark, "createtime": self.createtime }; return json;
很是傻瓜的一個寫法,接着是完善api的功能:
from flask import current_app,jsonify from ..models.Post import Post from ..api_1_0 import api @api.route("/posts/<int:page>") def posts(page): pagination = Post.query.order_by(Post.createtime.desc()).paginate( page, per_page=current_app.config["POSTS_PER_PAGE"], error_out=False ) return jsonify( { "has_next":1 if pagination.has_next else 0, "page":pagination.page, "posts":[post.to_json() for post in pagination.items] });
只要這幾項,基本也就夠用了,同土土的方法測試一下,在瀏覽器中輸入http://127.0.0.1:5000/api/v1_0/posts/1,返回內容以下:
{ "has_next": 1, "page": 1, "posts": [ ... { "author": { "birthday": "Fri, 05 Feb 1988 00:00:00 GMT", "createtime": "2017-02-24 23:27:54", "email": "zhangji@qq.com", "gender": 0, "headimg": "48da3c86-109f-11e7-8e7a-7824af04112f", "id": 1, "nickname": "\u5f20\u5409", "remark": null, "username": "zhangji" }, "body": "Morbi ut odio. Suspendisse potenti. Donec ut dolor.", "body_html": "<p>Morbi ut odio. Suspendisse potenti. Donec ut dolor.</p>", "createtime": "Thu, 06 Apr 2017 00:00:00 GMT", "id": 37 } ] }
注意日期格式不正確,對to_json進行一下修改:
def to_json(self): json={ "body":self.body, "body_html":self.body_html, "id":self.id, "createtime":self.createtime.strftime('%Y-%m-%d %H:%M:%S') , "author_id":self.author_id } return json;
User的日期部分與此相同,如今的輸出:
{ "has_next": 1, "page": 1, "posts": [ ... { "author": { "birthday": "Fri, 05 Feb 1988 00:00:00 GMT", "createtime": "2017-02-24 23:27:54", "email": "zhangji@qq.com", "gender": 0, "headimg": "48da3c86-109f-11e7-8e7a-7824af04112f", "id": 1, "nickname": "\u5f20\u5409", "remark": null, "username": "zhangji" }, "body": "Morbi ut odio. Suspendisse potenti. Donec ut dolor.", "body_html": "<p>Morbi ut odio. Suspendisse potenti. Donec ut dolor.</p>", "createtime": "2017-04-06 00:00:00", "id": 37 } ] }
ok 接下來就是對於我一個js渣來講最難的部分了,前端動態導入post
如下代碼僅僅爲了實現功能,對於一個js渣的代碼來講,對你們沒有任何參考價值,僅供參考,僅供參考,僅供參考,重要的話說三遍!!
<script type="text/javascript"> $(window).scroll(function () { var scrollTop = $(this).scrollTop(); var scrollHeight = $(document).height(); var windowHeight = $(this).height(); if (scrollTop + windowHeight == scrollHeight) { $.getJSON({url:"{{url_for('api.posts')}}",data:{page:$("#page_num").val()-0+1}, success:function (data,status) { $("#page_num").val(data.page); $("#has_next").val(data.has_next); console.log(data); var html=""; for(var i=0;i<data.posts.length;i++) { html+="<div class='bs-callout"; if(i%2==0){ html+=" bs-callout-last "; }else { html+=" bs-callout-d "; } html+="'>"; html+="<div class='row'>"; html+="<div class='col-sm-2 col-md-2'>"; html+="<a class='text-left' href='/user/"+data.posts[i].author.username+"'>"; html+="<img src='http://on4ag3uf5.bkt.clouddn.com/"+data.posts[i].author.headimg+"'>"; html+="</a>"; html+="</div>"; html+="<div class='col-sm-10 col-md-10'>"; html+="<div>"; html+="<p>"; if(data.posts[i].body_html!=""){ html+=data.posts[i].body_html; }else{ html+=data.posts[i].body; } html+="</p>"; html+="</div>"; html+="<div>"; html+="<a class='text-left' href='/user/"+data.posts[i].author.username+"'>"+data.posts[i].author.nickname+"</a>"; html+="<span class='text-right'>發表於 "+moment( data.posts[i].createtime).fromNow(refresh=true)+"前</span>"; html+="</div>"; html+="</div>"; html+="</div>"; html+="</div>"; } $("#all").html($("#all").html()+html); }}); } });
能夠看到,很爛的js代碼,基本都是HTML拼接,但無論怎麼說,功能算是實現了,並且運行起來也算是流暢,固然,若是誰有react或angularjs或vue的解決方案的話,仍是不吝賜教。並且不知道你還注意到沒有,在日期的</span>前面多了一個的前字,這是因爲flask-moment插件的fromNow直接顯示n天前,而momentjs則顯示的是n天,不知道是哪裏的配置有問題,若是哪位大俠可以明白,還望幫忙解惑,先謝謝了。