一個web應用的誕生(12)--再探首頁

就要面對本章的一個難點了,說是難點可能僅僅對於我來講,畢竟我是一個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

  1. 200 執行成功
  2. 400 請求錯誤
  3. 401 未受權
  4. 403 禁止
  5. 404 未發現
  6. 500 服務器錯

好比在代碼中寫一個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'>發表於&nbsp; "+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天,不知道是哪裏的配置有問題,若是哪位大俠可以明白,還望幫忙解惑,先謝謝了。

相關文章
相關標籤/搜索