Backbone筆記之二(Model/Collection)

來源:互聯網
上載者:User
Model

View的部分基本上就是這樣了,現在開始來談Model。

Model其實就是一條資料記錄。只不過它不是一般的待用資料記錄,它不但可以不限定資料結構,還可以自動與後端互動,甚至還可以綁定事件以實現相應View的自動更新。

最簡單的Model就是這樣:

var Foo = Backbone.Model.extend({});// 或是初始化預設資料var Foo = Backbone.Model.extend({    defaults: {        name: "hello",        value: "233"    }});//  或是運行時賦值。//  比如這樣:    var foo = new Foo({name:"world", value:"874"});//  或這樣:    var foo = new Foo;    foo.set({name:"world", value:"874"});

可以顯示一下結果看看效果:

$("#body").text(JSON.stringify(foo.toJSON()));
Collection

Collection就是一個Model集合。因為Model是一條資料記錄,也就是說,Collection相當於是一個資料集。

同樣,一個最簡單的Collection如下:

var FooList = Backbone.Collection.extend({    model: Foo});

之後你可以往裡增加資料:

    var foos = new FooList;    foos.add([{name:"hello", value:"233"},{name:"world", value:"874"}]);    $("#body").text(JSON.stringify(foos.at(0)));

更新刪除的方式請參考官方文檔。

注意,每個Model記錄會自動有一個id/cid的屬性,是記錄的唯一標誌。比如:

foos.get(foos.at(0).cid)
Model的事件綁定

為了能在資料變更之後及時更新View上的顯示,那就需要通過事件機制來處理。

var Task = Backbone.Model.extend({    initialize: function () {        this.on("change:name", function (model) {            alert("new name is : " + model.get("name"));        });    }});    var t = new Task({tid:"3333", name:"oooo", state:"working"});    t.set({name:"xxx"});

當執行到t.set()的時候,Model資料發生變化,將觸發change:name事件。

測試用的後端

在介紹與後端互動之前,先來一個簡單的後端。

這裡用web.py做一個最簡單的:

# start.pyimport webweb.config.debug = Falsefrom webpyext.webcommon import WebNotfoundErrorfrom webpyext.apiserver import RestBaseHandler, kwargs_decoratorimport logginglogger = logging.getLogger(__name__)urls = (        "/task/?"                    , "Tasks",        "/task/([0-9]+)/?"           , "Tasks",        )app = web.application(urls, locals())class APIHandler(RestBaseHandler):    def __init__(self):        self.dbconn = web.database(dbn='sqlite', db='xllxweb.dat')class Tasks(APIHandler):    def GET_(self, id=""):        if id:            result=self.dbconn.select("task", where="id=$id", vars={'id':int(id)}).list()            if not len(result):                raise WebNotfoundError("This task was not found!")            return result[0]        else:            return self.dbconn.select("task").list()    @kwargs_decorator    def POST_(self, kwargs={}):        return "%s" % self.dbconn.insert("task", **kwargs)    @kwargs_decorator    def PUT_(self, id, kwargs={}):        self.dbconn.update("task", where="id=$id", vars={'id':id}, **kwargs)        return ""    def DELETE_(self, id):        self.dbconn.delete("task", where="id=$id", vars={'id':id})        return ""if __name__ == "__main__":    import logging    logging.basicConfig(level=logging.DEBUG)    dbconn = web.database(dbn='sqlite', db='xllxweb.dat')    sql = """create table if not exists task (        id integer primary key not null,        name varchar not null,        state varchar    )"""    dbconn.query(sql)    app.run()

其中 webpyext 是我自己寫的一個擴充 web.py 的工具庫,提供一些增強功能。比如這裡用到的三個東西:RestBaseHandler, kwargs_decorator, WebNotfoundError。

其 中RestBaseHandler是提供一個統一的route handler去處理API調用,把固定格式的REST API調用請求轉為對方法的調用,其中還包括了對返回資料的JSON轉換。kwargs_decorator用於把HTTP請求參數轉為方法調用中的kwargs參數,可以自動處理backbone的JSON格式請求(不是一般的HTTP標準請求)。WebNotfoundError是一組HTTP響應專用的異常之一。

本例使用一個SQLite資料庫:xllxweb.dat 作為測試,其中只包含一個表:task ,表結構見代碼。

現在這個後台實現了這些功能:

/task : 取得所有tasks(GET)或建立一個新task(POST,帶參數為task欄位,返回記錄id號)
/task/[:tid] : 取得某個TaskID的task(GET)或修改(PUT,參數為需要修改的欄位)或刪除(DELETE,無參數)

以上完全是按照backbone的要求實現,並符合REST規範。

運行 python start.py 即可通過 http://localhost:8080 訪問。

Model/Collection與後端互動

首先是寫相應的Model和Collection:

var Task = Backbone.Model.extend({    urlRoot: "/task",});var TaskList = Backbone.Collection.extend({    url: "/task",    model: Task,});

就是最簡單的實現,與前面的例子相比,就是增加了url/urlRoot,這就是與後端互動的機關所在。

之後就可以在這個基礎上進行CRUD操作了。

// Createvar t = new Task({name:"hello", state:"waiting"});t.save();alert("Saved");var tid = t.id// Readt = new Task({id:tid});t.fetch({success: function(task) {    alert(JSON.stringify(task.toJSON()));}});// Updatet = new Task({id:tid});t.set({name:"world"});t.save();alert("Updated");// Deletet = new Task({id:tid});t.destroy();

需要注意的是:這些所有的操作都是非同步的,如果需要獲得操作結果(比如Read操作),必須通過回呼函數(比如fetch裡那個success回調),否則通常將無法取得正確的結果(比如在fetch執行後立即讀取t變數的值,將會只有id一個值,其它的屬性值都會為空白)。代碼中插入的alert主要是起等待作用。

以上是Model的操作方式,Collection與此類似,區別只在於Collection取得的是一組Model列表。

關於以上操作對應的HTTP請求及響應格式如下:

  Model Request Model Response Collection Request Collection Response
Create POST /task/
Content-Type: application/json
{tid: "1234"...}
... No No
Read GET /task/1 {tid: "1234"...} GET /task/ [{tid: "1234"...}...]
Update PUT /task/1
Content-Type: application/json
{name: "world"...}
... No No
Delete DELETE /task/1 ... No No

上表供進行後端開發時參考。如開發中遇到任何問題,建議立即開啟FireBug分析。

其中Collection只有Read,其它的Create/Update/Delete其實最終都是調用Model的相應方法處理的。

Model的資料校正

為了防止往Model裡存入不正確的值,可以對其加一個校正檢查,類似於資料庫的“約束(constraint)”。

下面的代碼約束name欄位必須長於3個字元。

var Task = Backbone.Model.extend({    urlRoot: "/task",    initialize: function () {        this.on("invalid", function (model, error) {            alert(error);        });    },    validate: function (attrs, options) {        if (attrs.name.length<3) {            return "name must longer than 3 chars!";        }    },});var t = new Task({id:1});t.fetch({success: function (task) {        task.set({name:"hi"});        task.save();    }});

注意,backbone有個坑爹的設定,那就是如果set一個欄位為空白,比如 set({name:""}) 時將不會觸發validate校正,在實際應用中要小心這個坑。

除此之外,還有一個坑就是:在我現在用的這個版本(0.9.10)裡,validate只在save的時候觸發,網上很多資料說它會在set的時候觸發可能是以前版本的設定,這個坑也要小心。

(待續)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.