成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

使用 Flask 和 AngularJS 構(gòu)建博客 - 2

awokezhou / 1953人閱讀

摘要:我們將使用方法創(chuàng)建一個(gè)。我們傳遞一個(gè)布爾類(lèi)型,這個(gè)就是我們?cè)缦扔懻摰牡膮?shù)。再使用和構(gòu)建博客教程系列的第三部分見(jiàn)。所有的源碼都在上,但是應(yīng)用程序的源碼還沒(méi)有放上去,因?yàn)槲覀冞€沒(méi)有完成它,等到第三部分寫(xiě)完以后再放全部的源碼到上。

  

注:該文作者是 John Kevin M. Basco,原文地址是 Building a blog using Flask and AngularJS Part 2

  

注:翻譯的第一部分請(qǐng)移步到 - 使用 Flask 和 AngularJS 構(gòu)建博客 - 1

這是這個(gè)教程系列的第二部分,如果你還沒(méi)有都第一部分,請(qǐng)移步到這里:http://blog.john.mayonvolcanosoftware.com/building-a-blog-using-flask-and-angularjs-part-1/

因?yàn)槲覀冊(cè)谠撓盗械牡谝徊糠忠呀?jīng)構(gòu)建好了 REST API ,在這部分我們將專(zhuān)注于構(gòu)建一個(gè) AngularJS 應(yīng)用,用來(lái)使用我們構(gòu)建的 REST API。

目錄結(jié)構(gòu)

AngularJS 應(yīng)用的目錄結(jié)構(gòu)看起來(lái)像這樣:

安裝必要的包

我們將使用的包如下:

angular-route

bootstrap

restangular

angularjs

angular-local-storage

如果你不熟悉 Restangular 的話,我建議你首先讀下 Restangular 的文檔 - https://github.com/mgonto/restangular

或者如果你懶得讀它的文檔,隨時(shí)繼續(xù)閱讀本教程,當(dāng)你遇到如下對(duì)你沒(méi)有意義的 Restangular 代碼的時(shí)候,你可以參考下 Restangular 文檔。

為了使得事情更容易,在 blog/client/ 目錄創(chuàng)建一個(gè) bower.json 文件,并且拷貝和粘貼以下內(nèi)容:

{
  "name": "client",
  "version": "0.0.0",
  "authors": [
    "John Kevin Basco "
  ],
  "license": "MIT",
  "ignore": [
    "**/.*",
    "node_modules",
    "bower_components",
    "test",
    "tests"
  ],
  "dependencies": {
    "angular-route": "~1.2.21",
    "bootstrap": "~3.2.0",
    "restangular": "~1.4.0",
    "angularjs": "~1.2.21",
    "angular-local-storage": "~0.0.7"
  }
}

然后進(jìn)入 blog/client 目錄,運(yùn)行 bower install 來(lái)安裝必要的包。

初始化應(yīng)用設(shè)置

首先,在 blog/client 目錄下創(chuàng)建一個(gè)新文件,并命名為 index.html,然后拷貝和粘貼以下內(nèi)容:



    
        
        Blog

        
        
        
    
    

        

        

在以上代碼中,我們只是簡(jiǎn)單的包含了我們稍后將要?jiǎng)?chuàng)建的 css 和 javascript 文件。我們也為 navigation bar, footer 等等添加了 html markup。你將注意到在以上的 gist 中,它包含了

這個(gè) html 元素。這是一個(gè)當(dāng)前的路由將用來(lái)插入模板的地方。你將看到這些事情:ng-class="{active: isActive("/")}"ng-show="isLoggedIn",忽略它們現(xiàn)在。我們將在 為 ApplicationCtrl 寫(xiě)代碼的時(shí)候討論它們。

添加一些樣式

現(xiàn)在讓我們添加一些樣式以便這個(gè) app 看起來(lái)更好。為了使我們的工作更輕松,讓我們使用一個(gè) Bootstrap 提供的主題 - http://getbootstrap.com/examples/blog/。在 app/client/css 目錄下創(chuàng)建一個(gè)新文件,并命名為 theme.css,然后拷貝和粘貼以下內(nèi)容:

/*
 * Globals
 */

body {
    font-family: Georgia, "Times New Roman", Times, serif;
    color: #555;
}

h1, .h1,
h2, .h2,
h3, .h3,
h4, .h4,
h5, .h5,
h6, .h6 {
    margin-top: 0;
    font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
    font-weight: normal;
    color: #333;
}


/*
 * Override Bootstrap"s default container.
 */

@media (min-width: 1200px) {
    .container {
        width: 970px;
    }
}


/*
 * Masthead for nav
 */

.blog-masthead {
    background-color: #428bca;
    -webkit-box-shadow: inset 0 -2px 5px rgba(0,0,0,.1);
                    box-shadow: inset 0 -2px 5px rgba(0,0,0,.1);
}

/* Nav links */
.blog-nav-item {
    position: relative;
    display: inline-block;
    padding: 10px;
    font-weight: 500;
    color: #cffffdeb;
}
.blog-nav-item:hover,
.blog-nav-item:focus {
    color: #fff;
    text-decoration: none;
}

/* Active state gets a caret at the bottom */
.blog-nav .active {
    color: #fff;
}
.blog-nav .active:after {
    position: absolute;
    bottom: 0;
    left: 50%;
    width: 0;
    height: 0;
    margin-left: -5px;
    vertical-align: middle;
    content: " ";
    border-right: 5px solid transparent;
    border-bottom: 5px solid;
    border-left: 5px solid transparent;
}


/*
 * Blog name and description
 */

.blog-header {
    padding-top: 20px;
    padding-bottom: 20px;
}
.blog-title {
    margin-top: 30px;
    margin-bottom: 0;
    font-size: 60px;
    font-weight: normal;
}
.blog-description {
    font-size: 20px;
    color: #999;
}


/*
 * Main column and sidebar layout
 */

.blog-main {
    font-size: 18px;
    line-height: 1.5;
}

/* Sidebar modules for boxing content */
.sidebar-module {
    padding: 15px;
    margin: 0 -15px 15px;
}
.sidebar-module-inset {
    padding: 15px;
    background-color: #f5f5f5;
    border-radius: 4px;
}
.sidebar-module-inset p:last-child,
.sidebar-module-inset ul:last-child,
.sidebar-module-inset ol:last-child {
    margin-bottom: 0;
}



/* Pagination */
.pager {
    margin-bottom: 60px;
    text-align: left;
}
.pager > li > a {
    width: 140px;
    padding: 10px 20px;
    text-align: center;
    border-radius: 30px;
}


/*
 * Blog posts
 */

.blog-post {
    margin-bottom: 60px;
}
.blog-post-title {
    margin-bottom: 5px;
    font-size: 40px;
}
.blog-post-meta {
    margin-bottom: 20px;
    color: #999;
}


/*
 * Footer
 */

.blog-footer {
    padding: 40px 0;
    color: #999;
    text-align: center;
    background-color: #f9f9f9;
    border-top: 1px solid #e5e5e5;
}
.blog-footer p:last-child {
    margin-bottom: 0;
}

在 app/client/css 目錄下創(chuàng)建另外一個(gè)文件,命名為 styles.css ,然后拷貝和粘貼一下內(nèi)容:

.main-view {
    margin-top: 20px;
    margin-bottom: 20px;
}

現(xiàn)在進(jìn)入 blog/client 目錄,然后運(yùn)行這個(gè)命令:python -m SimpleHTTPServer 8000,現(xiàn)在訪問(wèn) http://localhost:8000/,你應(yīng)該可以看到應(yīng)用已經(jīng)有設(shè)計(jì)樣式。

創(chuàng)建必須的 javascript 文件

注意:以下應(yīng)用使用的配置變量的值,為了假話,被硬編碼了。在生產(chǎn)環(huán)境的應(yīng)用中,需要把它放入一個(gè)配置文件中,因此你可以根據(jù)不同的環(huán)境使用不同的值,比如開(kāi)發(fā)環(huán)境和生產(chǎn)環(huán)境。

現(xiàn)在讓我們創(chuàng)建必須的 javascript 文件,在 blog/client/js 目錄下創(chuàng)建一個(gè)新文件,命名為 main.js 并且以下的代碼拷貝和粘貼進(jìn)文件:

window.Blog = angular.module("Blog", ["ngRoute", "restangular", "LocalStorageModule"])

.run(function($location, Restangular, AuthService) {
    Restangular.setFullRequestInterceptor(function(element, operation, route, url, headers, params, httpConfig) {
        headers["Authorization"] = "Basic " + AuthService.getToken();
        return {
            headers: headers
        };
    });

    Restangular.setErrorInterceptor(function(response, deferred, responseHandler) {
        if (response.config.bypassErrorInterceptor) {
            return true;
        } else {
            switch (response.status) {
                case 401:
                    AuthService.logout();
                    $location.path("/sessions/create");
                    break;
                default:
                    throw new Error("No handler for status code " + response.status);
            }
            return false;
        }
    });
})

.config(function($routeProvider, RestangularProvider) {

    RestangularProvider.setBaseUrl("http://localhost:5000/api/v1");

    var partialsDir = "../partials";

    var redirectIfAuthenticated = function(route) {
        return function($location, $q, AuthService) {

            var deferred = $q.defer();

            if (AuthService.isAuthenticated()) {
                deferred.reject()
                $location.path(route);
            } else {
                deferred.resolve()
            }

            return deferred.promise;
        }
    }

    var redirectIfNotAuthenticated = function(route) {
        return function($location, $q, AuthService) {

            var deferred = $q.defer();

            if (! AuthService.isAuthenticated()) {
                deferred.reject()
                $location.path(route);
            } else {
                deferred.resolve()
            }

            return deferred.promise;
        }
    }

    $routeProvider
        .when("/", {
            controller: "HomeDetailCtrl",
            templateUrl: partialsDir + "/home/detail.html"
        })
        .when("/sessions/create", {
            controller: "SessionCreateCtrl",
            templateUrl: partialsDir + "/session/create.html",
            resolve: {
                redirectIfAuthenticated: redirectIfAuthenticated("/posts/create")
            }
        })
        .when("/sessions/destroy", {
            controller: "SessionDestroyCtrl",
            templateUrl: partialsDir + "/session/destroy.html"
        })
        .when("/users/create", {
            controller: "UserCreateCtrl",
            templateUrl: partialsDir + "/user/create.html"
        })
        .when("/posts/create", {
            controller: "PostCreateCtrl",
            templateUrl: partialsDir + "/post/create.html",
            resolve: {
                redirectIfNotAuthenticated: redirectIfNotAuthenticated("/sessions/create")
            }
        });
})

在以上代碼中,我們初始化了我們的應(yīng)用,配置 Restangular 來(lái)包括每個(gè)請(qǐng)求的登錄用戶的用戶名和密碼,配置 Restangular 來(lái)使用一個(gè)錯(cuò)誤攔截器,它將刪除本地存儲(chǔ)的所有已經(jīng)保存的數(shù)據(jù),并且如果 REST API 返回一個(gè) 401 狀態(tài)碼,則把用戶跳轉(zhuǎn)到登錄頁(yè)面。

在配置部分,我們?cè)O(shè)置了 Restangular 將使用的基準(zhǔn) url,我們也設(shè)置了路由。你將注意到 /posts/create 路由有一個(gè)解決屬性包含了 redirectIfNotAuthenticated promise。是的,像你猜的那樣,如果用戶未被授權(quán),它將把用戶跳轉(zhuǎn)到登錄頁(yè)面。/sessions/create 路由也有一個(gè)解決屬性,但是它包含了 redirectIfAuthenticated promise 而不是 redirectIfNotAuthenticated promise。如果用戶被授權(quán)了,它將簡(jiǎn)單的跳轉(zhuǎn)用戶到創(chuàng)建博客的頁(yè)面。你可以閱讀關(guān)于這個(gè)主題的更多信息 - http://blog.john.mayonvolcanosoftware.com/protecting-routes-in-angularjs/。

Factories

讓我們創(chuàng)建我們的應(yīng)用將使用到的工廠方法。

Post

讓我們?cè)?blog/client/js/factories 目錄下創(chuàng)建一個(gè)新文件,命名為 Post.js ,然后拷貝并粘貼一下代碼到文件中:

Blog.factory("Post", function(Restangular) {
    var Post;
    Post = {
        get: function() {
            return Restangular
                .one("posts")
                .getList();
        },
        create: function(data) {
            return Restangular
                .one("posts")
                .customPOST(data);
        }
    };
    return Post;
})

在以上代碼中,factory 將創(chuàng)建一個(gè)對(duì)象,該對(duì)象有一個(gè) get 和 create 方法。我們將使用 get 方法來(lái)獲取博客列表,create 方法來(lái)創(chuàng)建一篇博客。

Session

讓我們?cè)?blog/client/js/factories 目錄下創(chuàng)建一個(gè)新文件,命名為 Session.js ,然后拷貝并粘貼一下代碼到文件中:

Blog.factory("Session", function(Restangular) {
    var Session;
    Session = {
        create: function(data, bypassErrorInterceptor) {
            return Restangular
                .one("sessions")
                .withHttpConfig({bypassErrorInterceptor: bypassErrorInterceptor})
                .customPOST(data);
        }
    };
    return Session;
})

上面的 Session 工廠有一個(gè) create 方法返回這個(gè)對(duì)象。我們將用這個(gè) create 方法來(lái)授權(quán)一個(gè)用戶的 email 和密碼。你將注意到 create 方法有一個(gè)參數(shù)叫做 bypassErrorInterceptor。這個(gè)參數(shù)應(yīng)該是一個(gè)布爾類(lèi)型的值(true or false),當(dāng) bypassErrorInterceptor 是 true 的時(shí)候,它將繞過(guò)我們?cè)缦仍谂渲脡K中定義的 error 攔截器。這不會(huì)立即顯得有意義,但是在后面我們將遇到一個(gè)場(chǎng)景,在那我們需要繞過(guò) error 攔截器。

User

在 blog/client/js/factories 目錄下創(chuàng)建一個(gè)新文件,并命名為 User.js,然后把以下代碼拷貝和粘貼進(jìn)文件:

Blog.factory("User", function(Restangular) {
    var User;
    User = {
        create: function(user) {
            return Restangular
                .one("users")
                .customPOST(user);
        }
    };
    return User;
}

User 工廠將有一個(gè) create 方法返回該對(duì)象。我們將使用 create 方法創(chuàng)建一個(gè) user。

Services

我們的應(yīng)用需要一個(gè)服務(wù),該服務(wù)包含登錄,登出,和校驗(yàn)該用戶是否被授權(quán)的業(yè)務(wù)邏輯。我們把該服務(wù)命名為 AuthService。在 blog/cient/js/services 目錄下創(chuàng)建一個(gè)新文件,并命名為 AuthService.js,然后拷貝和粘貼一下代碼到文件中:

Blog.service("AuthService", AuthService = function($q, localStorageService, Session) {

    this.login = function(credentials) {
        var me = this;
        deferred = $q.defer()
        Session.create(credentials, true).then(function(user) {
            me.setToken(credentials);
            return deferred.resolve(user);
        }, function(response) {
            if (response.status == 401) {
                return deferred.reject(false);
            }
            throw new Error("No handler for status code " + response.status);
        });
        return deferred.promise
    };

    this.logout = function() {
        localStorageService.clearAll();
    };

    this.isAuthenticated = function() {
        var token = this.getToken();
        if (token) {
            return true
        }
        return false;
    };

    this.setToken = function(credentials) {
        localStorageService.set("token", btoa(credentials.email + ":" + credentials.password));
    };

    this.getToken = function() {
        return localStorageService.get("token");
    };

    return this;
}

以上的 login 方法使用 Session.create 認(rèn)證用戶的認(rèn)證信息。當(dāng)?shù)卿浾J(rèn)證信息是有效的,我們將保存 base64 編碼格式的 email 和密碼到本地存儲(chǔ)稍后使用,并授權(quán)。當(dāng)?shù)卿浾J(rèn)證信息是無(wú)效的(當(dāng)?shù)卿浾J(rèn)證信息是無(wú)效的,REST API 將返回一個(gè) 401 狀態(tài)碼),我們簡(jiǎn)單的拒絕授權(quán),并且讓使用該方法的代碼處理它??匆幌挛覀儌鬟f給 Session.create 的第二個(gè)參數(shù)。我們傳遞一個(gè)布爾類(lèi)型(true),這個(gè)就是我們?cè)缦扔懻摰?bypassErrorInterceptor 的參數(shù)。我們需要繞過(guò)在配置塊中的 error 攔截器,因?yàn)槿绻覀儾贿@樣做,處理 401 錯(cuò)誤碼的 handler 將把用戶跳轉(zhuǎn)到登錄視圖。我們想這個(gè)發(fā)生在其他場(chǎng)景,但當(dāng)我們正在登錄視圖并且用戶提交了錯(cuò)誤的認(rèn)證信息的時(shí)候,我們想展示一個(gè)錯(cuò)誤消息,比如“Incorrect login credentials. Please try again.”。這就是為什么我們需要繞過(guò)默認(rèn)的 error 攔截器,使用一個(gè)新的,包含了不同的業(yè)務(wù)邏輯(檢查以上代碼的 10 - 15 行)。

logout 方法將清理保存在本地存儲(chǔ)的數(shù)據(jù),isAuthenticated 方法僅僅通過(guò)檢查 token 是否被呈現(xiàn)來(lái)檢查當(dāng)前用戶是否被授權(quán)。setToken 方法保存一個(gè) token (base64 編碼格式的 email 和 password)到本地存儲(chǔ)中,getToken 方法獲取保存在本地存儲(chǔ)中的 token。

Directives

我們應(yīng)用的 registration form 將有一個(gè) password 和 一個(gè)確認(rèn) password 字段,因此我們需要一個(gè)方法來(lái)校驗(yàn)值是否匹配。為這個(gè)我們將使用 directive,在 blog/client/js/directives 目錄下創(chuàng)建一個(gè)新文件,并命名為 match.js,然后拷貝和粘貼一下代碼到文件中:

Blog.directive("match", function () {
    return {
        require: "ngModel",
        restrict: "A",
        scope: {
            match: "="
        },
        link: function(scope, elem, attrs, ctrl) {
            scope.$watch(function() {
                return (ctrl.$pristine && angular.isUndefined(ctrl.$modelValue)) || scope.match === ctrl.$modelValue;
            }, function(currentValue) {
                ctrl.$setValidity("match", currentValue);
            });
        }
    };
}

信任以上 directive 的作者。我是從別處抓取來(lái)了以上源碼,但是我沒(méi)有忘記鏈接到該站點(diǎn)和誰(shuí)是作者。

我們現(xiàn)在完成了我們 AngularJS 應(yīng)用程序的一半。我們還沒(méi)有寫(xiě)的剩下部分是控制層和模板。因?yàn)檫@篇文章太長(zhǎng)了,我決定在第三部分寫(xiě)控制層和模板部分。同時(shí),研究目前為止我們已經(jīng)編寫(xiě)的代碼,讓我們更熟悉它。再使用 Flask 和 AngularJS 構(gòu)建博客教程系列的第三部分見(jiàn)。

所有的 REST API 源碼都在 Github 上 - https://github.com/basco-johnkevin/building-a-blog-using-flask-and-angularjs ,但是 AngularJS 應(yīng)用程序的源碼還沒(méi)有放上去,因?yàn)槲覀冞€沒(méi)有完成它,等到第三部分寫(xiě)完以后再放全部的源碼到 Github 上。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/45297.html

相關(guān)文章

  • 使用 Flask AngularJS 構(gòu)建博客 - 1

    摘要:注原文作者,原文地址為在這個(gè)教程中,我們將使用和構(gòu)建一個(gè)博客。在開(kāi)發(fā)期間,這將允許我們把它們運(yùn)行在不同的端口例如和?,F(xiàn)在我們將進(jìn)入目錄并使用運(yùn)行這個(gè)腳本。示例創(chuàng)建一篇文章為了創(chuàng)建一篇文章,你需要發(fā)送一個(gè)請(qǐng)求給。 注:原文作者 John Kevin M. Basco,原文地址為 Building a blog using Flask and AngularJS Part 1 在...

    劉玉平 評(píng)論0 收藏0
  • 使用 Flask AngularJS 構(gòu)建博客 - 1

    摘要:注原文作者,原文地址為在這個(gè)教程中,我們將使用和構(gòu)建一個(gè)博客。在開(kāi)發(fā)期間,這將允許我們把它們運(yùn)行在不同的端口例如和?,F(xiàn)在我們將進(jìn)入目錄并使用運(yùn)行這個(gè)腳本。示例創(chuàng)建一篇文章為了創(chuàng)建一篇文章,你需要發(fā)送一個(gè)請(qǐng)求給。 注:原文作者 John Kevin M. Basco,原文地址為 Building a blog using Flask and AngularJS Part 1 在...

    lavnFan 評(píng)論0 收藏0
  • MongoDB 資源、庫(kù)、工具、應(yīng)用程序精選列表中文版

    摘要:推薦閱讀資源庫(kù)工具應(yīng)用程序精選列表中文版有哪些鮮為人知,但是很有意思的網(wǎng)站一份攻城獅筆記每天搜集上優(yōu)秀的項(xiàng)目一些有趣的民間故事超好用的谷歌瀏覽器油猴插件合集目錄資源文檔文章圖書(shū)會(huì)談教程更多庫(kù)工具管理數(shù)據(jù)部署桌面發(fā)展監(jiān)控應(yīng)用資源文檔介紹文檔教 推薦閱讀 MongoDB 資源、庫(kù)、工具、應(yīng)用程序精選列表中文版 有哪些鮮為人知,但是很有意思的網(wǎng)站? 一份攻城獅筆記 每天搜集 Github ...

    e10101 評(píng)論0 收藏0
  • 【譯】《精通使用AngularJS開(kāi)發(fā)Web App》(一) --- 相關(guān)背景、社區(qū)、工具介紹

    摘要:下一篇譯精通使用開(kāi)發(fā)二原版書(shū)名第一章之道這一章主要是介紹,包括這個(gè)框架以及它背后的項(xiàng)目。幸運(yùn)的是,擁有一個(gè)活躍的,支持度高的社區(qū)。另外,社區(qū)還為已經(jīng)存在的工具箱里貢獻(xiàn)了許多有意思的工具。 下一篇:【譯】《精通使用AngularJS開(kāi)發(fā)Web App》(二) 原版書(shū)名:Mastering Web Application Development with AngularJS Ch...

    ddongjian0000 評(píng)論0 收藏0
  • Day 25: 聯(lián)合Tornado、MongoDB AngularJS 進(jìn)行應(yīng)用開(kāi)發(fā)

    摘要:在被收購(gòu)之后,維護(hù)并繼續(xù)發(fā)展。設(shè)置是告訴應(yīng)用在目錄尋找應(yīng)用模板。設(shè)置告訴應(yīng)用使用目錄里面的類(lèi)似圖像文件等靜態(tài)文件。我們會(huì)在應(yīng)用開(kāi)發(fā)過(guò)程中,保持著調(diào)試器在后臺(tái)運(yùn)行。這能提供高效的開(kāi)發(fā)環(huán)境。我們會(huì)把回應(yīng)狀態(tài)設(shè)為已創(chuàng)建。 編者注:我們發(fā)現(xiàn)了有趣的系列文章《30天學(xué)習(xí)30種新技術(shù)》,正在翻譯,一天一篇更新,年終禮包。下面是第23天的內(nèi)容。 今天的《30天學(xué)習(xí)30種新技術(shù)》,我決定暫時(shí)放下...

    hsluoyz 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<