部署
最后更新于:2022-04-01 19:56:13
## 配置管理
local_settings.py
## Fabric
* NGINX - public facing web server
* gunicorn - internal HTTP application server
* PostgreSQL - database server
* memcached - in-memory caching server
* supervisord - process control and monitor
* virtualenv - isolated Python environments for each project
* git or mercurial - version control systems (optional)
';
前端重构
最后更新于:2022-04-01 19:56:11
## MVVM
## UX
';
移动应用
最后更新于:2022-04-01 19:56:08
依靠习惯我们还将用Ionic 2继续创建hello,world。
## hello,world
开始之前我们需要先安装Ionic的命令行工具,后来我们需要用这个工具来创建工程。
~~~
npm install -g ionic@beta
~~~
如果没有意外,我们将安装成功,然后可以使用`ionic`命令:
它自带了一系列的工具来加速我们的开发,这些工具可以在后面的章节中学习到。
~~~
Available tasks: (use --help or -h for more info)
start .......... Starts a new Ionic project in the specified PATH
serve .......... Start a local development server for app dev/testing
platform ....... Add platform target for building an Ionic app
run ............ Run an Ionic project on a connected device
emulate ........ Emulate an Ionic project on a simulator or emulator
build .......... Build (prepare + compile) an Ionic project for a given platform.
plugin ......... Add a Cordova plugin
resources ...... Automatically create icon and splash screen resources (beta)
Put your images in the ./resources directory, named splash or icon.
Accepted file types are .png, .ai, and .psd.
Icons should be 192x192 px without rounded corners.
Splashscreens should be 2208x2208 px, with the image centered in the middle.
upload ......... Upload an app to your Ionic account
share .......... Share an app with a client, co-worker, friend, or customer
lib ............ Gets Ionic library version or updates the Ionic library
setup .......... Configure the project with a build tool (beta)
io ............. Integrate your app with the ionic.io platform services (alpha)
security ....... Store your app's credentials for the Ionic Platform (alpha)
push ........... Upload APNS and GCM credentials to Ionic Push (alpha)
package ........ Use Ionic Package to build your app (alpha)
config ......... Set configuration variables for your ionic app (alpha)
browser ........ Add another browser for a platform (beta)
service ........ Add an Ionic service package and install any required plugins
add ............ Add an Ion, bower component, or addon to the project
remove ......... Remove an Ion, bower component, or addon from the project
list ........... List Ions, bower components, or addons in the project
info ........... List information about the users runtime environment
help ........... Provides help for a certain command
link ........... Sets your Ionic App ID for your project
hooks .......... Manage your Ionic Cordova hooks
state .......... Saves or restores state of your Ionic Application using the package.json file
docs ........... Opens up the documentation for Ionic
generate ....... Generate pages and components
~~~
现在,我们就可以用第一个命令`start`来创建我们的项目。
~~~
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
[=============================] 100% 0.0s
Downloading: https://github.com/driftyco/ionic2-starter-tabs/archive/master.zip
[=============================] 100% 0.0s
Installing npm packages...
~~~
然后到`growth-blog-app`目录,我们会看到类似于下面的内容:
~~~
.
├── README.md
├── app
│ ├── app.js
│ ├── pages
│ │ ├── page1
│ │ │ ├── page1.html
│ │ │ ├── page1.js
│ │ │ └── page1.scss
│ │ ├── page2
│ │ │ ├── page2.html
│ │ │ ├── page2.js
│ │ │ └── page2.scss
│ │ ├── page3
│ │ │ ├── page3.html
│ │ │ ├── page3.js
│ │ │ └── page3.scss
│ │ └── tabs
│ │ ├── tabs.html
│ │ └── tabs.js
│ └── theme
│ ├── app.core.scss
│ ├── app.ios.scss
│ ├── app.md.scss
│ ├── app.variables.scss
│ └── app.wp.scss
├── config.xml
├── gulpfile.js
├── hooks
│ ├── README.md
│ └── after_prepare
│ └── 010_add_platform_class.js
├── ionic.config.json
├── package.json
└── www
└── index.html
~~~
在这2.0版本的Ionic,页面开始以目录来划分,一个页面路径下有自己的`html`、`js`、`scss`。
* `tabs`负责这些页面间跳转
* `theme`则负责系统相应样式的修改
* `config.xml`带有相应的Cordova配置
* `hooks`则对系统添加和编译时进行一些预处理
* `ionic.config.json`则是ionic的一些相关配置选项
* `package.json`则存放相应的node.js的包的依赖
* `www`目录用于存放出最后构建出来的内容,以及一些静态资源
由于Angular 2.0使用的是Typescript,所以在这里我们将用typescript进行展示,因此我们的执行命令变成~~:
~~~
ionic start growth-blog-app --v2 --ts
~~~
`--ts`表示使用的是`typescript`来创建项目,安装的过程是一样的,不一样的是后面写的代码。
执行相应的起serve命令,我们就可以开始我们的项目了:
~~~
ionic serve
~~~
这时候Ionic将做一些额外的事,才能启动我们的服务,如:
* 删除`www/build`目录下的文件
* 编译SASS到CSS
* 编译文件到HTML
* 编译字体
* 等等
最后,它将启动一个Web服务,URL为[http://localhost:8100](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 $
~~~
接着,就可以打开相应的Web页面,如下图所示:
![Ionic Web预览界面](http://growth-in-action.phodal.com/images/ionic-web-view.jpg)
Ionic Web预览界面
### 构建应用
由于Ionic是基于Cordova的,我们需要安装Cordova业完成后续的工作。
~~~
sudo npm install -g cordova
~~~
为了构建不同的平台的应用,我们就需要添加不同的平台,如:
~~~
ionic platform add android
~~~
上面的命令可以为项目添加Android平台的支持,过程如下面的日志所示:
~~~
Adding android project...
Creating Cordova project for the Android platform:
Path: platforms/android
Package: io.ionic.starter
Name: V2_Test
Activity: MainActivity
Android target: android-23
Android project created with cordova-android@5.1.1
Running command: /Users/fdhuang/repractise/growth-blog-app/hooks/after_prepare/010_add_platform_class.js /Users/fdhuang/repractise/growth-blog-app
~~~
最近,再执行`run`就可以在对应的平台上运行,如:
~~~
ionic run android
~~~
## 博客列表页
现在,让我们来结合我们的博客APP,做一个相应的展示博客的APP。
### 列表页
在上一个章节里我们已经有了一个博客详细的API,我们只需要获取这个API并显示即可。不过,让我们简单地熟悉一下显示数据的这部分内容:
~~~
博客
~~~
上面是一个基本的详情页的模板,其中定义了一系列的Ionic自定义标签,如:
* 显示在导航栏中的内容
* 显示APP的内容
* 即将博客成每一项
而从上面的内容中,我们可以看到:我们在ngFor中遍历了blogposts,然后显示每篇文章的标题和内容。对应的代码也就比较简单了:
~~~
import {Page} from 'ionic-angular';
@Page({
templateUrl: 'build/pages/blog/list/index.html',
providers: [BlogpostServices]
})
export class BlogList {
public blogposts;
constructor() {
}
}
~~~
但是我们要去哪里获取博客的值呢,先我们我们看完改造后听BlogList的Controller:
~~~
import {Page} from 'ionic-angular';
import {BlogpostServices} from '../../../services/BlogpostServices';
@Page({
templateUrl: 'build/pages/blog/list/index.html',
providers: [BlogpostServices]
})
export class BlogList {
private blogListService;
public blogposts;
constructor(blogpostServices:BlogpostServices) {
this.blogListService = blogpostServices;
this.initService();
}
private initService() {
this.blogListService.getBlogpostLists().subscribe(
data => {this.blogposts = JSON.parse(data._body);},
err => console.log('Error: ' + JSON.stringify(err)),
() => console.log('Get Blogpost')
);
}
}
~~~
我们初始化了一个blogListService,然后我们调用这个服务去获取博客列表。
~~~
this.blogListService.getBlogpostLists().subscribe(
data => {this.blogposts = JSON.parse(data._body);},
err => console.log('Error: ' + JSON.stringify(err)),
() => console.log('Get Blogpost')
);
~~~
当我们获取到数据的时候,我们就解析这个数据,并将这个值赋予blogposts。如果这其中遇到什么错误,就会显示相应的错误信息。
现在,让我们创建一个获取博客的服务:
~~~
import {Inject} from 'angular2/core';
import {Http} from 'angular2/http';
import 'rxjs/add/operator/map';
export class BlogpostServices {
private http;
constructor(@Inject(Http) http:Http) {
this.http = http
}
getBlogpostLists() {
var url = 'http://127.0.0.1:8000/api/blogpost/?format=json';
return this.http.get(url).map(res => res);
}
}
~~~
### 详情页
~~~
ionic g page blog-detail --ts
~~~
~~~
app/pages/blog-detail/
├── blog-detail.html
├── blog-detail.ts
└── blog-detail.scss
~~~
修改`app.ts`添加Route:
~~~
const ROUTES = [
{path: '/app/blog/:id', component: BlogDetailPage}
];
@App({
template: ' ',
config: {}
})
@RouteConfig(ROUTES)
export class MyApp {
rootPage:any = TabsPage;
constructor(platform:Platform) {
this.rootPage = TabsPage;
this.initializeApp(platform)
}
private initializeApp(platform:Platform) {
platform.ready().then(() => {
StatusBar.styleDefault();
});
}
}
~~~
添加服务
~~~
getBlogpostDetail(id) {
var url = 'http://localhost:8000/api/blogpost/' + id + '?format=json';
return this.http.get(url).map(res => res);
}
~~~
添加Controller
~~~
import {Page, NavController, NavParams} from 'ionic-angular';
import {BlogpostServices} from "../../services/BlogpostServices";
@Page({
templateUrl: 'build/pages/blog-detail/blog-detail.html',
providers: [BlogpostServices]
})
export class BlogDetailPage {
private navParams;
private blogServices;
private blogpost;
constructor(public nav:NavController, navParams:NavParams, blogServices:BlogpostServices) {
this.nav = nav;
this.navParams = navParams;
this.blogServices = blogServices;
this.initService();
}
private initService() {
let id = this.navParams.get('id');
this.blogServices.getBlogpostDetail(id).subscribe(
data => {
this.blogpost = JSON.parse(data._body);
console.log(this.blogpost);
},
err => console.log('Error: ' + JSON.stringify(err)),
() => console.log('Get Blogpost')
);
}
}
~~~
## Profile
### Json Web Tokens
~~~
pip install djangorestframework-jwt
~~~
~~~
urlpatterns = patterns(
'',
# ...
url(r'^api-token-auth/', 'rest_framework_jwt.views.obtain_jwt_token'),
)
~~~
~~~
constructor(http: Http, nav:NavController) {
this.nav = nav;
this.http = http;
this.local.get('id_token').then(
(data) => {
this.user = this.jwtHelper.decodeToken(data).username;
}
);
}
login(credentials) {
this.contentHeader = new Headers({"Content-Type": "application/json"});
this.http.post(this.LOGIN_URL, JSON.stringify(credentials), {headers: this.contentHeader})
.map(res => res.json())
.subscribe(
data => this.authSuccess(data.token),
err => console.log(err)
);
}
authSuccess(token) {
this.local.set('id_token', token);
this.user = this.jwtHelper.decodeToken(token).username;
}
~~~
~~~
logout() {
this.local.remove('id_token');
this.user = null;
}
~~~
Install Angular JWT
~~~
npm install angular2-jwt
~~~
### Profile
~~~
def list(self, request):
search_param = self.request.query_params.get('username', None)
if search_param is not None:
queryset = User.objects.filter(username__contains=search_param)
serializer = UserSerializer(queryset, many=True)
return Response(serializer.data)
~~~
## 创建博客
权限管理
~~~
SAFE_METHODS = ['GET', 'HEAD', 'OPTIONS']
class IsAuthenticatedOrReadOnly(BasePermission):
"""
The request is authenticated as a user, or is a read-only request.
"""
def has_permission(self, request, view):
if (request.method in SAFE_METHODS or
request.user and
request.user.is_authenticated()):
return True
return False
class BlogpsotSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Blogpost
fields = ('title', 'author', 'body', 'slug', 'id')
# ViewSets define the view behavior.
class BlogpostSet(viewsets.ModelViewSet):
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
queryset = Blogpost.objects.all()
serializer_class = BlogpsotSerializer
~~~
## TODO
';
{{blogpost.title}}
{{blogpost.body}}
API
最后更新于:2022-04-01 19:56:06
## 自动完成
AutoComplete是一个很有意思的功能,特别是当我们的文章很多的时候,我们可以让读者有机会能搜索到相应的功能。
## RESTful
### Django REST Framework
> Django REST Framework 这个名字很直白,就是基于 Django 的 REST 框架。
~~~
pip install djangorestframework
pip install markdown # Markdown support for the browsable API.
pip install django-filter # Filtering support
~~~
~~~
INSTALLED_APPS = (
...
'rest_framework',
)
~~~
如下所示:
~~~
INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'blogpost'
)
~~~
~~~
urlpatterns = [
...
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
]
~~~
## 跨域
### CORS
### 添加跨域支持
~~~
pip install django-cors-headers
~~~
~~~
Collecting django-cors-headers
Downloading django-cors-headers-1.1.0.tar.gz
Building wheels for collected packages: django-cors-headers
Running setup.py bdist_wheel for django-cors-headers ... done
Stored in directory: /Users/fdhuang/Library/Caches/pip/wheels/b0/75/89/7b17f134fc01b74e10523f3128e45b917da0c5f8638213e073
Successfully built django-cors-headers
Installing collected packages: django-cors-headers
Successfully installed django-cors-headers-1.1.0
~~~
添加到`django-cors-headers=1.1.0`到`requirements.txt`文件中。
添加到`settings.py`中:
~~~
INSTALLED_APPS = (
...
'corsheaders',
...
)
~~~
以及对应的中间件:
~~~
MIDDLEWARE_CLASSES = (
...
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
...
)
~~~
对应的配置:
~~~
CORS_ALLOW_CREDENTIALS = True
~~~
';
前端框架
最后更新于:2022-04-01 19:56:04
我们的前端样式实在是太丑了,让我们想办法来美化一下它们吧——这时候我们就需要一个前端框架来帮助我们做这件事。这里的前端框架并不是指那种MV*框架,而是UI框架。
## 响应式设计
考虑到易学程度,以其响应式设计的问题,我们决定用Bootstrap来作为这里的前端框架。Bootstrap是Twitter推出的一个用于前端开发的开源工具包,似乎也是当前“最受欢迎”的前端框架。它提供了全面、美观的文档。你能在这里找到关于 HTML 元素、HTML 和 CSS 组件、jQuery 插件方面的所有详细文档。并且我们能在 Bootstrap 的帮助下通过同一份代码快速、有效适配手机、平板、PC 设备。
它是一个支持响应式设计的框架,即页面的设计与开发应当根据用户行为以及设备环境(系统平台、屏幕尺寸、屏幕定向等)进行相应的响应和调整。如下图所示:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-18_573be52a190e7.png)
响应式设计
我们在不同的设计上看到的是不是同的布局,这会依据我们的设备大小做出调整——使用媒体查询(media queries)实现。
### 引入前端框架
下好Bootstrap,将里面的内容复制到`static/`目录,如下所示:
~~~
.
├── css
│ ├── bootstrap-theme.css
│ ├── bootstrap-theme.css.map
│ ├── bootstrap-theme.min.css
│ ├── bootstrap-theme.min.css.map
│ ├── bootstrap.css
│ ├── bootstrap.css.map
│ ├── bootstrap.min.css
│ ├── bootstrap.min.css.map
│ └── styles.css
├── fonts
│ ├── glyphicons-halflings-regular.eot
│ ├── glyphicons-halflings-regular.svg
│ ├── glyphicons-halflings-regular.ttf
│ ├── glyphicons-halflings-regular.woff
│ └── glyphicons-halflings-regular.woff2
└── js
├── bootstrap.js
├── bootstrap.min.js
└── npm.js
~~~
它包含了JavaScript、CSS还有字体,需要注意的一点是bootstrap依赖于jquery。因此,我们需要下载jquery并放到这个目录里。然后在我们的head里引入这些css
~~~
{% block head_title %}Welcome to my blog{% endblock %}
~~~
在我们的body结尾的地方:
~~~