From 0fbe68708c589bec285fd9b65ce76506c69acf9f Mon Sep 17 00:00:00 2001 From: Phodal Huang Date: Wed, 15 Nov 2017 16:38:00 +0800 Subject: [PATCH] [T] add author info --- .gitignore | 1 + chapters/0prelude.md | 51 +++++++ chapters/chapter1.md | 10 +- chapters/chapter2.md | 4 +- chapters/chapter3.md | 14 +- chapters/chapter4.md | 18 +-- chapters/chapter5.md | 12 +- chapters/chapter6.md | 12 +- chapters/chapter7.md | 4 +- growth.md | 125 ++++++++++++----- images/alipay.png | Bin 0 -> 4484 bytes images/wechat-pay.png | Bin 0 -> 54943 bytes images/wechat.jpg | Bin 0 -> 21121 bytes images/xiaomiquan.jpg | Bin 0 -> 10746 bytes index.html | 315 ++++++++++++++++++++++++------------------ 15 files changed, 354 insertions(+), 212 deletions(-) create mode 100644 images/alipay.png create mode 100644 images/wechat-pay.png create mode 100644 images/wechat.jpg create mode 100644 images/xiaomiquan.jpg diff --git a/.gitignore b/.gitignore index 3b07715..4aa9470 100644 --- a/.gitignore +++ b/.gitignore @@ -65,3 +65,4 @@ target/ *.rtf *.mobi +.idea/ \ No newline at end of file diff --git a/chapters/0prelude.md b/chapters/0prelude.md index d1da178..916b520 100644 --- a/chapters/0prelude.md +++ b/chapters/0prelude.md @@ -1,6 +1,57 @@ 序:如何成为全栈增长工程师? === +Phodal's Idea实战指南 +=== + +关于作者 +--- + +黄峰达(Phodal Huang)是一个创客、工程师、咨询师和作家。他毕业于西安文理学院电子信息工程专业,现作为一个咨询师就职于 ThoughtWorks 深圳。长期活跃于开源软件社区 GitHub,目前专注于物联网和前端领域。 + +作为一个开源软件作者,著有 Growth、Stepping、Lan、Echoesworks 等软件。其中开源学习应用 Growth,广受读者和用户好评,可在 APP Store 及各大 Android 应用商店下载。 + +作为一个技术作者,著有《自己动手设计物联网》(电子工业出版社)、《全栈应用开发:精益实践》(电子工业出版社,正在出版)。并在 GitHub 上开源有《Growth: 全栈增长工程师指南》、《GitHub 漫游指南》等七本电子书。 + +作为技术专家,他为英国 Packt 出版社审阅有物联网书籍《Learning IoT》、《Smart IoT》,前端书籍《Angular 2 Serices》、《Getting started with Angular》等技术书籍。 + +他热爱编程、写作、设计、旅行、hacking,你可以从他的个人网站:[https://www.phodal.com/](https://www.phodal.com/) 了解到更多的内容。 + +其它相关信息: + + - 微博:[http://weibo.com/phodal](http://weibo.com/phodal) + - GitHub: [https://github.com/phodal](https://github.com/phodal) + - 知乎:[https://www.zhihu.com/people/phodal](https://www.zhihu.com/people/phodal) + - SegmentFault:[https://segmentfault.com/u/phodal](https://segmentfault.com/u/phodal) + +当前为预览版,在使用的过程中遇到任何问题请及时与我联系。阅读过程中的问题,不妨在GitHub上提出来: [Issues](https://github.com/phodal/fe/issues) + +阅读过程中遇到语法错误、拼写错误、技术错误等等,不妨来个Pull Request,这样可以帮助到其他阅读这本电子书的童鞋。 + +我的电子书: + + * 《[GitHub 漫游指南](https://github.com/phodal/github-roam)》 + * 《[我的职业是前端工程师](https://github.com/phodal/fe)》 + * 《[Serverless 架构应用开发指南](https://github.com/phodal/serverless)》 + * 《[Growth: 全栈增长工程师指南](https://github.com/phodal/growth-ebook)》 + * 《[Phodal's Idea实战指南](https://github.com/phodal/ideabook)》 + * 《[一步步搭建物联网系统](https://github.com/phodal/designiot)》 + * 《[RePractise](https://github.com/phodal/repractise)》 + * 《[Growth: 全栈增长工程师实战](https://github.com/phodal/growth-in-action)》 + +我的微信公众号: + +![作者微信公众号:phodal-weixin](./images/wechat.jpg) + +支持作者,可以加入作者的小密圈: + +![小密圈](./images/xiaomiquan.jpg) + +或者转账: + +![支付宝](./images/alipay.png) ![微信](./images/wechat-pay.png) + + 记得我们在《[RePractise前端篇: 前端演进史](http://mp.weixin.qq.com/s?src=3×tamp=1463835081&ver=1&signature=z1onJvKn4TSrUmXm384CQUF1IZBVsLShsQ4DpmumN6xY0Gm5RR9XKdbf6ELzdRqg-mxdtxceTg-4-KrhYHZQC6wiSEWsP64vh0sl2Je4G16hnS6MsuZaD-u01HAENCSKoMhQiw0tu2y3-tSJsOML0w==)》中提到技术在最近十几年的飞速发展,当然最主要的就是:技术的复杂度不断地从应用层抽象到了框架层。虽说: > 技术的复杂度同力一样不会消失,也不会凭空产生,它总是从一个物体转移到另一个物体或一种形式转为另一种形式。 diff --git a/chapters/chapter1.md b/chapters/chapter1.md index 65e3252..2507d7a 100644 --- a/chapters/chapter1.md +++ b/chapters/chapter1.md @@ -8,7 +8,7 @@ Django是一个高级的Python Web开发框架,它的目标是使得开发复 由于Django最初是被开发来用于管理劳伦斯出版集团旗下的一些以新闻内容为主的网站的。所以,我们可以发现在使用Django的很多网站里,都是用于作为CMS(内容管理系统)来使用的。使用Django的一些比较知名的网站如下图所示: -![使用Django的网站](http://growth-in-action.phodal.com/images/who-use-django.jpg) +![使用Django的网站](./images/who-use-django.jpg) Django是一个MTV框架,其架构模板看上去与传统的MVC架构并没有太大的区别。其对比如下表所示: @@ -39,7 +39,7 @@ Controller | Django itself Django的每一个模块在内部都称之为APP,在每个APP里都有自己的三层结构。如下图所示: -![Django 应用架构](http://growth-in-action.phodal.com/images/django_app_arch.jpg) +![Django 应用架构](./images/django_app_arch.jpg) 这样做不仅可以在开发的时候更容易理解系统,而且可以提高代码的可复用性——因为每一个APP都是独立的应用,在下次使用时我们只需要简单的复制和粘贴。 @@ -308,7 +308,7 @@ Superuser created successfully. 输入相应的用户名和密码,即可完成创建。然后访问 [http://127.0.0.1:8000/admin](http://127.0.0.1:8000/admin),输入上面的用户名和密码就可以来到后台: -![Django后台](http://growth-in-action.phodal.com/images/django-backend.jpg) +![Django后台](./images/django-backend.jpg) ### 第一次提交 @@ -338,7 +338,7 @@ git reset db.sqlite3 这时我们会将其变成下面的状态: -![第一次提交前的reset](http://growth-in-action.phodal.com/images/first-commit.png) +![第一次提交前的reset](./images/first-commit.png) 上面的绿色文件代表这几个文件都被添加了进去,蓝色则代表未添加的文件。为了避免手误产生一些问题,我们需要添加一个名为``.gitignore``文件用于将一些文件名加入忽略名单,如下是常用的python项目的``.gitignore``文件中的内容: @@ -350,7 +350,7 @@ git reset db.sqlite3 当我们添加完这个文件,git就会识别这个文件,并忽略原来的那些文件,如下图所示: -![添加完gitignore文件后的效果](http://growth-in-action.phodal.com/images/git-ignore.png) +![添加完gitignore文件后的效果](./images/git-ignore.png) 我们只需要添加这个文件即可: diff --git a/chapters/chapter2.md b/chapters/chapter2.md index 10ee7e8..a6c7ea8 100644 --- a/chapters/chapter2.md +++ b/chapters/chapter2.md @@ -119,11 +119,11 @@ python manage.py makemigrations 进入后台,我们就可以看到BLOGPOST的一栏里,就可以对其进行相关的操作。 -![Django后台界面](http://growth-in-action.phodal.com/images/django-admin-ui.png) +![Django后台界面](./images/django-admin-ui.png) 点击Blogpost的Add后,我们就会进入如下的添加博客界面: -![Django添加博客](http://growth-in-action.phodal.com/images/admin-blog.png) +![Django添加博客](./images/admin-blog.png) 实际上,这样做的意义是将删除(Delete)、修改(Update)、添加(Create)这些内容交给用户后台来做,当然它也不需要在View/Template层来做。在我们的Template层中,我们只需要关心如何来显示这些数据。 diff --git a/chapters/chapter3.md b/chapters/chapter3.md index ee09bee..8c3cfa2 100644 --- a/chapters/chapter3.md +++ b/chapters/chapter3.md @@ -38,11 +38,11 @@ class HomepageTestCase(LiveServerTestCase): 运行上面的测试就会启动一个浏览器,并且会在浏览器上进行相应的操作。如下图所示: -![Selenium Demo](http://growth-in-action.phodal.com/images/selenium-demo.jpg) +![Selenium Demo](./images/selenium-demo.jpg) 这时你可能会产生一些疑惑,这些内容我们不是已经测试过了么?两者从测试看是差不多的,但是从流程上看来说并不是如些。下图是页面渲染的时间线: -![页面渲染时间线](http://growth-in-action.phodal.com/images/page-timing-overview.png) +![页面渲染时间线](./images/page-timing-overview.png) 请求从浏览器传到服务器要有一系列的过程,如重定向、缓存、DNS等等,最后直至返回对应的Response。我们用Django的测试框架只能实现到这一步,随后页面请请求对应的静态资料,再对页面进行渲染,在这个过程中页面的内容会发生一些变化。 @@ -150,11 +150,11 @@ INFO: Started ServerConnector@733a9ac6{HTTP/1.1}{0.0.0.0:8080} 接着,打开[http://0.0.0.0:8080/](http://0.0.0.0:8080/)就可以进行后续的安装,如下图所示: -![Jenkins安装过程](http://growth-in-action.phodal.com/images/jenkins-install.jpg) +![Jenkins安装过程](./images/jenkins-install.jpg) 慢慢等其安装完成: -![Jenkins安装完成](http://growth-in-action.phodal.com/images/jenkins-getting-started.jpg) +![Jenkins安装完成](./images/jenkins-getting-started.jpg) 等安装完成后,我们就可以开始使用Jenkins来创建我们的任务了。 @@ -170,7 +170,7 @@ INFO: Started ServerConnector@733a9ac6{HTTP/1.1}{0.0.0.0:8080} 如下图所示: -![Jenkins设计Repo](http://growth-in-action.phodal.com/images/jenkins-repo-setup.jpg) +![Jenkins设计Repo](./images/jenkins-repo-setup.jpg) 然后就是构建触发器,一共有五种类型的触发器,意思也很容易理解: @@ -200,11 +200,11 @@ pip install -r requirements.txt 然后在保存后,我们可以尝试立即构建这个项目: -![控制台输出](http://growth-in-action.phodal.com/images/build-console-ouput.jpg) +![控制台输出](./images/build-console-ouput.jpg) 在编写shell的过程中,我们要经过一些尝试,在这其中会经历一些失败的情形——即使是大部分有相关经验的程序员。如下图就是一次编写构建脚本引起的构建失败的例子: -![Jenkins失败的构建](http://growth-in-action.phodal.com/images/jenkins-failure-setup.jpg) +![Jenkins失败的构建](./images/jenkins-failure-setup.jpg) 最后,我们就得到下面的一个shell脚本,我们就可以将其变成相应的运行CI的脚本。以便于它可以在其他环境中使用: diff --git a/chapters/chapter4.md b/chapters/chapter4.md index 931bfa5..da7d23c 100644 --- a/chapters/chapter4.md +++ b/chapters/chapter4.md @@ -104,11 +104,11 @@ Running migrations: 当我们完成模板后,我们就需要登录后台,并添加对应的静态页面的配置: -![管理员界面创建flatpage](http://growth-in-action.phodal.com/images/admin-flatpages-create.jpg) +![管理员界面创建flatpage](./images/admin-flatpages-create.jpg) 然后从高级选项中填写我们的静态页面的路径,我们就可以完成静态页面的创建。如下图所示: -![flatpage高级选项](http://growth-in-action.phodal.com/images/flatpages-advance-option.png) +![flatpage高级选项](./images/flatpages-advance-option.png) 最后,还要有个链接加到首页的导航中: @@ -214,7 +214,7 @@ url(r'^comments/', include('django_comments.urls')), 遗憾的是,当我们刷新页面的时候,页面报错了,原因如下所示: -![SITE_ID报错](http://growth-in-action.phodal.com/images/site_id_issue.jpg) +![SITE_ID报错](./images/site_id_issue.jpg) 我们还需要定义一个``SITE_ID``,添加下面的代码到``settings.py``文件中即可: @@ -224,7 +224,7 @@ SITE_ID = 1 然后,我们就可以从后台创建评论: -![后台创建评论](http://growth-in-action.phodal.com/images/create-comment-backend.jpg) +![后台创建评论](./images/create-comment-backend.jpg) Sitemap --- @@ -440,22 +440,22 @@ class BlogSitemap(Sitemap): 我们可以登录Google的Webmaster:[https://www.google.com/webmasters/tools/home?hl=zh-cn](https://www.google.com/webmasters/tools/home?hl=zh-cn),然后点击添加属性来创建一个新的网站: -![添加网站](http://growth-in-action.phodal.com/images/add-property.png) +![添加网站](./images/add-property.png) 这时候Google需要确认这个网站是你的,所以它提供几种方法来验证,除了下面的推荐方法: -![推荐的验证方式](http://growth-in-action.phodal.com/images/google-add-website.png) +![推荐的验证方式](./images/google-add-website.png) 我们可以使用下面的这一些方法: -![备选的难方法](http://growth-in-action.phodal.com/images/google-addition-method.png) +![备选的难方法](./images/google-addition-method.png) 我个人比较喜欢用HTML Tag的方式来实现 -![HTML标签验证](http://growth-in-action.phodal.com/images/html-tag.png) +![HTML标签验证](./images/html-tag.png) 在我们完成验证之后,我们就可以在后台手动提交Sitemap.xml了。 -![提交Sitemap.xml](http://growth-in-action.phodal.com/images/google-add-sitemap.png) +![提交Sitemap.xml](./images/google-add-sitemap.png) 点击上方的**添加/测试站点地图**即可。 diff --git a/chapters/chapter5.md b/chapters/chapter5.md index 4871d3d..702dbcf 100644 --- a/chapters/chapter5.md +++ b/chapters/chapter5.md @@ -10,7 +10,7 @@ 它是一个支持响应式设计的框架,即页面的设计与开发应当根据用户行为以及设备环境(系统平台、屏幕尺寸、屏幕定向等)进行相应的响应和调整。如下图所示: -![响应式设计](http://growth-in-action.phodal.com/images/responsive-design.png) +![响应式设计](./images/responsive-design.png) 我们在不同的设计上看到的是不同的布局,这会依据我们的设备大小做出调整——使用媒体查询(media queries)实现。 @@ -104,15 +104,15 @@ 它在桌面下的效果大致如下图所示: -![桌面浏览器下的Bootstrap导航](http://growth-in-action.phodal.com/images/bootstrap-nav-desktop.png) +![桌面浏览器下的Bootstrap导航](./images/bootstrap-nav-desktop.png) 而在移动浏览器下则是这样的效果: -![移动设备上的导航](http://growth-in-action.phodal.com/images/nav-in-mobile.png) +![移动设备上的导航](./images/nav-in-mobile.png) 当我们点击右上角的菜单按钮时,会出现我们的菜单 -![点击导航后的结果](http://growth-in-action.phodal.com/images/nav-in-mobile-with-click.png) +![点击导航后的结果](./images/nav-in-mobile-with-click.png) ### 添加标语 @@ -164,9 +164,9 @@ 它在桌面和自动设备上的效果如下图所示: -![桌面设备效果](http://growth-in-action.phodal.com/images/desktop-blogposts.png) +![桌面设备效果](./images/desktop-blogposts.png) -![移动设备效果](http://growth-in-action.phodal.com/images/mobile-blogposts.png) +![移动设备效果](./images/mobile-blogposts.png) ### 添加footer diff --git a/chapters/chapter6.md b/chapters/chapter6.md index 17fde9f..13fdc0c 100644 --- a/chapters/chapter6.md +++ b/chapters/chapter6.md @@ -105,15 +105,15 @@ url(r'^api/', include(apiRouter.urls)) 现在,我们可以访问[http://127.0.0.1:8000/api/](http://127.0.0.1:8000/api/)来访问我们现在的API。由于Django REST Framework提供了一个UI机制,所以我们可以在网页上直接看到我们所有的API: -![Django REST Framework列表](http://growth-in-action.phodal.com/images/django-rest-framework-api-lists.png) +![Django REST Framework列表](./images/django-rest-framework-api-lists.png) 然后,点击页面中的[http://127.0.0.1:8000/api/blogpost/](http://127.0.0.1:8000/api/blogpost/),我们就可以访问博客相关的API了,如下图所示: -![博客API](http://growth-in-action.phodal.com/images/drf-blogppost-set-list.png) +![博客API](./images/drf-blogppost-set-list.png) 在页面上显示了所有的博客内容,在页面的下面有一个表单可以先让我们来创建数据: -![创建博客的表单](http://growth-in-action.phodal.com/images/api-post-form.png) +![创建博客的表单](./images/api-post-form.png) 直接在表单中添加数据,我们就可以完成数据创建了。 @@ -125,18 +125,18 @@ curl -i http://127.0.0.1:8000/api/blogpost/ 即可返回相应的结果: -![CuRL API](http://growth-in-action.phodal.com/images/curl-api.png) +![CuRL API](./images/curl-api.png) 自动完成 --- AutoComplete是一个很有意思的功能,特别是当我们的文章很多的时候,我们可以让读者有机会能搜索到相应的功能。以Google为例,Google在我们输入一些关键字的时候,会向我们推荐一些比较流行的词条可以让我们选择。 -![Google AutoComplete](http://growth-in-action.phodal.com/images/google-autocomplete.png) +![Google AutoComplete](./images/google-autocomplete.png) 同样的,我们也可以实现一个同样的效果用于我们的博客搜索: -![自动完成](http://growth-in-action.phodal.com/images/autocomplete-example.png) +![自动完成](./images/autocomplete-example.png) 当我们输入某一些关键字的时候,就会出现文章的标题,随后我们只需要点击相应的标题即可跳转到文章。 diff --git a/chapters/chapter7.md b/chapters/chapter7.md index 0c7bc37..10015f3 100644 --- a/chapters/chapter7.md +++ b/chapters/chapter7.md @@ -181,7 +181,7 @@ ionic serve 接着,就可以打开相应的Web页面,如下图所示: -![Ionic Web预览界面](http://growth-in-action.phodal.com/images/ionic-web-view.jpg) +![Ionic Web预览界面](./images/ionic-web-view.jpg) ### 构建应用 @@ -453,7 +453,7 @@ export class BlogDetailPage { 现在我们几乎已经完成了博客详情页的工作,我们可以直接通过URL来访问博客详情页:[http://localhost:8100/#/app/blog/1](http://localhost:8100/#/app/blog/1)。结果如下图所示: -![访问博客详情页](http://growth-in-action.phodal.com/images/blog-detail-page.png) +![访问博客详情页](./images/blog-detail-page.png) 不过,这时候我们的列表页并没有和详情页关联到一起。我们还需要做一些额外的工作: diff --git a/growth.md b/growth.md index 17502cb..f139df3 100644 --- a/growth.md +++ b/growth.md @@ -2,6 +2,57 @@ 序:如何成为全栈增长工程师? === +Phodal's Idea实战指南 +=== + +关于作者 +--- + +黄峰达(Phodal Huang)是一个创客、工程师、咨询师和作家。他毕业于西安文理学院电子信息工程专业,现作为一个咨询师就职于 ThoughtWorks 深圳。长期活跃于开源软件社区 GitHub,目前专注于物联网和前端领域。 + +作为一个开源软件作者,著有 Growth、Stepping、Lan、Echoesworks 等软件。其中开源学习应用 Growth,广受读者和用户好评,可在 APP Store 及各大 Android 应用商店下载。 + +作为一个技术作者,著有《自己动手设计物联网》(电子工业出版社)、《全栈应用开发:精益实践》(电子工业出版社,正在出版)。并在 GitHub 上开源有《Growth: 全栈增长工程师指南》、《GitHub 漫游指南》等七本电子书。 + +作为技术专家,他为英国 Packt 出版社审阅有物联网书籍《Learning IoT》、《Smart IoT》,前端书籍《Angular 2 Serices》、《Getting started with Angular》等技术书籍。 + +他热爱编程、写作、设计、旅行、hacking,你可以从他的个人网站:[https://www.phodal.com/](https://www.phodal.com/) 了解到更多的内容。 + +其它相关信息: + + - 微博:[http://weibo.com/phodal](http://weibo.com/phodal) + - GitHub: [https://github.com/phodal](https://github.com/phodal) + - 知乎:[https://www.zhihu.com/people/phodal](https://www.zhihu.com/people/phodal) + - SegmentFault:[https://segmentfault.com/u/phodal](https://segmentfault.com/u/phodal) + +当前为预览版,在使用的过程中遇到任何问题请及时与我联系。阅读过程中的问题,不妨在GitHub上提出来: [Issues](https://github.com/phodal/fe/issues) + +阅读过程中遇到语法错误、拼写错误、技术错误等等,不妨来个Pull Request,这样可以帮助到其他阅读这本电子书的童鞋。 + +我的电子书: + + * 《[GitHub 漫游指南](https://github.com/phodal/github-roam)》 + * 《[我的职业是前端工程师](https://github.com/phodal/fe)》 + * 《[Serverless 架构应用开发指南](https://github.com/phodal/serverless)》 + * 《[Growth: 全栈增长工程师指南](https://github.com/phodal/growth-ebook)》 + * 《[Phodal's Idea实战指南](https://github.com/phodal/ideabook)》 + * 《[一步步搭建物联网系统](https://github.com/phodal/designiot)》 + * 《[RePractise](https://github.com/phodal/repractise)》 + * 《[Growth: 全栈增长工程师实战](https://github.com/phodal/growth-in-action)》 + +我的微信公众号: + +![作者微信公众号:phodal-weixin](./images/wechat.jpg) + +支持作者,可以加入作者的小密圈: + +![小密圈](./images/xiaomiquan.jpg) + +或者转账: + +![支付宝](./images/alipay.png) ![微信](./images/wechat-pay.png) + + 记得我们在《[RePractise前端篇: 前端演进史](http://mp.weixin.qq.com/s?src=3×tamp=1463835081&ver=1&signature=z1onJvKn4TSrUmXm384CQUF1IZBVsLShsQ4DpmumN6xY0Gm5RR9XKdbf6ELzdRqg-mxdtxceTg-4-KrhYHZQC6wiSEWsP64vh0sl2Je4G16hnS6MsuZaD-u01HAENCSKoMhQiw0tu2y3-tSJsOML0w==)》中提到技术在最近十几年的飞速发展,当然最主要的就是:技术的复杂度不断地从应用层抽象到了框架层。虽说: > 技术的复杂度同力一样不会消失,也不会凭空产生,它总是从一个物体转移到另一个物体或一种形式转为另一种形式。 @@ -67,7 +118,7 @@ Django是一个高级的Python Web开发框架,它的目标是使得开发复 由于Django最初是被开发来用于管理劳伦斯出版集团旗下的一些以新闻内容为主的网站的。所以,我们可以发现在使用Django的很多网站里,都是用于作为CMS(内容管理系统)来使用的。使用Django的一些比较知名的网站如下图所示: -![使用Django的网站](http://growth-in-action.phodal.com/images/who-use-django.jpg) +![使用Django的网站](./images/who-use-django.jpg) Django是一个MTV框架,其架构模板看上去与传统的MVC架构并没有太大的区别。其对比如下表所示: @@ -98,7 +149,7 @@ Controller | Django itself Django的每一个模块在内部都称之为APP,在每个APP里都有自己的三层结构。如下图所示: -![Django 应用架构](http://growth-in-action.phodal.com/images/django_app_arch.jpg) +![Django 应用架构](./images/django_app_arch.jpg) 这样做不仅可以在开发的时候更容易理解系统,而且可以提高代码的可复用性——因为每一个APP都是独立的应用,在下次使用时我们只需要简单的复制和粘贴。 @@ -367,7 +418,7 @@ Superuser created successfully. 输入相应的用户名和密码,即可完成创建。然后访问 [http://127.0.0.1:8000/admin](http://127.0.0.1:8000/admin),输入上面的用户名和密码就可以来到后台: -![Django后台](http://growth-in-action.phodal.com/images/django-backend.jpg) +![Django后台](./images/django-backend.jpg) ### 第一次提交 @@ -397,7 +448,7 @@ git reset db.sqlite3 这时我们会将其变成下面的状态: -![第一次提交前的reset](http://growth-in-action.phodal.com/images/first-commit.png) +![第一次提交前的reset](./images/first-commit.png) 上面的绿色文件代表这几个文件都被添加了进去,蓝色则代表未添加的文件。为了避免手误产生一些问题,我们需要添加一个名为``.gitignore``文件用于将一些文件名加入忽略名单,如下是常用的python项目的``.gitignore``文件中的内容: @@ -409,7 +460,7 @@ git reset db.sqlite3 当我们添加完这个文件,git就会识别这个文件,并忽略原来的那些文件,如下图所示: -![添加完gitignore文件后的效果](http://growth-in-action.phodal.com/images/git-ignore.png) +![添加完gitignore文件后的效果](./images/git-ignore.png) 我们只需要添加这个文件即可: @@ -554,11 +605,11 @@ python manage.py makemigrations 进入后台,我们就可以看到BLOGPOST的一栏里,就可以对其进行相关的操作。 -![Django后台界面](http://growth-in-action.phodal.com/images/django-admin-ui.png) +![Django后台界面](./images/django-admin-ui.png) 点击Blogpost的Add后,我们就会进入如下的添加博客界面: -![Django添加博客](http://growth-in-action.phodal.com/images/admin-blog.png) +![Django添加博客](./images/admin-blog.png) 实际上,这样做的意义是将删除(Delete)、修改(Update)、添加(Create)这些内容交给用户后台来做,当然它也不需要在View/Template层来做。在我们的Template层中,我们只需要关心如何来显示这些数据。 @@ -895,11 +946,11 @@ class HomepageTestCase(LiveServerTestCase): 运行上面的测试就会启动一个浏览器,并且会在浏览器上进行相应的操作。如下图所示: -![Selenium Demo](http://growth-in-action.phodal.com/images/selenium-demo.jpg) +![Selenium Demo](./images/selenium-demo.jpg) 这时你可能会产生一些疑惑,这些内容我们不是已经测试过了么?两者从测试看是差不多的,但是从流程上看来说并不是如些。下图是页面渲染的时间线: -![页面渲染时间线](http://growth-in-action.phodal.com/images/page-timing-overview.png) +![页面渲染时间线](./images/page-timing-overview.png) 请求从浏览器传到服务器要有一系列的过程,如重定向、缓存、DNS等等,最后直至返回对应的Response。我们用Django的测试框架只能实现到这一步,随后页面请请求对应的静态资料,再对页面进行渲染,在这个过程中页面的内容会发生一些变化。 @@ -1007,11 +1058,11 @@ INFO: Started ServerConnector@733a9ac6{HTTP/1.1}{0.0.0.0:8080} 接着,打开[http://0.0.0.0:8080/](http://0.0.0.0:8080/)就可以进行后续的安装,如下图所示: -![Jenkins安装过程](http://growth-in-action.phodal.com/images/jenkins-install.jpg) +![Jenkins安装过程](./images/jenkins-install.jpg) 慢慢等其安装完成: -![Jenkins安装完成](http://growth-in-action.phodal.com/images/jenkins-getting-started.jpg) +![Jenkins安装完成](./images/jenkins-getting-started.jpg) 等安装完成后,我们就可以开始使用Jenkins来创建我们的任务了。 @@ -1027,7 +1078,7 @@ INFO: Started ServerConnector@733a9ac6{HTTP/1.1}{0.0.0.0:8080} 如下图所示: -![Jenkins设计Repo](http://growth-in-action.phodal.com/images/jenkins-repo-setup.jpg) +![Jenkins设计Repo](./images/jenkins-repo-setup.jpg) 然后就是构建触发器,一共有五种类型的触发器,意思也很容易理解: @@ -1057,11 +1108,11 @@ pip install -r requirements.txt 然后在保存后,我们可以尝试立即构建这个项目: -![控制台输出](http://growth-in-action.phodal.com/images/build-console-ouput.jpg) +![控制台输出](./images/build-console-ouput.jpg) 在编写shell的过程中,我们要经过一些尝试,在这其中会经历一些失败的情形——即使是大部分有相关经验的程序员。如下图就是一次编写构建脚本引起的构建失败的例子: -![Jenkins失败的构建](http://growth-in-action.phodal.com/images/jenkins-failure-setup.jpg) +![Jenkins失败的构建](./images/jenkins-failure-setup.jpg) 最后,我们就得到下面的一个shell脚本,我们就可以将其变成相应的运行CI的脚本。以便于它可以在其他环境中使用: @@ -1188,11 +1239,11 @@ Running migrations: 当我们完成模板后,我们就需要登录后台,并添加对应的静态页面的配置: -![管理员界面创建flatpage](http://growth-in-action.phodal.com/images/admin-flatpages-create.jpg) +![管理员界面创建flatpage](./images/admin-flatpages-create.jpg) 然后从高级选项中填写我们的静态页面的路径,我们就可以完成静态页面的创建。如下图所示: -![flatpage高级选项](http://growth-in-action.phodal.com/images/flatpages-advance-option.png) +![flatpage高级选项](./images/flatpages-advance-option.png) 最后,还要有个链接加到首页的导航中: @@ -1298,7 +1349,7 @@ url(r'^comments/', include('django_comments.urls')), 遗憾的是,当我们刷新页面的时候,页面报错了,原因如下所示: -![SITE_ID报错](http://growth-in-action.phodal.com/images/site_id_issue.jpg) +![SITE_ID报错](./images/site_id_issue.jpg) 我们还需要定义一个``SITE_ID``,添加下面的代码到``settings.py``文件中即可: @@ -1308,7 +1359,7 @@ SITE_ID = 1 然后,我们就可以从后台创建评论: -![后台创建评论](http://growth-in-action.phodal.com/images/create-comment-backend.jpg) +![后台创建评论](./images/create-comment-backend.jpg) Sitemap --- @@ -1524,23 +1575,23 @@ class BlogSitemap(Sitemap): 我们可以登录Google的Webmaster:[https://www.google.com/webmasters/tools/home?hl=zh-cn](https://www.google.com/webmasters/tools/home?hl=zh-cn),然后点击添加属性来创建一个新的网站: -![添加网站](http://growth-in-action.phodal.com/images/add-property.png) +![添加网站](./images/add-property.png) 这时候Google需要确认这个网站是你的,所以它提供几种方法来验证,除了下面的推荐方法: -![推荐的验证方式](http://growth-in-action.phodal.com/images/google-add-website.png) +![推荐的验证方式](./images/google-add-website.png) 我们可以使用下面的这一些方法: -![备选的难方法](http://growth-in-action.phodal.com/images/google-addition-method.png) +![备选的难方法](./images/google-addition-method.png) 我个人比较喜欢用HTML Tag的方式来实现 -![HTML标签验证](http://growth-in-action.phodal.com/images/html-tag.png) +![HTML标签验证](./images/html-tag.png) 在我们完成验证之后,我们就可以在后台手动提交Sitemap.xml了。 -![提交Sitemap.xml](http://growth-in-action.phodal.com/images/google-add-sitemap.png) +![提交Sitemap.xml](./images/google-add-sitemap.png) 点击上方的**添加/测试站点地图**即可。 @@ -1556,7 +1607,7 @@ class BlogSitemap(Sitemap): 它是一个支持响应式设计的框架,即页面的设计与开发应当根据用户行为以及设备环境(系统平台、屏幕尺寸、屏幕定向等)进行相应的响应和调整。如下图所示: -![响应式设计](http://growth-in-action.phodal.com/images/responsive-design.png) +![响应式设计](./images/responsive-design.png) 我们在不同的设计上看到的是不同的布局,这会依据我们的设备大小做出调整——使用媒体查询(media queries)实现。 @@ -1650,15 +1701,15 @@ class BlogSitemap(Sitemap): 它在桌面下的效果大致如下图所示: -![桌面浏览器下的Bootstrap导航](http://growth-in-action.phodal.com/images/bootstrap-nav-desktop.png) +![桌面浏览器下的Bootstrap导航](./images/bootstrap-nav-desktop.png) 而在移动浏览器下则是这样的效果: -![移动设备上的导航](http://growth-in-action.phodal.com/images/nav-in-mobile.png) +![移动设备上的导航](./images/nav-in-mobile.png) 当我们点击右上角的菜单按钮时,会出现我们的菜单 -![点击导航后的结果](http://growth-in-action.phodal.com/images/nav-in-mobile-with-click.png) +![点击导航后的结果](./images/nav-in-mobile-with-click.png) ### 添加标语 @@ -1710,9 +1761,9 @@ class BlogSitemap(Sitemap): 它在桌面和自动设备上的效果如下图所示: -![桌面设备效果](http://growth-in-action.phodal.com/images/desktop-blogposts.png) +![桌面设备效果](./images/desktop-blogposts.png) -![移动设备效果](http://growth-in-action.phodal.com/images/mobile-blogposts.png) +![移动设备效果](./images/mobile-blogposts.png) ### 添加footer @@ -1855,15 +1906,15 @@ url(r'^api/', include(apiRouter.urls)) 现在,我们可以访问[http://127.0.0.1:8000/api/](http://127.0.0.1:8000/api/)来访问我们现在的API。由于Django REST Framework提供了一个UI机制,所以我们可以在网页上直接看到我们所有的API: -![Django REST Framework列表](http://growth-in-action.phodal.com/images/django-rest-framework-api-lists.png) +![Django REST Framework列表](./images/django-rest-framework-api-lists.png) 然后,点击页面中的[http://127.0.0.1:8000/api/blogpost/](http://127.0.0.1:8000/api/blogpost/),我们就可以访问博客相关的API了,如下图所示: -![博客API](http://growth-in-action.phodal.com/images/drf-blogppost-set-list.png) +![博客API](./images/drf-blogppost-set-list.png) 在页面上显示了所有的博客内容,在页面的下面有一个表单可以先让我们来创建数据: -![创建博客的表单](http://growth-in-action.phodal.com/images/api-post-form.png) +![创建博客的表单](./images/api-post-form.png) 直接在表单中添加数据,我们就可以完成数据创建了。 @@ -1875,18 +1926,18 @@ curl -i http://127.0.0.1:8000/api/blogpost/ 即可返回相应的结果: -![CuRL API](http://growth-in-action.phodal.com/images/curl-api.png) +![CuRL API](./images/curl-api.png) 自动完成 --- AutoComplete是一个很有意思的功能,特别是当我们的文章很多的时候,我们可以让读者有机会能搜索到相应的功能。以Google为例,Google在我们输入一些关键字的时候,会向我们推荐一些比较流行的词条可以让我们选择。 -![Google AutoComplete](http://growth-in-action.phodal.com/images/google-autocomplete.png) +![Google AutoComplete](./images/google-autocomplete.png) 同样的,我们也可以实现一个同样的效果用于我们的博客搜索: -![自动完成](http://growth-in-action.phodal.com/images/autocomplete-example.png) +![自动完成](./images/autocomplete-example.png) 当我们输入某一些关键字的时候,就会出现文章的标题,随后我们只需要点击相应的标题即可跳转到文章。 @@ -2241,7 +2292,7 @@ ionic serve 接着,就可以打开相应的Web页面,如下图所示: -![Ionic Web预览界面](http://growth-in-action.phodal.com/images/ionic-web-view.jpg) +![Ionic Web预览界面](./images/ionic-web-view.jpg) ### 构建应用 @@ -2513,7 +2564,7 @@ export class BlogDetailPage { 现在我们几乎已经完成了博客详情页的工作,我们可以直接通过URL来访问博客详情页:[http://localhost:8100/#/app/blog/1](http://localhost:8100/#/app/blog/1)。结果如下图所示: -![访问博客详情页](http://growth-in-action.phodal.com/images/blog-detail-page.png) +![访问博客详情页](./images/blog-detail-page.png) 不过,这时候我们的列表页并没有和详情页关联到一起。我们还需要做一些额外的工作: diff --git a/images/alipay.png b/images/alipay.png new file mode 100644 index 0000000000000000000000000000000000000000..36cb9d5adaf013e8e1fa034c997504e63029652c GIT binary patch literal 4484 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 literal 0 HcmV?d00001 diff --git a/images/wechat-pay.png b/images/wechat-pay.png new file mode 100644 index 0000000000000000000000000000000000000000..6bbbe8223c6c36e0d7b6079b19e56d632c34e38b GIT binary patch literal 54943 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 Qgob+Q>locC*20AT5B_YqlK=n! literal 0 HcmV?d00001 diff --git a/images/wechat.jpg b/images/wechat.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5779d5e6e326cb62fbcd4be7217403acbf1c79e3 GIT binary patch literal 21121 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 B#!CPI literal 0 HcmV?d00001 diff --git a/images/xiaomiquan.jpg b/images/xiaomiquan.jpg new file mode 100644 index 0000000000000000000000000000000000000000..45712d65ffd9cd85f1485274fd28dfc8e232f4e2 GIT binary patch literal 10746 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 Yon>D}vHr&m@|HLA-+全栈增长工程师实战

全栈增长工程师实战目录

序:如何成为全栈增长工程师?

+

Phodal’s Idea实战指南

+

关于作者

+

黄峰达(Phodal Huang)是一个创客、工程师、咨询师和作家。他毕业于西安文理学院电子信息工程专业,现作为一个咨询师就职于 ThoughtWorks 深圳。长期活跃于开源软件社区 GitHub,目前专注于物联网和前端领域。

+

作为一个开源软件作者,著有 Growth、Stepping、Lan、Echoesworks 等软件。其中开源学习应用 Growth,广受读者和用户好评,可在 APP Store 及各大 Android 应用商店下载。

+

作为一个技术作者,著有《自己动手设计物联网》(电子工业出版社)、《全栈应用开发:精益实践》(电子工业出版社,正在出版)。并在 GitHub 上开源有《Growth: 全栈增长工程师指南》、《GitHub 漫游指南》等七本电子书。

+

作为技术专家,他为英国 Packt 出版社审阅有物联网书籍《Learning IoT》、《Smart IoT》,前端书籍《Angular 2 Serices》、《Getting started with Angular》等技术书籍。

+

他热爱编程、写作、设计、旅行、hacking,你可以从他的个人网站:https://www.phodal.com/ 了解到更多的内容。

+

其它相关信息:

+ +

当前为预览版,在使用的过程中遇到任何问题请及时与我联系。阅读过程中的问题,不妨在GitHub上提出来: Issues

+

阅读过程中遇到语法错误、拼写错误、技术错误等等,不妨来个Pull Request,这样可以帮助到其他阅读这本电子书的童鞋。

+

我的电子书:

+ +

我的微信公众号:

+
+作者微信公众号:phodal-weixin
作者微信公众号:phodal-weixin
+
+

支持作者,可以加入作者的小密圈:

+
+小密圈
小密圈
+
+

或者转账:

+

支付宝 微信

记得我们在《RePractise前端篇: 前端演进史》中提到技术在最近十几年的飞速发展,当然最主要的就是:技术的复杂度不断地从应用层抽象到了框架层。虽说:

技术的复杂度同力一样不会消失,也不会凭空产生,它总是从一个物体转移到另一个物体或一种形式转为另一种形式。

@@ -223,7 +262,7 @@

Django简介

Django是一个高级的Python Web开发框架,它的目标是使得开发复杂的、数据库驱动的网站变得更加简单。

由于Django最初是被开发来用于管理劳伦斯出版集团旗下的一些以新闻内容为主的网站的。所以,我们可以发现在使用Django的很多网站里,都是用于作为CMS(内容管理系统)来使用的。使用Django的一些比较知名的网站如下图所示:

-使用Django的网站
使用Django的网站
+使用Django的网站
使用Django的网站

Django是一个MTV框架,其架构模板看上去与传统的MVC架构并没有太大的区别。其对比如下表所示:

@@ -271,7 +310,7 @@

Django简介

Django应用架构

Django的每一个模块在内部都称之为APP,在每个APP里都有自己的三层结构。如下图所示:

-Django 应用架构
Django 应用架构
+Django 应用架构
Django 应用架构

这样做不仅可以在开发的时候更容易理解系统,而且可以提高代码的可复用性——因为每一个APP都是独立的应用,在下次使用时我们只需要简单的复制和粘贴。

说了这么多,还不如从一个hello,world开始。

@@ -437,20 +476,20 @@

Django后台

Superuser created successfully.

输入相应的用户名和密码,即可完成创建。然后访问 http://127.0.0.1:8000/admin,输入上面的用户名和密码就可以来到后台:

-Django后台
Django后台
+Django后台
Django后台

第一次提交

在创建完应用后,我们就可以进行第一次提交,通常初次提交的提交信息(commit message)是init project。如果在那之前,你没有执行git init来初始化git的话,那么我们就需要去执行这个命令。

-
git init
+
git init

它将返回类似于下面的结果

-
Initialized empty Git repository in /Users/fdhuang/test/helloworld/.git/
+
Initialized empty Git repository in /Users/fdhuang/test/helloworld/.git/

即初始化了一个空的Git项目,然后我们就可以执行add来添加上面的内容:

-
git add .
+
git add .

需要注意的是上面的数据库文件不应该添加到项目里,所以我们应该执行reset命令来重置这个状态:

-
git reset db.sqlite3
+
git reset db.sqlite3

这时我们会将其变成下面的状态:

-第一次提交前的reset
第一次提交前的reset
+第一次提交前的reset
第一次提交前的reset

上面的绿色文件代表这几个文件都被添加了进去,蓝色则代表未添加的文件。为了避免手误产生一些问题,我们需要添加一个名为.gitignore文件用于将一些文件名加入忽略名单,如下是常用的python项目的.gitignore文件中的内容:

*.pyc
@@ -458,12 +497,12 @@ 

第一次提交

*.sqlite3

当我们添加完这个文件,git就会识别这个文件,并忽略原来的那些文件,如下图所示:

-添加完gitignore文件后的效果
添加完gitignore文件后的效果
+添加完gitignore文件后的效果
添加完gitignore文件后的效果

我们只需要添加这个文件即可:

-
git add .gitignore
+
git add .gitignore

如果你之前已经不小心添加了一些不应该添加的文件,那么可以执行下面的命令来重置其状态:

-
git reset .
+
git reset .

然后再执行添加命令。

最后,我们就可以在本地提交我们的代码了:

git commit -m "init project"
@@ -533,7 +572,7 @@

创建Model

接着我们需要先将blogpost这个APP添加到配置文件blog/blog/settings.pyINSTALLED_APPS字段中:

INSTALLED_APPS = [ 
     'blogpost.apps.BlogpostConfig',
-    'django.contrib.admin',
+    'django.contrib.admin',
     ...
 ]

然后做数据库迁移:

@@ -549,11 +588,11 @@

创建Model

python manage.py makemigrations

进入后台,我们就可以看到BLOGPOST的一栏里,就可以对其进行相关的操作。

-Django后台界面
Django后台界面
+Django后台界面
Django后台界面

点击Blogpost的Add后,我们就会进入如下的添加博客界面:

-Django添加博客
Django添加博客
+Django添加博客
Django添加博客

实际上,这样做的意义是将删除(Delete)、修改(Update)、添加(Create)这些内容交给用户后台来做,当然它也不需要在View/Template层来做。在我们的Template层中,我们只需要关心如何来显示这些数据。

现在,我们可以执行一次新的代码提交——因为现在的代码可以正常工作。这样出现问题时,我们就可以即时的返回上一版本的代码。

@@ -595,14 +634,14 @@

创建博客列表页

 TEMPLATES = [
       {
           'BACKEND': 'django.template.backends.django.DjangoTemplates',
-          'DIRS': ['templates/'],
-          'APP_DIRS': True,
-          'OPTIONS': {
+          'DIRS': ['templates/'],
+          'APP_DIRS': True,
+          'OPTIONS': {
               'context_processors': [
                   'django.template.context_processors.debug',
-                  'django.template.context_processors.request',
-                 'django.contrib.auth.context_processors.auth',
-                 'django.contrib.messages.context_processors.messages',
+                  'django.template.context_processors.request',
+                 'django.contrib.auth.context_processors.auth',
+                 'django.contrib.messages.context_processors.messages',
              ],
          },
      },
@@ -728,7 +767,7 @@ 

测试首页

found = resolve('/') self.assertEqual(found.func, index)

但是这样的测试看上去没有多大意义,不过它可以保证我们的route可以和我们的URL对应上。在编写完测试后,我们就可以命令提示行中运行:

-
python manage.py test
+
python manage.py test

来查看测试的结果:

Creating test database for alias 'default'...
 
@@ -795,11 +834,11 @@ 

Selenium与第一个UI测试

在setUp——即开始的时候,我们会用selenium启动一个Firefox浏览器的进程,并执行maximize_window来将窗口最大化。在tearDown——即结束的时候,我们就会关闭这个浏览器的进程。我们的主要测试代码就在test_visit_homepage这个方法里,我们在里面访问首页,并判断标题是不是Welcome to my blog

运行上面的测试就会启动一个浏览器,并且会在浏览器上进行相应的操作。如下图所示:

-Selenium Demo
Selenium Demo
+Selenium Demo
Selenium Demo

这时你可能会产生一些疑惑,这些内容我们不是已经测试过了么?两者从测试看是差不多的,但是从流程上看来说并不是如些。下图是页面渲染的时间线:

-页面渲染时间线
页面渲染时间线
+页面渲染时间线
页面渲染时间线

请求从浏览器传到服务器要有一系列的过程,如重定向、缓存、DNS等等,最后直至返回对应的Response。我们用Django的测试框架只能实现到这一步,随后页面请请求对应的静态资料,再对页面进行渲染,在这个过程中页面的内容会发生一些变化。

为了避免页面的内容被替换掉,那么我们就需要对这部分内容进行测试。

@@ -863,32 +902,32 @@

搭建持续集成

它提供了软件开发的持续集成服务。它运行在Servlet容器中(例如Apache Tomcat)。它支持软件配置管理(SCM)工具(包括AccuRev SCM、CVS、Subversion、Git、Perforce、Clearcase和和RTC),可以执行基于Apache Ant和Apache Maven的项目,以及任意的Shell脚本和Windows批处理命令。

要使用Jenkins,只需要从Jenkins的主页上(https://jenkins.io/)下载最新的 jenkins.war文件。然后运行

-
java -jar jenkins.war
+
java -jar jenkins.war

便可以启动:

-
Running from: /Users/fdhuang/repractise/growth-ci/jenkins.war
-webroot: $user.home/.jenkins
-May 12, 2016 10:55:18 PM org.eclipse.jetty.util.log.JavaUtilLog info
-INFO: Logging initialized @489ms
-May 12, 2016 10:55:18 PM winstone.Logger logInternal
-INFO: Beginning extraction from war file
-May 12, 2016 10:55:20 PM org.eclipse.jetty.util.log.JavaUtilLog warn
-WARNING: Empty contextPath
-May 12, 2016 10:55:20 PM org.eclipse.jetty.util.log.JavaUtilLog info
-INFO: jetty-9.2.z-SNAPSHOT
-May 12, 2016 10:55:20 PM org.eclipse.jetty.util.log.JavaUtilLog info
-INFO: NO JSP Support for /, did not find org.eclipse.jetty.jsp.JettyJspServlet
-Jenkins home directory: /Users/fdhuang/.jenkins found at: $user.home/.jenkins
-May 12, 2016 10:55:21 PM org.eclipse.jetty.util.log.JavaUtilLog info
-INFO: Started w.@68c34b0{/,file:/Users/fdhuang/.jenkins/war/,AVAILABLE}{/Users/fdhuang/.jenkins/war}
-May 12, 2016 10:55:21 PM org.eclipse.jetty.util.log.JavaUtilLog info
-INFO: Started ServerConnector@733a9ac6{HTTP/1.1}{0.0.0.0:8080}
+
Running from: /Users/fdhuang/repractise/growth-ci/jenkins.war
+webroot: $user.home/.jenkins
+May 12, 2016 10:55:18 PM org.eclipse.jetty.util.log.JavaUtilLog info
+INFO: Logging initialized @489ms
+May 12, 2016 10:55:18 PM winstone.Logger logInternal
+INFO: Beginning extraction from war file
+May 12, 2016 10:55:20 PM org.eclipse.jetty.util.log.JavaUtilLog warn
+WARNING: Empty contextPath
+May 12, 2016 10:55:20 PM org.eclipse.jetty.util.log.JavaUtilLog info
+INFO: jetty-9.2.z-SNAPSHOT
+May 12, 2016 10:55:20 PM org.eclipse.jetty.util.log.JavaUtilLog info
+INFO: NO JSP Support for /, did not find org.eclipse.jetty.jsp.JettyJspServlet
+Jenkins home directory: /Users/fdhuang/.jenkins found at: $user.home/.jenkins
+May 12, 2016 10:55:21 PM org.eclipse.jetty.util.log.JavaUtilLog info
+INFO: Started w.@68c34b0{/,file:/Users/fdhuang/.jenkins/war/,AVAILABLE}{/Users/fdhuang/.jenkins/war}
+May 12, 2016 10:55:21 PM org.eclipse.jetty.util.log.JavaUtilLog info
+INFO: Started ServerConnector@733a9ac6{HTTP/1.1}{0.0.0.0:8080}

接着,打开http://0.0.0.0:8080/就可以进行后续的安装,如下图所示:

-Jenkins安装过程
Jenkins安装过程
+Jenkins安装过程
Jenkins安装过程

慢慢等其安装完成:

-Jenkins安装完成
Jenkins安装完成
+Jenkins安装完成
Jenkins安装完成

等安装完成后,我们就可以开始使用Jenkins来创建我们的任务了。

Jenkins创建任务

@@ -897,7 +936,7 @@

Jenkins创建任务

[https://github.com/phodal/growth-in-action-python-code](https://github.com/phodal/growth-in-action-python-code)

如下图所示:

-Jenkins设计Repo
Jenkins设计Repo
+Jenkins设计Repo
Jenkins设计Repo

然后就是构建触发器,一共有五种类型的触发器,意思也很容易理解:

    @@ -915,24 +954,24 @@

    Jenkins创建任务

    由于,我们暂时不需要一些特殊的构建环境配置,我们就可以将这个放空。接着,我们就可以配置构建了。

    创建shell

    在这里我们需要添加的构建步骤是:execute shell,先让我们写一个简单的安装依赖的shell

    -
    virtualenv --distribute -p /usr/local/bin/python3.5 growth-django
    -source growth-django/bin/activate
    -pip install -r requirements.txt
    +
    virtualenv --distribute -p /usr/local/bin/python3.5 growth-django
    +source growth-django/bin/activate
    +pip install -r requirements.txt

    然后在保存后,我们可以尝试立即构建这个项目:

    -控制台输出
    控制台输出
    +控制台输出
    控制台输出

    在编写shell的过程中,我们要经过一些尝试,在这其中会经历一些失败的情形——即使是大部分有相关经验的程序员。如下图就是一次编写构建脚本引起的构建失败的例子:

    -Jenkins失败的构建
    Jenkins失败的构建
    +Jenkins失败的构建
    Jenkins失败的构建

    最后,我们就得到下面的一个shell脚本,我们就可以将其变成相应的运行CI的脚本。以便于它可以在其他环境中使用:

    #!/usr/bin/env bash
    -virtualenv --distribute -p /usr/local/bin/python3.5 growth-django
    -source growth-django/bin/activate
    -pip install -r requirements.txt
    -python manage.py test
    -python manage.py test test
    +virtualenv --distribute -p /usr/local/bin/python3.5 growth-django +source growth-django/bin/activate +pip install -r requirements.txt +python manage.py test +python manage.py test test

记得给你的shell文件,加上执行的标志:

chmod u+x ./scripts/ci.sh

最后,我们就可以修改CI上相应的构建环境的配置。

@@ -1012,11 +1051,11 @@

创建模板

{% endblock %}

当我们完成模板后,我们就需要登录后台,并添加对应的静态页面的配置:

-管理员界面创建flatpage
管理员界面创建flatpage
+管理员界面创建flatpage
管理员界面创建flatpage

然后从高级选项中填写我们的静态页面的路径,我们就可以完成静态页面的创建。如下图所示:

-flatpage高级选项
flatpage高级选项
+flatpage高级选项
flatpage高级选项

最后,还要有个链接加到首页的导航中:

<li>
@@ -1037,15 +1076,15 @@ 

评论功能

接着,将django.contrib.sitesdjango_comments添加到INSTALLED_APPS,如下:

INSTALLED_APPS = (
     'django.contrib.admin',
-    'django.contrib.auth',
-    'django.contrib.contenttypes',
-    'django.contrib.sessions',
-    'django.contrib.messages',
-    'django.contrib.staticfiles',
-    'django.contrib.sites',
-    'django_comments',
-    'rest_framework',
-    'blogpost'
+    'django.contrib.auth',
+    'django.contrib.contenttypes',
+    'django.contrib.sessions',
+    'django.contrib.messages',
+    'django.contrib.staticfiles',
+    'django.contrib.sites',
+    'django_comments',
+    'rest_framework',
+    'blogpost'
 )

然后做一下数据库迁移我们就可以完成对其的初始化:

Operations to perform:
@@ -1087,13 +1126,13 @@ 

评论功能

{% endblock %}

遗憾的是,当我们刷新页面的时候,页面报错了,原因如下所示:

-SITE_ID报错
SITE_ID报错
+SITE_ID报错
SITE_ID报错

我们还需要定义一个SITE_ID,添加下面的代码到settings.py文件中即可:

SITE_ID = 1

然后,我们就可以从后台创建评论:

-后台创建评论
后台创建评论
+后台创建评论
后台创建评论

Sitemap

我们在之前的文章中提到过SEO的重要性,这里只是简单地对Sitemap的内容进行展开。

@@ -1247,23 +1286,23 @@

提交到搜索引擎

这里我们以Google Webmaster为例简单的介绍一下如何使用各种站长工具来提交sitemap.xml。

我们可以登录Google的Webmaster:https://www.google.com/webmasters/tools/home?hl=zh-cn,然后点击添加属性来创建一个新的网站:

-添加网站
添加网站
+添加网站
添加网站

这时候Google需要确认这个网站是你的,所以它提供几种方法来验证,除了下面的推荐方法:

-推荐的验证方式
推荐的验证方式
+推荐的验证方式
推荐的验证方式

我们可以使用下面的这一些方法:

-备选的难方法
备选的难方法
+备选的难方法
备选的难方法

我个人比较喜欢用HTML Tag的方式来实现

-HTML标签验证
HTML标签验证
+HTML标签验证
HTML标签验证

在我们完成验证之后,我们就可以在后台手动提交Sitemap.xml了。

-提交Sitemap.xml
提交Sitemap.xml
+提交Sitemap.xml
提交Sitemap.xml

点击上方的添加/测试站点地图即可。

样式与UI美化

@@ -1272,7 +1311,7 @@

响应式设计

考虑到易学程度,以其响应式设计的问题,我们决定用Bootstrap来作为这里的前端框架。Bootstrap是Twitter推出的一个用于前端开发的开源工具包,似乎也是当前“最受欢迎”的前端框架。它提供了全面、美观的文档。你能在这里找到关于 HTML 元素、HTML 和 CSS 组件、jQuery 插件方面的所有详细文档。并且我们能在 Bootstrap 的帮助下通过同一份代码快速、有效适配手机、平板、PC 设备。

它是一个支持响应式设计的框架,即页面的设计与开发应当根据用户行为以及设备环境(系统平台、屏幕尺寸、屏幕定向等)进行相应的响应和调整。如下图所示:

-响应式设计
响应式设计
+响应式设计
响应式设计

我们在不同的设计上看到的是不同的布局,这会依据我们的设备大小做出调整——使用媒体查询(media queries)实现。

引入前端框架

@@ -1343,15 +1382,15 @@

添加导航

</header>

它在桌面下的效果大致如下图所示:

-桌面浏览器下的Bootstrap导航
桌面浏览器下的Bootstrap导航
+桌面浏览器下的Bootstrap导航
桌面浏览器下的Bootstrap导航

而在移动浏览器下则是这样的效果:

-移动设备上的导航
移动设备上的导航
+移动设备上的导航
移动设备上的导航

当我们点击右上角的菜单按钮时,会出现我们的菜单

-点击导航后的结果
点击导航后的结果
+点击导航后的结果
点击导航后的结果

添加标语

接着,我们可以快速的创建一个标语:

@@ -1392,10 +1431,10 @@

优化列表

{% endblock %}

它在桌面和自动设备上的效果如下图所示:

-桌面设备效果
桌面设备效果
+桌面设备效果
桌面设备效果
-移动设备效果
移动设备效果
+移动设备效果
移动设备效果

添加footer

最后,我们可以在页面的最下方添加一个footer,来做一些版权声明:

@@ -1490,31 +1529,31 @@

创建博客列表API

测试 API

现在,我们可以访问http://127.0.0.1:8000/api/来访问我们现在的API。由于Django REST Framework提供了一个UI机制,所以我们可以在网页上直接看到我们所有的API:

-Django REST Framework列表
Django REST Framework列表
+Django REST Framework列表
Django REST Framework列表

然后,点击页面中的http://127.0.0.1:8000/api/blogpost/,我们就可以访问博客相关的API了,如下图所示:

-博客API
博客API
+博客API
博客API

在页面上显示了所有的博客内容,在页面的下面有一个表单可以先让我们来创建数据:

-创建博客的表单
创建博客的表单
+创建博客的表单
创建博客的表单

直接在表单中添加数据,我们就可以完成数据创建了。

当然,我们也可以直接用命令行工具来测试,执行:

-
curl -i  http://127.0.0.1:8000/api/blogpost/
+
curl -i  http://127.0.0.1:8000/api/blogpost/

即可返回相应的结果:

-CuRL API
CuRL API
+CuRL API
CuRL API

自动完成

AutoComplete是一个很有意思的功能,特别是当我们的文章很多的时候,我们可以让读者有机会能搜索到相应的功能。以Google为例,Google在我们输入一些关键字的时候,会向我们推荐一些比较流行的词条可以让我们选择。

-Google AutoComplete
Google AutoComplete
+Google AutoComplete
Google AutoComplete

同样的,我们也可以实现一个同样的效果用于我们的博客搜索:

-自动完成
自动完成
+自动完成
自动完成

当我们输入某一些关键字的时候,就会出现文章的标题,随后我们只需要点击相应的标题即可跳转到文章。

搜索API

@@ -1528,7 +1567,7 @@

搜索API

queryset = Blogpost.objects.all() search_param =self.request.query_params.get('title', None) - if search_param isnotNone: + if search_param isnotNone: queryset = Blogpost.objects.filter(title__contains=search_param) serializer = BlogpsotSerializer(queryset, many=True) @@ -1607,7 +1646,7 @@

跨域支持

当我们想为其他的网页提供我们的API时,可能会报错——原因是不支持跨域请求。为了方便我们下一章更好的展开,内容我们在这里对跨域进行支持。

添加跨域支持

有一个名为django-cors-headers的插件用于实现对跨域请求的支持,我们只需要安装它,并进行一些简单的配置即可。

-
pip install django-cors-headers
+
pip install django-cors-headers

安装过程如下:

Collecting django-cors-headers
   Downloading django-cors-headers-1.1.0.tar.gz
@@ -1637,7 +1676,7 @@ 

创建移动应用

依照国际惯例,我们还将用Ionic 2继续创建hello,world。

hello,world

开始之前我们需要先安装Ionic的命令行工具,后面我们需要用这个工具来创建工程。

-
npm install -g ionic@beta
+
npm install -g ionic@beta

如果没有意外,我们将安装成功,然后可以使用ionic命令:

它自带了一系列的工具来加速我们的开发,这些工具可以在后面的章节中学习到。

Available tasks: (use --help or -h for more info)
@@ -1678,7 +1717,7 @@ 

hello,world

docs ........... Opens up the documentation for Ionic generate ....... Generate pages and components

现在,我们就可以用第一个命令start来创建我们的项目。

-
ionic start growth-blog-app --v2
+
ionic start growth-blog-app --v2

在这个过程中,它将下载Ionic 2项目的基础项目,并执行安装命令。

Creating Ionic app in folder /Users/fdhuang/repractise/growth-blog-app based on tabs project
 Downloading: https://github.com/driftyco/ionic2-app-base/archive/master.zip
@@ -1737,7 +1776,7 @@ 

hello,world

ionic start growth-blog-app --v2 --ts

--ts表示使用的是typescript来创建项目,安装的过程是一样的,不一样的是后面写的代码。

执行相应的启动serve命令,我们就可以开始我们的项目了:

-
ionic serve
+
ionic serve

这时候Ionic将做一些额外的事,才能启动我们的服务,如:

  • 删除www/build目录下的文件
  • @@ -1747,42 +1786,42 @@

    hello,world

  • 等等

最后,它将启动一个Web服务,URL为http://localhost:8100

-
  Running 'serve:before' gulp task before serve
-  [20:59:16] Starting 'clean'...
-  [20:59:16] Finished 'clean' after 6.07 ms
-  [20:59:16] Starting 'watch'...
-  [20:59:16] Starting 'sass'...
-  [20:59:16] Starting 'html'...
-  [20:59:16] Starting 'fonts'...
-  [20:59:16] Starting 'scripts'...
-  [20:59:16] Finished 'scripts' after 43 ms
-  [20:59:16] Finished 'html' after 51 ms
-  [20:59:16] Finished 'fonts' after 54 ms
-  [20:59:16] Finished 'sass' after 738 ms
-  7.6 MB bytes written (5.62 seconds)
-  [20:59:22] Finished 'watch' after 6.62 s
-  [20:59:22] Starting 'serve:before'...
-  [20:59:22] Finished 'serve:before' after 3.87 μs
-
-  Running live reload server: http://localhost:35729
-  Watching: www/**/*, !www/lib/**/*
-  √ Running dev server:  http://localhost:8100
-  Ionic server commands, enter:
-    restart or r to restart the client app from the root
-    goto or g and a url to have the app navigate to the given url
-    consolelogs or c to enable/disable console log output
-    serverlogs or s to enable/disable server log output
-    quit or q to shutdown the server and exit
-  ionic $
+
  Running 'serve:before' gulp task before serve
+  [20:59:16] Starting 'clean'...
+  [20:59:16] Finished 'clean' after 6.07 ms
+  [20:59:16] Starting 'watch'...
+  [20:59:16] Starting 'sass'...
+  [20:59:16] Starting 'html'...
+  [20:59:16] Starting 'fonts'...
+  [20:59:16] Starting 'scripts'...
+  [20:59:16] Finished 'scripts' after 43 ms
+  [20:59:16] Finished 'html' after 51 ms
+  [20:59:16] Finished 'fonts' after 54 ms
+  [20:59:16] Finished 'sass' after 738 ms
+  7.6 MB bytes written (5.62 seconds)
+  [20:59:22] Finished 'watch' after 6.62 s
+  [20:59:22] Starting 'serve:before'...
+  [20:59:22] Finished 'serve:before' after 3.87 μs
+
+  Running live reload server: http://localhost:35729
+  Watching: www/**/*, !www/lib/**/*
+  √ Running dev server:  http://localhost:8100
+  Ionic server commands, enter:
+    restart or r to restart the client app from the root
+    goto or g and a url to have the app navigate to the given url
+    consolelogs or c to enable/disable console log output
+    serverlogs or s to enable/disable server log output
+    quit or q to shutdown the server and exit
+  ionic $

接着,就可以打开相应的Web页面,如下图所示:

-Ionic Web预览界面
Ionic Web预览界面
+Ionic Web预览界面
Ionic Web预览界面

构建应用

由于Ionic是基于Cordova的,我们需要安装Cordova业完成后续的工作。

-
sudo npm install -g cordova
+
sudo npm install -g cordova

为了构建不同的平台的应用,我们就需要添加不同的平台,如:

-
ionic platform add android
+
ionic platform add android

上面的命令可以为项目添加Android平台的支持,过程如下面的日志所示:

Adding android project...
 Creating Cordova project for the Android platform:
@@ -1904,12 +1943,12 @@ 

详情页

  • 点击某一项时,将跳转到详情页,并去获取相应的API的数据,并渲染到页面上。
  • 好了,我们可以用ionic的生成命令来创建博客详情页。

    -
    ionic g page blog-detail --ts
    +
    ionic g page blog-detail --ts

    它将在app/pages目录下,生成下面的内容:

    -
    app/pages/blog-detail/
    -├── blog-detail.html
    -├── blog-detail.ts
    -└── blog-detail.scss
    +
    app/pages/blog-detail/
    +├── blog-detail.html
    +├── blog-detail.ts
    +└── blog-detail.scss

    我们可以遵循之前添加Django App的习惯,先添加Router。因此我们可以在app.ts添加新的Route:

    const ROUTES = [
       {path: '/app/blog/:id', component: BlogDetailPage}
    @@ -1977,7 +2016,7 @@ 

    详情页

    }

    现在我们几乎已经完成了博客详情页的工作,我们可以直接通过URL来访问博客详情页:http://localhost:8100/#/app/blog/1。结果如下图所示:

    -访问博客详情页
    访问博客详情页
    +访问博客详情页
    访问博客详情页

    不过,这时候我们的列表页并没有和详情页关联到一起。我们还需要做一些额外的工作:

      @@ -2114,7 +2153,7 @@

      获取用户信息

      只是我们的API似乎还不支持这样的功能。它的实现方式和我们之前的AutoComplete是一样的,也是搜索用户名:

      def list(self, request):
           search_param = self.request.query_params.get('username', None)
      -    if search_param is not None:
      +    if search_param is not None:
               queryset = User.objects.filter(username__contains=search_param)
       
           serializer = UserSerializer(queryset, many=True)
      @@ -2138,8 +2177,8 @@ 

      创建博客

      """ def has_permission(self, request, view): - if (request.method in SAFE_METHODS or - request.user and + if (request.method in SAFE_METHODS or + request.user and request.user.is_authenticated()): return True return False @@ -2338,8 +2377,8 @@

      创建博客列表页

      this.unmount(); riot.route("blogDetail/" + event.item.id); } - </script> -</blog>
      + </script> +</blog>

    在Riot中,变量默认是以opts的方式传递起来的,因此我们也遵循这个方式。在模板方面,我们遍历每个博客取出其中的内容:

    <div class="col-sm-4" each={ opts }>
         <h2><a href="#/blogDetail/{id}" onclick={ parent.click }>{ title }</a></h2>
    @@ -2431,10 +2470,10 @@ 

    local settings

    作为一个开源项目,我们在这方面做得并不是特别好——当然是有意如此的。不过,这里我们还是做一些简单的介绍。对于我们的项目来说,我们需要一些额外的配置,如我们的数据库中的DATABASESDEFAULT_AUTHENTICATION_CLASSESCORS_ORIGIN_ALLOW_ALLSECRET_KEY应该在不同的环境中都有不同的配置。

    我们可以一个创建local_settings.py,在里面放置一些关键的服务器相关的配置,如:

    
    -# SECURITY WARNING: keep the secret key used in production secret!
    +# SECURITY WARNING: keep the secret key used in production secret!
     SECRET_KEY = 'hpi!zb8!(j%40)r55@+_5k*^9qcjf9sx0o_it*jlp3=x9^2ak@'
     
    -# SECURITY WARNING: don't run with debug turned on in production!
    +# SECURITY WARNING: don't run with debug turned on in production!
     DEBUG = True
     
     TEMPLATE_DEBUG = True
    @@ -2445,7 +2484,7 @@ 

    local settings

    DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': 'db.sqlite3', + 'NAME': 'db.sqlite3', } } @@ -2453,10 +2492,10 @@

    local settings

    'DEFAULT_PERMISSION_CLASSES': ( ), - 'DEFAULT_AUTHENTICATION_CLASSES': ( + 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework.authentication.SessionAuthentication', - 'rest_framework.authentication.BasicAuthentication', - 'rest_framework_jwt.authentication.JSONWebTokenAuthentication', + 'rest_framework.authentication.BasicAuthentication', + 'rest_framework_jwt.authentication.JSONWebTokenAuthentication', ), }