天使汇开发指南¶
作者: 王然 kxxoling@gmail.com
如何编译 reST 文档¶
reST 文档的编译依赖 make 和 sphinx,安装完依赖后在文档的根目录执行
make html
构建 HTML 文档,如无错误即可在 _build/html
目录中生成对应的 HTML 文件,
可以在浏览器中直接打开 _build/html/index.html
预览生成的 HTML。
本文档托管在 ReadTheDocs,文档合并之主分支后将会自动构建,预览请访问 RTFD 。
程序部 : 新人/兼职入职流程¶
账号准备等¶
- 使用公司邮箱(如没有请联系 HR)注册 Slack ,并 修改备注名为真实姓名 。
- 注册 Slack 并加入 PE.VC 团队,推荐使用公司邮箱注册,可直接加入 Team。其它邮箱需要联系我来邀请。
- 注册 BitBucket 账号
- 加入 PE.VC 以及程序部QQ群:11757089(公司)239812971(程序部)
- 注册 tower.im 账号,并申请加入 PE.VC 程序部
- 申请 程序部共享文件夹 共享权限
- 申请加入 程序部 GoogleGroups
根据本文档配置开发环境以及熟悉常用开发工具¶
有不清楚的地方及时向我反馈。
常用账号及密码¶
常用账号及密码都公开在 Google Docs 上, 如无法访问请申请权限。
天使汇 API¶
手机 API (version 2)¶
作者: tonghs tonghuashuai@gmail.com
注册登录¶
获取图片验证码¶
http://mobile.tonghs.me/v2/home/img_verify_code
method:
GET
params:
无
return:
{
key: 验证码 key
img: 验证码图片 base64
}
发送手机验证码¶
http://mobile.tonghs.me/v2/home/verify_code
params:
phone: 手机号码
key: 图片验证码 key
token: 图片验证码
return:
{
message: 返回信息
success: 是否成功 true/false
time: 剩余时间
}
注册¶
http://mobile.tonghs.me/v2/home/register
params:
phone: 手机号码
code: 验证码
name: 姓名
password: 密码
password_: 确认密码
key: 图片验证码 key
return:
{
message: 返回信息
success: true/false
}
登录¶
http://mobile.tonghs.me/v2/home/login
params:
account: 邮箱或手机号码
password: 密码
return:
登录失败时
{
message: 返回信息
success: true/false
}
登录成功时
{
user: {
id: 用户ID
name: 姓名
avatar_big: 头像
avatar_small: 小头像
access_token:
summary: 简介
firmname: 公司名
title: 职位
phone: 电话
qq:
weixin:
email:
defaultpart: 参与身份1: 投资人 2: 领投人
regionid: 省份ID
regionname: 省份名
cityid: 城市ID
cityname: 城市名
}
}
用户¶
投资人列表¶
http://mobile.tonghs.me/v2/user
params:
*pagesize: 每页条数, 默认为 10
*pageindex: 当前页数, 默认为 1
uid: 用户 ID
access_token:
*industry: 行业(筛选用)
*region: 区域(筛选用)
return:
{
industry: 行业
regionid: 区域
total: 总条数
list: [{
id:
name: 姓名
firmname: 公司
title: 职位
followercount: 粉丝数
industry: 行业
region_name: 地区
isfollow: 是否关注
summary: 简介
part: 身份 0: 创业者 1: 投资人 2: 领投人
avatar: 头像
meetingtimes: 约谈数
view_count: 0 查看次数,主站无该数据
}]
}
投资人列表搜索¶
http://mobile.tonghs.me/v2/user_search
params:
*pagesize: 每页条数, 默认为 10
*pageindex: 当前页数, 默认为 1
uid: 用户 ID
access_token:
keyword: 关键字
return:
{
pagesize: 每页条数
pageindex: 当前页数
total: 总条数
list: [{
id:
name: 姓名
firmname: 公司
title: 职位
followercount: 粉丝数
industry: 行业
region_name: 地区
isfollow: 是否关注
summary: 简介
part: 身份 0: 创业者 1: 投资人 2: 领投人
avatar: 头像
meetingtimes: 约谈数
view_count: 0 查看次数,主站无该数据
}]
}
投资人详情¶
http://mobile.tonghs.me/v2/user/detail
params:
uid: 用户 ID
access_token:
user_id: 要查看的用户的ID
return:
{
user: {
id: ID
name: 姓名
avatar: 头像
part: 0: 创业者 1: 投资人
summary: 简介
style: 投资理念
business: 擅长领域
service: 提供服务
isfollow: 是否关注
following_count: 关注人数
following_list:
[{
id:
name: 姓名
title: 职位
avatar: 头像
industry: 行业
isfollow: 是否关注
summary: 简介
part: 身份 0: 创业者 1: 投资人 2: 领投人
}]
follower_count: 粉丝人数
follower_list:
[{
id:
name: 姓名
title: 职位
avatar: 头像
industry: 行业
isfollow: 是否关注
summary: 简介
part: 身份 0: 创业者 1: 投资人 2: 领投人
}]
invested_com: 参与过的项目
[{
id: 公司 ID
name: 项目名
logo: 公司 logo
concept: 一句话介绍
viewercount: 查看次数
isfans: 是否是粉丝
creatorid: 创建人id
industry: 行业
region: 区域
shareurl: 微信分享链接
meetingcount: 约谈次数
day: 剩余天数
amount: 融资金额
fanscount: 粉丝数
finishamount: 完成融资数
part: 参与身份1: 投资人 2: 领投人
}]
comment_list: 评论列表
[{
user_id: 用户ID
name:
avatar: 头像
title: 职位
content: 评论内容
time: 时间(时间戳,目前未取到)
}]
bbs_list: bbs 列表
[{
title: 标题
url: 连接
time: 时间(时间戳)
}]
}
}
提交项目¶
http://mobile.tonghs.me/v2/user/submit_com
params:
uid: 用户ID
access_token:
com_id: 项目ID
target_id: 要提交给的投资人的ID
return:
{
message: 错误信息
success: true/false
}
创业者详情¶
http://mobile.tonghs.me/v2/user/detail
params:
uid: 用户 ID
access_token:
user_id: 要查看的用户的ID
return:
{
user: {
id: ID
name: 姓名
avatar: 头像
summary: 简介
skill: 技能
part: 0: 创业者 1: 投资人
isfollow: 是否关注
my_com: 参与过的项目
[{
id: 项目ID
name:
logo:
state: 项目状态
concept: 项目简介
viewercount: 查看次数
isfans: 是否是粉丝
industry: 行业
region: 区域
shareurl: 微信分享链接
meetingcount: 约谈次数
day: 剩余天数
amount: 融资金额
fanscount: 粉丝数
finishamount: 完成融资数
}]
following_count: 关注人数
following_list:
[{
id:
name: 姓名
title: 职位
avatar: 头像
industry: 行业
isfollow: 是否关注
summary: 简介
part: 身份 0: 创业者 1: 投资人 2: 领投人
}]
follower_count: 粉丝人数
follower_list:
[{
id:
name: 姓名
title: 职位
avatar: 头像
industry: 行业
isfollow: 是否关注
summary: 简介
part: 身份 0: 创业者 1: 投资人 2: 领投人
}]
career: 工作经历
[{
start: 开始时间
end: 结束时间
company: 公司名称
title: 职位
txt: 介绍
}]
edu:
[{
start: 0,
major: 专业
school: 学校
degress: 学位
}]
}
}
项目相关¶
项目列表¶
http://mobile.tonghs.me/v2/startup
params:
client_id:
*pagesize: 每页条数, 默认为 10
*pageindex: 当前页数, 默认为 1
uid: 用户 ID
access_token:
*state: 项目所处状态 全部 0 /上线 1 /预热 2(筛选用)
*industryid: 行业(筛选用)
*regionid: 区域(筛选用)
type: 请求类型
0: 项目列表
1: 我收到的项目
2: 我关注的项目
3: 我创建的项目
return:
{
pageindex: 当前页数, 默认为 1
industryid: 行业
total: 总条数
regionid: 区域
list: [{
viewercount: 查看次数
concept: 一句话介绍
viewapply: 是否申请查看 1/0
name: 项目名
coinveststatus: 合投状态
10: '申请未通过',
20: '创建中',
21: '未申请合投',
30: '申请合投中',
40: '合投预热',
50: '合投待上线',
60: '合投上线',
70: '确认投资人名单',
80: '融资完成',
90: '融资失败',
isfans: 是否是粉丝
industry: 行业
region: 区域
member_count: 成员数
shareurl: 微信分享链接
meetingcount: 约谈次数
day: 剩余天数
creatorname: 创建者姓名
amount: 融资金额
canview: 是否可以查看
creatorid: 创建者 ID
financingid: 融资 ID (目前没用)
creatorphone: 创建者手机
logo: 公司 logo
id: 公司 ID
fanscount: 粉丝数
finishamount: 完成融资数
}]
}
项目列表搜索¶
http://mobile.tonghs.me/v2/startup_search
params:
client_id:
*pagesize: 每页条数, 默认为 10
*pageindex: 当前页数, 默认为 1
uid: 用户 ID
access_token:
*keyword: 关键字
return:
{
pagesize: 每页条数
pageindex: 当前页数
total: 总条数
list: [{
viewercount: 查看次数
concept: 一句话介绍
viewapply: 是否申请查看 1/0
name: 项目名
coinveststatus: 合投状态
10: '申请未通过',
20: '创建中',
21: '未申请合投',
30: '申请合投中',
40: '合投预热',
50: '合投待上线',
60: '合投上线',
70: '确认投资人名单',
80: '融资完成',
90: '融资失败',
isfans: 是否是粉丝
industry: 行业
region: 区域
member_count: 成员数
shareurl: 微信分享链接
meetingcount: 约谈次数
day: 剩余天数
creatorname: 创建者姓名
amount: 融资金额
canview: 是否可以查看
creatorid: 创建者 ID
financingid: 融资 ID (目前没用)
creatorphone: 创建者手机
logo: 公司 logo
id: 公司 ID
fanscount: 粉丝数
finishamount: 完成融资数
}]
}
项目详情页¶
http://mobile.tonghs.me/v2/startup/detail
params:
uid: 用户 ID
access_token:
com_id: 要查看的项目ID
return:
{
id: 项目ID
name: "运策网"
url: 官方网站
creatorid: 创始人ID
logo:
summary: 简介
demourl: 试用地址
android: android 下载地址
demouser: 试用用户
demopwd: 试用密码
weibo: 微博
weixin: 微信
ios: iOS 下载地址
growthdata: 成长数据
[{
occurtime: 时间
name: 数据名称
quantity: 数量
}]
tutor: 导师
[{
id:
name: 姓名
title: 职位
avatar: 头像
industry: 行业
isfollow: 是否关注
summary: 简介
part: 身份 0: 创业者 1: 投资人 2: 领投人
}]
milestone: 大事记
[{
content: 内容
occurdate: 时间
}]
news: 新闻
[{
title: 标题
content: 内容
url: 连接
from: 来源
occurdate: 时间
}]
pics: 图片信息列表
[{
small: 小图片(320px)
big: 大图片(640px)
}]
incubator: 孵化器
[{
id:
name:
avatar: 头像
summary: 简介
region: 区域
start_date: 开始时间
end_date: 结束时间
}]
team: 团队
[{
id:
name: 姓名
title: 职位
avatar: 头像
industry: 行业
isfollow: 是否关注
summary: 简介
part: 身份 0: 创业者 1: 投资人 2: 领投人
}]
}
项目融资信息¶
http://mobile.tonghs.me/v2/startup/finance
params:
uid: 用户 ID
access_token:
com_id: 项目ID
return:
{
stock_sale: 出让股权比例
min_quota: 最小融资额度
hope_amounta: 预计融资
price: 融资前估值
finace_history: 过往融资
txt: 除资金以外的其他需求
[{
time: 时间(时间戳)
content: 内容?(带确定,目前该字段内容为融资金额)
}]
vc_list: 本轮投资意向列表
[{
id:
name: 姓名
title: 职位
avatar: 头像
industry: 行业
isfollow: 是否关注
summary: 简介
part: 身份 0: 创业者 1: 投资人 2: 领投人
}]
pre_vc_list: 上一轮投资意向列表
[{
id:
name: 姓名
title: 职位
avatar: 头像
industry: 行业
isfollow: 是否关注
summary: 简介
part: 身份 0: 创业者 1: 投资人 2: 领投人
}]
purpose: 资金用途
qa_list: 提问列表
[{
q: 提问内容
q_time: 提问时间(时间戳)
a: 回答
a_time: 回答时间(时间戳)
user_id: 提问用户
name: 提问用户名
title: 提问用户职位
}]
}
我收到的项目/我关注的项目/我创建的项目¶
http://mobile.tonghs.me/v2/startup/my
params:
*pagesize: 每页条数, 默认为 10
*pageindex: 当前页数, 默认为 1
uid: 用户 ID
access_token:
*state: 项目所处状态 全部 0 /上线 1 /预热 2(筛选用)
type: 请求类型
0: 我收到的项目
1: 我关注的项目
2: 我创建的项目
return:
{
pageindex: 当前页
total: 总条数
list:
[{
id: 公司ID
name: 项目名
logo: 公司logo
concept: 项目简介
member_count: 成员数
industry: 行业
region: 地区
stage: 所处阶段
fanscount: 粉丝数
viewcount: 查看数
meetingcount: 约谈数
}]
}
申请查看项目¶
http://mobile.tonghs.me/v2/startup/view_apply
params:
uid: 用户ID
access_token:
com_id: 要查看的公司ID
return:
{
message: 提示信息
success: true/false
}
发送投资意向¶
http://mobile.tonghs.me/v2/startup/vc
params:
uid: 用户ID
access_token:
com_id: 项目
amount: 投资金额
phone: 电话
weixin: 微信
service: 提供的服务
*angel_name: 投资人姓名
retrun:
{
message: 返回信息
success: true/false
}
项目新闻列表¶
http://mobile.tonghs.me/v2/startup/news
params:
uid: 用户ID
access_token:
com_id: 项目ID
*pageindex: 当前页
*pagesize: 每页条数
return:
{
list:
{
title: 标题
content: 内容
url:
from: 来源
occurdate: 日期(时间戳)
}
}
约谈¶
http://mobile.tonghs.me/v2/startup/meeting
params:
uid: 用户ID
access_token:
com_id: 项目ID
content: 内容
return:
{
message: 提示信息
success: true/false
}
分享项目¶
http://mobile.tonghs.me/v2/startup/share
params:
uid: 用户ID
access_token:
com_id: 项目ID
user_list: 用户ID 列表,字符串,ID以逗号分隔,如:'10878516,10878515'
content: 内容
return:
{
message: 提示信息
success: true/false
}
关注和粉丝¶
关注人或项目¶
http://mobile.tonghs.me/v2/follow
params:
id: 要关注的人或项目的ID
uid: 登录人ID
access_token:
return:
{
message: 提示信息
success: true/false
}
取消关注人或项目¶
http://mobile.tonghs.me/v2/unfollow
params:
id: 要关注的人或项目的ID
uid: 登录人ID
access_token:
return:
{
message: 提示信息
success: true/false
}
关注的人¶
http://mobile.tonghs.me/v2/user/focused
params:
uid: 用户ID
*id: 要查询的用户或公司的ID,如果不传,则默认用为当前登录人ID
access_token:
*pageindex: 页数
*pagesize: 每页显示条数
*type: 请求列表类型 0: 全部 1: 创业者 2: 投资人
return:
{
list:
[{
id: 用户ID
name: 姓名
title: 职位
company: 公司
industry: 行业
summary: 简介
part: 身份 0: 创业者 1: 投资人 2: 领投人
avatar: 头像
active_time: 活跃时间(时间戳)
}]
}
粉丝¶
http://mobile.tonghs.me/v2/user/follower
params:
uid: 用户ID
*id: 要查询的用户或公司的ID,如果不传,则默认用为当前登录人ID
access_token:
*pageindex: 页数
*pagesize: 每页显示条数
*type: 请求列表类型 0: 全部 1: 创业者 2: 投资人
return:
{
list:
[{
id: 用户ID
name: 姓名
title: 职位
company: 公司
industry: 行业
summary: 简介
part: 身份 0: 创业者 1: 投资人 2: 领投人
avatar: 头像
active_time: 活跃时间(时间戳)
}]
}
个人设置¶
修改姓名¶
http://mobile.tonghs.me/v2/settings/profile/save_name
params:
uid: 用户ID
access_token:
name: 用户姓名
return:
{
message: 返回信息
success: true/false
}
修改公司¶
http://mobile.tonghs.me/v2/settings/profile/save_com
params:
uid: 用户ID
access_token:
com: 公司名称
return:
{
message: 返回信息
success: true/false
}
修改职位¶
http://mobile.tonghs.me/v2/settings/profile/save_title
params:
uid: 用户ID
access_token:
title: 职位
return:
{
message: 返回信息
success: true/false
}
修改电话¶
http://mobile.tonghs.me/v2/settings/profile/save_phone
params:
uid: 用户ID
access_token:
phone: 电话
return:
{
message: 返回信息
success: true/false
}
修改QQ¶
http://mobile.tonghs.me/v2/settings/profile/save_qq
params:
uid: 用户ID
access_token:
qq: QQ
return:
{
message: 返回信息
success: true/false
}
修改微信¶
http://mobile.tonghs.me/v2/settings/profile/save_weixin
params:
uid: 用户ID
access_token:
weixin: 微信
return:
{
message: 返回信息
success: true/false
}
修改简介¶
http://mobile.tonghs.me/v2/settings/profile/save_summary
params:
uid: 用户ID
access_token:
summary: 简介
return:
{
message: 返回信息
success: true/false
}
修改地区¶
http://mobile.tonghs.me/v2/settings/profile/save_region
params:
uid: 用户ID
access_token:
region: 区域ID
return:
{
message: 返回信息
success: true/false
}
修改头像¶
http://mobile.tonghs.me/v2/settings/profile/save_avatar
params:
uid: 用户ID
access_token:
avatar: 头像文件
return:
{
message: 返回信息
success: true/false
avatar: 返回头像 url 值
}
其他¶
获取区域列表¶
http://mobile.tonghs.me/v2/settings/profile/getregionlist
method:
GET
params:
无
return:
{
list:
[{
parentid: 父级ID
ancestornames: 父级名称
id: 区域ID
name: 区域名称
}]
}
示例:
{
list:
[{
parentid: "1"
ancestornames: ""
id: "1"
name: "中国"
}
{
parentid: "1"
ancestornames: "中国"
id: "4295032832"
name: "北京"
}
{
parentid: "4295032832"
ancestornames: "北京"
id: "4295033088"
name: "东城区"
}]
}
说明:
可通过以下方法判断国家、省(直辖市)和城市(区):
- 当id 的长度小于 10 时是国家
- 当parentid 长度小于 10 时是省(直辖市)
- 当parentid 长度等于 10 时是市(地区)
提问¶
http://mobile.tonghs.me/v2/startup/q
param:
uid: 当前登录人ID
access_token:
com_id: 公司ID
content: 提问内容
return:
{
success: true/false
message:
}
回答¶
http://mobile.tonghs.me/v2/startup/a
param:
uid: 当前登录人ID
access_token:
q_id: 问题ID
content: 回答内容
return:
{
success: true/false
message:
}
是否收到新项目¶
http://mobile.tonghs.me/v2/user/receive_com_count
param:
uid: 当前登录人ID
access_token:
count: 本地保存的接受项目个数
return:
{
success: true/false 是否接收到新项目
message:
count: 新更新的项目数
}
是否有新粉丝¶
http://mobile.tonghs.me/v2/user/follow_count
param:
uid: 当前登录人ID
access_token:
count: 本地保存的粉丝数
return:
{
success: true/false 是否有新粉丝
message:
count: 新更新的粉丝数
}
系统通知¶
http://mobile.tonghs.me/v2/settings/notice
旧版: http://mobile.tonghs.me/settings/notice
param:
uid: 当前登录人ID
access_token:
return:
{
list: [{
id: 通知ID
cid: 通知类型 详细类型见说明
create_time: 通知时间
txt: 详细数据类型见说明
}]
}
说明:
通知类型:
提交项目: 3
分享项目: 4
项目进入预热: 5
项目审核失败 : 6
发送投资意向: 7
合投上线: 8
融资成功: 9
融资失败: 10
投资人审核通过: 11
投资人审核失败: 12
管理员分享项目: 13(新版未上,目前没有)
不同类型的返回值如下:
提交项目:
user_id: 提交人ID
user_name: 提交人姓名
user_ico: 提交人ico
com_id: 项目ID
com_name: 项目名
com_ico: 项目logo
分享项目:
user_id: 提交人ID
user_name: 提交人姓名
user_ico: 提交人ico
com_id: 项目ID
com_name: 项目名
com_ico: 项目logo
reson: 分享理由
项目进入预热/合投上线/融资成功/融资失败:
com_id: 项目ID
com_name: 项目名
com_ico: 项目logo
项目审核失败:
com_id: 项目ID
com_name: 项目名
com_ico: 项目logo
reason: 失败原因
发送投资意向:
user_id: 提交人ID
user_name: 提交人姓名
user_ico: 提交人ico
com_id: 项目ID
com_name: 项目名
com_ico: 项目logo
amount: 发送金额
投资人申请通过:
{}
投资人申请未通过:
reason: 未通过原因
管理员分享项目:
com_id: 项目ID
com_name: 项目名
com_ico: 项目logo
reason: 分享理由
team: 团队成员介绍
summary: 公司简介
另外:
成功图片:http://dn-ac88.qbox.me/default_cheer.png
成功图片:http://dn-ac88.qbox.me/default_sorry.png
手机 API (version 2)¶
作者: tonghs tonghuashuai@gmail.com
注册登录¶
获取图片验证码¶
http://mobile.tonghs.me/v2/home/img_verify_code
method:
GET
params:
无
return:
{
key: 验证码 key
img: 验证码图片 base64
}
发送手机验证码¶
http://mobile.tonghs.me/v2/home/verify_code
params:
phone: 手机号码
key: 图片验证码 key
token: 图片验证码
return:
{
message: 返回信息
success: 是否成功 true/false
time: 剩余时间
}
注册¶
http://mobile.tonghs.me/v2/home/register
params:
phone: 手机号码
code: 验证码
name: 姓名
password: 密码
password_: 确认密码
key: 图片验证码 key
return:
{
message: 返回信息
success: true/false
}
登录¶
http://mobile.tonghs.me/v2/home/login
params:
account: 邮箱或手机号码
password: 密码
return:
登录失败时
{
message: 返回信息
success: true/false
}
登录成功时
{
user: {
id: 用户ID
name: 姓名
avatar_big: 头像
avatar_small: 小头像
access_token:
summary: 简介
firmname: 公司名
title: 职位
phone: 电话
qq:
weixin:
email:
defaultpart: 参与身份1: 投资人 2: 领投人
regionid: 省份ID
regionname: 省份名
cityid: 城市ID
cityname: 城市名
}
}
用户¶
投资人列表¶
http://mobile.tonghs.me/v2/user
params:
*pagesize: 每页条数, 默认为 10
*pageindex: 当前页数, 默认为 1
uid: 用户 ID
access_token:
*industry: 行业(筛选用)
*region: 区域(筛选用)
return:
{
industry: 行业
regionid: 区域
total: 总条数
list: [{
id:
name: 姓名
firmname: 公司
title: 职位
followercount: 粉丝数
industry: 行业
region_name: 地区
isfollow: 是否关注
summary: 简介
part: 身份 0: 创业者 1: 投资人 2: 领投人
avatar: 头像
meetingtimes: 约谈数
view_count: 0 查看次数,主站无该数据
}]
}
投资人列表搜索¶
http://mobile.tonghs.me/v2/user_search
params:
*pagesize: 每页条数, 默认为 10
*pageindex: 当前页数, 默认为 1
uid: 用户 ID
access_token:
keyword: 关键字
return:
{
pagesize: 每页条数
pageindex: 当前页数
total: 总条数
list: [{
id:
name: 姓名
firmname: 公司
title: 职位
followercount: 粉丝数
industry: 行业
region_name: 地区
isfollow: 是否关注
summary: 简介
part: 身份 0: 创业者 1: 投资人 2: 领投人
avatar: 头像
meetingtimes: 约谈数
view_count: 0 查看次数,主站无该数据
}]
}
投资人详情¶
http://mobile.tonghs.me/v2/user/detail
params:
uid: 用户 ID
access_token:
user_id: 要查看的用户的ID
return:
{
user: {
id: ID
name: 姓名
avatar: 头像
part: 0: 创业者 1: 投资人
summary: 简介
style: 投资理念
business: 擅长领域
service: 提供服务
isfollow: 是否关注
following_count: 关注人数
following_list:
[{
id:
name: 姓名
title: 职位
avatar: 头像
industry: 行业
isfollow: 是否关注
summary: 简介
part: 身份 0: 创业者 1: 投资人 2: 领投人
}]
follower_count: 粉丝人数
follower_list:
[{
id:
name: 姓名
title: 职位
avatar: 头像
industry: 行业
isfollow: 是否关注
summary: 简介
part: 身份 0: 创业者 1: 投资人 2: 领投人
}]
invested_com: 参与过的项目
[{
id: 公司 ID
name: 项目名
logo: 公司 logo
concept: 一句话介绍
viewercount: 查看次数
isfans: 是否是粉丝
creatorid: 创建人id
industry: 行业
region: 区域
shareurl: 微信分享链接
meetingcount: 约谈次数
day: 剩余天数
amount: 融资金额
fanscount: 粉丝数
finishamount: 完成融资数
part: 参与身份1: 投资人 2: 领投人
}]
comment_list: 评论列表
[{
user_id: 用户ID
name:
avatar: 头像
title: 职位
content: 评论内容
time: 时间(时间戳,目前未取到)
}]
bbs_list: bbs 列表
[{
title: 标题
url: 连接
time: 时间(时间戳)
}]
}
}
提交项目¶
http://mobile.tonghs.me/v2/user/submit_com
params:
uid: 用户ID
access_token:
com_id: 项目ID
target_id: 要提交给的投资人的ID
return:
{
message: 错误信息
success: true/false
}
创业者详情¶
http://mobile.tonghs.me/v2/user/detail
params:
uid: 用户 ID
access_token:
user_id: 要查看的用户的ID
return:
{
user: {
id: ID
name: 姓名
avatar: 头像
summary: 简介
skill: 技能
part: 0: 创业者 1: 投资人
isfollow: 是否关注
my_com: 参与过的项目
[{
id: 项目ID
name:
logo:
state: 项目状态
concept: 项目简介
viewercount: 查看次数
isfans: 是否是粉丝
industry: 行业
region: 区域
shareurl: 微信分享链接
meetingcount: 约谈次数
day: 剩余天数
amount: 融资金额
fanscount: 粉丝数
finishamount: 完成融资数
}]
following_count: 关注人数
following_list:
[{
id:
name: 姓名
title: 职位
avatar: 头像
industry: 行业
isfollow: 是否关注
summary: 简介
part: 身份 0: 创业者 1: 投资人 2: 领投人
}]
follower_count: 粉丝人数
follower_list:
[{
id:
name: 姓名
title: 职位
avatar: 头像
industry: 行业
isfollow: 是否关注
summary: 简介
part: 身份 0: 创业者 1: 投资人 2: 领投人
}]
career: 工作经历
[{
start: 开始时间
end: 结束时间
company: 公司名称
title: 职位
txt: 介绍
}]
edu:
[{
start: 0,
major: 专业
school: 学校
degress: 学位
}]
}
}
项目相关¶
项目列表¶
http://mobile.tonghs.me/v2/startup
params:
client_id:
*pagesize: 每页条数, 默认为 10
*pageindex: 当前页数, 默认为 1
uid: 用户 ID
access_token:
*state: 项目所处状态 全部 0 /上线 1 /预热 2(筛选用)
*industryid: 行业(筛选用)
*regionid: 区域(筛选用)
type: 请求类型
0: 项目列表
1: 我收到的项目
2: 我关注的项目
3: 我创建的项目
return:
{
pageindex: 当前页数, 默认为 1
industryid: 行业
total: 总条数
regionid: 区域
list: [{
viewercount: 查看次数
concept: 一句话介绍
viewapply: 是否申请查看 1/0
name: 项目名
coinveststatus: 合投状态
10: '申请未通过',
20: '创建中',
21: '未申请合投',
30: '申请合投中',
40: '合投预热',
50: '合投待上线',
60: '合投上线',
70: '确认投资人名单',
80: '融资完成',
90: '融资失败',
isfans: 是否是粉丝
industry: 行业
region: 区域
member_count: 成员数
shareurl: 微信分享链接
meetingcount: 约谈次数
day: 剩余天数
creatorname: 创建者姓名
amount: 融资金额
canview: 是否可以查看
creatorid: 创建者 ID
financingid: 融资 ID (目前没用)
creatorphone: 创建者手机
logo: 公司 logo
id: 公司 ID
fanscount: 粉丝数
finishamount: 完成融资数
}]
}
项目列表搜索¶
http://mobile.tonghs.me/v2/startup_search
params:
client_id:
*pagesize: 每页条数, 默认为 10
*pageindex: 当前页数, 默认为 1
uid: 用户 ID
access_token:
*keyword: 关键字
return:
{
pagesize: 每页条数
pageindex: 当前页数
total: 总条数
list: [{
viewercount: 查看次数
concept: 一句话介绍
viewapply: 是否申请查看 1/0
name: 项目名
coinveststatus: 合投状态
10: '申请未通过',
20: '创建中',
21: '未申请合投',
30: '申请合投中',
40: '合投预热',
50: '合投待上线',
60: '合投上线',
70: '确认投资人名单',
80: '融资完成',
90: '融资失败',
isfans: 是否是粉丝
industry: 行业
region: 区域
member_count: 成员数
shareurl: 微信分享链接
meetingcount: 约谈次数
day: 剩余天数
creatorname: 创建者姓名
amount: 融资金额
canview: 是否可以查看
creatorid: 创建者 ID
financingid: 融资 ID (目前没用)
creatorphone: 创建者手机
logo: 公司 logo
id: 公司 ID
fanscount: 粉丝数
finishamount: 完成融资数
}]
}
项目详情页¶
http://mobile.tonghs.me/v2/startup/detail
params:
uid: 用户 ID
access_token:
com_id: 要查看的项目ID
return:
{
id: 项目ID
name: "运策网"
url: 官方网站
creatorid: 创始人ID
logo:
summary: 简介
demourl: 试用地址
android: android 下载地址
demouser: 试用用户
demopwd: 试用密码
weibo: 微博
weixin: 微信
ios: iOS 下载地址
growthdata: 成长数据
[{
occurtime: 时间
name: 数据名称
quantity: 数量
}]
tutor: 导师
[{
id:
name: 姓名
title: 职位
avatar: 头像
industry: 行业
isfollow: 是否关注
summary: 简介
part: 身份 0: 创业者 1: 投资人 2: 领投人
}]
milestone: 大事记
[{
content: 内容
occurdate: 时间
}]
news: 新闻
[{
title: 标题
content: 内容
url: 连接
from: 来源
occurdate: 时间
}]
pics: 图片信息列表
[{
small: 小图片(320px)
big: 大图片(640px)
}]
incubator: 孵化器
[{
id:
name:
avatar: 头像
summary: 简介
region: 区域
start_date: 开始时间
end_date: 结束时间
}]
team: 团队
[{
id:
name: 姓名
title: 职位
avatar: 头像
industry: 行业
isfollow: 是否关注
summary: 简介
part: 身份 0: 创业者 1: 投资人 2: 领投人
}]
}
项目融资信息¶
http://mobile.tonghs.me/v2/startup/finance
params:
uid: 用户 ID
access_token:
com_id: 项目ID
return:
{
stock_sale: 出让股权比例
min_quota: 最小融资额度
hope_amounta: 预计融资
price: 融资前估值
finace_history: 过往融资
txt: 除资金以外的其他需求
[{
time: 时间(时间戳)
content: 内容?(带确定,目前该字段内容为融资金额)
}]
vc_list: 本轮投资意向列表
[{
id:
name: 姓名
title: 职位
avatar: 头像
industry: 行业
isfollow: 是否关注
summary: 简介
part: 身份 0: 创业者 1: 投资人 2: 领投人
}]
pre_vc_list: 上一轮投资意向列表
[{
id:
name: 姓名
title: 职位
avatar: 头像
industry: 行业
isfollow: 是否关注
summary: 简介
part: 身份 0: 创业者 1: 投资人 2: 领投人
}]
purpose: 资金用途
qa_list: 提问列表
[{
q: 提问内容
q_time: 提问时间(时间戳)
a: 回答
a_time: 回答时间(时间戳)
user_id: 提问用户
name: 提问用户名
title: 提问用户职位
}]
}
我收到的项目/我关注的项目/我创建的项目¶
http://mobile.tonghs.me/v2/startup/my
params:
*pagesize: 每页条数, 默认为 10
*pageindex: 当前页数, 默认为 1
uid: 用户 ID
access_token:
*state: 项目所处状态 全部 0 /上线 1 /预热 2(筛选用)
type: 请求类型
0: 我收到的项目
1: 我关注的项目
2: 我创建的项目
return:
{
pageindex: 当前页
total: 总条数
list:
[{
id: 公司ID
name: 项目名
logo: 公司logo
concept: 项目简介
member_count: 成员数
industry: 行业
region: 地区
stage: 所处阶段
fanscount: 粉丝数
viewcount: 查看数
meetingcount: 约谈数
}]
}
申请查看项目¶
http://mobile.tonghs.me/v2/startup/view_apply
params:
uid: 用户ID
access_token:
com_id: 要查看的公司ID
return:
{
message: 提示信息
success: true/false
}
发送投资意向¶
http://mobile.tonghs.me/v2/startup/vc
params:
uid: 用户ID
access_token:
com_id: 项目
amount: 投资金额
phone: 电话
weixin: 微信
service: 提供的服务
*angel_name: 投资人姓名
retrun:
{
message: 返回信息
success: true/false
}
项目新闻列表¶
http://mobile.tonghs.me/v2/startup/news
params:
uid: 用户ID
access_token:
com_id: 项目ID
*pageindex: 当前页
*pagesize: 每页条数
return:
{
list:
{
title: 标题
content: 内容
url:
from: 来源
occurdate: 日期(时间戳)
}
}
约谈¶
http://mobile.tonghs.me/v2/startup/meeting
params:
uid: 用户ID
access_token:
com_id: 项目ID
content: 内容
return:
{
message: 提示信息
success: true/false
}
分享项目¶
http://mobile.tonghs.me/v2/startup/share
params:
uid: 用户ID
access_token:
com_id: 项目ID
user_list: 用户ID 列表,字符串,ID以逗号分隔,如:'10878516,10878515'
content: 内容
return:
{
message: 提示信息
success: true/false
}
关注和粉丝¶
关注人或项目¶
http://mobile.tonghs.me/v2/follow
params:
id: 要关注的人或项目的ID
uid: 登录人ID
access_token:
return:
{
message: 提示信息
success: true/false
}
取消关注人或项目¶
http://mobile.tonghs.me/v2/unfollow
params:
id: 要关注的人或项目的ID
uid: 登录人ID
access_token:
return:
{
message: 提示信息
success: true/false
}
关注的人¶
http://mobile.tonghs.me/v2/user/focused
params:
uid: 用户ID
*id: 要查询的用户或公司的ID,如果不传,则默认用为当前登录人ID
access_token:
*pageindex: 页数
*pagesize: 每页显示条数
*type: 请求列表类型 0: 全部 1: 创业者 2: 投资人
return:
{
list:
[{
id: 用户ID
name: 姓名
title: 职位
company: 公司
industry: 行业
summary: 简介
part: 身份 0: 创业者 1: 投资人 2: 领投人
avatar: 头像
active_time: 活跃时间(时间戳)
}]
}
粉丝¶
http://mobile.tonghs.me/v2/user/follower
params:
uid: 用户ID
*id: 要查询的用户或公司的ID,如果不传,则默认用为当前登录人ID
access_token:
*pageindex: 页数
*pagesize: 每页显示条数
*type: 请求列表类型 0: 全部 1: 创业者 2: 投资人
return:
{
list:
[{
id: 用户ID
name: 姓名
title: 职位
company: 公司
industry: 行业
summary: 简介
part: 身份 0: 创业者 1: 投资人 2: 领投人
avatar: 头像
active_time: 活跃时间(时间戳)
}]
}
个人设置¶
修改姓名¶
http://mobile.tonghs.me/v2/settings/profile/save_name
params:
uid: 用户ID
access_token:
name: 用户姓名
return:
{
message: 返回信息
success: true/false
}
修改公司¶
http://mobile.tonghs.me/v2/settings/profile/save_com
params:
uid: 用户ID
access_token:
com: 公司名称
return:
{
message: 返回信息
success: true/false
}
修改职位¶
http://mobile.tonghs.me/v2/settings/profile/save_title
params:
uid: 用户ID
access_token:
title: 职位
return:
{
message: 返回信息
success: true/false
}
修改电话¶
http://mobile.tonghs.me/v2/settings/profile/save_phone
params:
uid: 用户ID
access_token:
phone: 电话
return:
{
message: 返回信息
success: true/false
}
修改QQ¶
http://mobile.tonghs.me/v2/settings/profile/save_qq
params:
uid: 用户ID
access_token:
qq: QQ
return:
{
message: 返回信息
success: true/false
}
修改微信¶
http://mobile.tonghs.me/v2/settings/profile/save_weixin
params:
uid: 用户ID
access_token:
weixin: 微信
return:
{
message: 返回信息
success: true/false
}
修改简介¶
http://mobile.tonghs.me/v2/settings/profile/save_summary
params:
uid: 用户ID
access_token:
summary: 简介
return:
{
message: 返回信息
success: true/false
}
修改地区¶
http://mobile.tonghs.me/v2/settings/profile/save_region
params:
uid: 用户ID
access_token:
region: 区域ID
return:
{
message: 返回信息
success: true/false
}
修改头像¶
http://mobile.tonghs.me/v2/settings/profile/save_avatar
params:
uid: 用户ID
access_token:
avatar: 头像文件
return:
{
message: 返回信息
success: true/false
avatar: 返回头像 url 值
}
其他¶
获取区域列表¶
http://mobile.tonghs.me/v2/settings/profile/getregionlist
method:
GET
params:
无
return:
{
list:
[{
parentid: 父级ID
ancestornames: 父级名称
id: 区域ID
name: 区域名称
}]
}
示例:
{
list:
[{
parentid: "1"
ancestornames: ""
id: "1"
name: "中国"
}
{
parentid: "1"
ancestornames: "中国"
id: "4295032832"
name: "北京"
}
{
parentid: "4295032832"
ancestornames: "北京"
id: "4295033088"
name: "东城区"
}]
}
说明:
可通过以下方法判断国家、省(直辖市)和城市(区):
- 当id 的长度小于 10 时是国家
- 当parentid 长度小于 10 时是省(直辖市)
- 当parentid 长度等于 10 时是市(地区)
提问¶
http://mobile.tonghs.me/v2/startup/q
param:
uid: 当前登录人ID
access_token:
com_id: 公司ID
content: 提问内容
return:
{
success: true/false
message:
}
回答¶
http://mobile.tonghs.me/v2/startup/a
param:
uid: 当前登录人ID
access_token:
q_id: 问题ID
content: 回答内容
return:
{
success: true/false
message:
}
是否收到新项目¶
http://mobile.tonghs.me/v2/user/receive_com_count
param:
uid: 当前登录人ID
access_token:
count: 本地保存的接受项目个数
return:
{
success: true/false 是否接收到新项目
message:
count: 新更新的项目数
}
是否有新粉丝¶
http://mobile.tonghs.me/v2/user/follow_count
param:
uid: 当前登录人ID
access_token:
count: 本地保存的粉丝数
return:
{
success: true/false 是否有新粉丝
message:
count: 新更新的粉丝数
}
系统通知¶
http://mobile.tonghs.me/v2/settings/notice
旧版: http://mobile.tonghs.me/settings/notice
param:
uid: 当前登录人ID
access_token:
return:
{
list: [{
id: 通知ID
cid: 通知类型 详细类型见说明
create_time: 通知时间
txt: 详细数据类型见说明
}]
}
说明:
通知类型:
提交项目: 3
分享项目: 4
项目进入预热: 5
项目审核失败 : 6
发送投资意向: 7
合投上线: 8
融资成功: 9
融资失败: 10
投资人审核通过: 11
投资人审核失败: 12
管理员分享项目: 13(新版未上,目前没有)
不同类型的返回值如下:
提交项目:
user_id: 提交人ID
user_name: 提交人姓名
user_ico: 提交人ico
com_id: 项目ID
com_name: 项目名
com_ico: 项目logo
分享项目:
user_id: 提交人ID
user_name: 提交人姓名
user_ico: 提交人ico
com_id: 项目ID
com_name: 项目名
com_ico: 项目logo
reson: 分享理由
项目进入预热/合投上线/融资成功/融资失败:
com_id: 项目ID
com_name: 项目名
com_ico: 项目logo
项目审核失败:
com_id: 项目ID
com_name: 项目名
com_ico: 项目logo
reason: 失败原因
发送投资意向:
user_id: 提交人ID
user_name: 提交人姓名
user_ico: 提交人ico
com_id: 项目ID
com_name: 项目名
com_ico: 项目logo
amount: 发送金额
投资人申请通过:
{}
投资人申请未通过:
reason: 未通过原因
管理员分享项目:
com_id: 项目ID
com_name: 项目名
com_ico: 项目logo
reason: 分享理由
team: 团队成员介绍
summary: 公司简介
另外:
成功图片:http://dn-ac88.qbox.me/default_cheer.png
成功图片:http://dn-ac88.qbox.me/default_sorry.png
后端技术¶
天使汇开发流程简介¶
python¶
- 闭包
- 正则表达式
- collections
- defaultdict
- itertools
- enum
- IntEnum
- enumerate
- time.mktime(time.strptime(“2007-03-04 21:08:12”, “%Y-%m-%d %H:%M:%S”))
- dateparser
- python 的 新式类与旧式类 , 以及super的意义
supervisor¶
- 线上服务器如何看异常
开发流程¶
新建一个页面通常需要创建几个文件:
- 模板 zapp/SITE/model/模块名.py
- 视图 zapp/SITE/view/模块名.py
- Coffee Script 脚本 coffee/SITE/auth/模块名/视图名.coffee
- Make 模板 html/SITE/auth/模块名/视图名.html
- CSS 样式文件 css/SITE/auth/模块名.css
并在 _url.py
中注册视图。
- 新建url页面
- render
- css,js的引用
- merge.conf
- 新建css,js,修改merge.conf需要重启开发服务器
- View的类型
- 分页
- 在页面取得当前用户
- 搜索
- 自动补全
- gearman 异步调用
- JsOb
- rendermail 发送邮件
- redis key的定义 , R.
- model 中 使用绝对路径import以防止redis提示key重复定义
- import _env
- 配置文件 的 定义 与 自适应
- make.py 生成配置文件
Mako 模板¶
Mako 模板的存放路径通常是 42web/html/SITE/模块名/文件名.html。
Mako 模板的使用见 教程 ,通用部分通常需要剥离成一个 _base.html 文件中,
不被直接 render 的模板命名以下划线 _
开头。
一个基本的模板文件大概是这样的:
## 这里继承父模版
<%inherit file="/SITE/_base/default.html" />
## 添加头文件、CSS 文件
<%block name="head">
<meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=0, width=device-width">
## 这里引入 CSS 文件,将目录名中的斜线换成下划线作为变量传入
<link rel="stylesheet" href="${css.SITE_auth_m}" />
</%block>
<%block name="script">
## 在文件尾引入 JS 文件,变量名同为替换后的目录名,JS 文件来自于变异 Coffee Script
<script src="${js.SITE_auth_m_m}"></script>
</%block>
Coffee Script¶
网页脚本用 Coffee Script,写完后需编译为 JavaScript (添加新的 CS 脚本需要手动重启 dev.sh 脚本,修改已存在的脚本会自动变异成 JS)。
Python Model¶
数据存储使用的是 MongoDB,通过封装过的 MongoKit 将数据 model 对应上 MongoDB 文档,
需要 from z42.web.mongo import mongo
。下面是一个简单的 model 文件示例:
from z42.web.mongo import Doc
from z42.web.mongo import mongo
class UserIM(Doc):
structure = {
'user_id': int,
'phone': basestring,
'qq': basestring,
'weixin':basestring
}
创建一个 UserIM 对象使用 upsert() 方法,如 UserIM({'phone': PHONE}).upsert({user_id: 1001})
,
这行代码的作用是:如果存在 user_id 为 1001 的 UserIM,则将其 ‘phone’ 设置为 PHONE,
否则在 MongoDB 中插入这样一个 JSON 文档: {‘user_id’: 1001, ‘phone’: PHONE}。
Python View¶
- View
- HostView
- LoginView
- AdminView
- GodView
- JsonErrView
- RpcView
- 组合 View
web 开发使用的框架是修改过的 Tornado,需要通过装饰器注册 URL。 新建一个简单的 view 如下:
from _route import route
from z42.web.view.j import JsonErrView
from jsob import JsOb
from zapp.SITE.view._base import HostView
@route('/m/register/')
class register(HostView):
def get(self, sign):
self.render()
@route('/j/m/')
class _(JsonErrView, HostView):
def post(self, sign):
err = JsOb() # 使用 JsOb 对象保存错误信息
o = self.json # 获取 JSON 化的 POST 信息
if not o.title:
err.title = "链接已失效!"
if not err:
do_something()
self.render(err)
这个 module 注册了两个 view,一个注册页面和一个 Ajax 接口。route 方法是一个用于注册 URL 的装饰器, 装饰在 Handler class(通常继承自XxxView)上即可。
register class 就是视图 Handler 的最简写法。对于 Ajax 视图,Handler 名意义不大,可以使用下划线命名。 需要返回错误提示的视图,可以继承 JsonErrView。View 的继承用法详见 视图介绍
上线流程¶
- 修改函数接口后, 用ag查找并修改些调用过的地方
- 函数命名规则 :名词在前动词在后 , 常用命名如下
- user_new 新建
- user_rm 删除
- user_dumps 返回一个包含各种相关数据的json对象
- user_id_list_by_com_id(limit, offset) 查询
- user_new 新建
- user_rm 删除
- user_dumps 返回一个包含各种相关数据的json对象
- user_id_list_by_com_id(limit, offset) 查询
- user_id_count_by_com_id
我们通常把user_id作为第一个参数
视图介绍¶
作者: | 王然 kxxoling@gmail.com |
---|
View¶
HostView¶
页面视图通常继承自该类,示例代码:
from zapp.SITE.misc.web.host_view import HostView
@route('/')
class index(HostView):
def get(self):
self.render()
JsonErrView¶
该 class 提供一个返回 JSON 文件的 render() 方法,通常用于 Ajax 后台验证。示例代码:
from z42.web.view.j import JsonErrView
from zapp.SITE.misc.web.host_view import HostView
@route('/j/m')
class _(JsonErrView, HostView):
def post(self):
err = JsOb()
# 为 err 添加内容
self.render(err)
LoginView¶
该 class 提供登录验证,需要登录的视图继承该视图。示例代码:
from zapp.SITE.view._base import LoginView
from zapp.SITE.misc.web.host_view import HostView
@route('/user/manage')
class _(LoginView, HostView):
def get(self):
self.render()
LoginHostView¶
JsonLoginView¶
HostAdminView¶
JsonHostAdminView¶
数据库¶
MongoDB¶
Author: | lzy kzinglzy@gmail.com, tonghs tonghuashuai@gmail.com |
---|
简介¶
MongoDB是文档型的非关系型数据库,其优势在于查询功能强大,能存储海量数据. 是懒人借以代替SQL型数据库的产品.
在API选择上, 我们用的是基于PyMongo的MongoKit, 并在此基础上进行了小的封装. 所以如果你遇到了问题, 可以去查阅PyMongo或MongoKit的官方文档
基本用法¶
- find
- limit
- skip
- sort
- delete
- remove(删除条件)
- save
- 填充默认值
- upsert
- 时间用int保存
- mongo默认值需要是一个生成函数
- pyhton常见的默认值陷阱,以create_time=time()为例
创建文档¶
在mongo里,用”文档”的概念代替SQL里的”表”. 例如, 下面定义了一个UserIm文档:
class UserIM(Doc):
structure = dict(
user_id=int,
phone=str,
qq=str,
weixin=str,
)
indexes = [{
'fields': 'user_id',
'unique': True
}]
default_values = {
'user_id': 0
}
其中, UserIm继承自类Doc
structure定义了文档的字段, 接受一个Python字典对象;
indexes定义了索引, 接受一个列表
default_values定义了初始化时的默认值.
除此之外, 你还可以添加更多的信息, 这些可以在 MongoKit document 里找到.
初始化¶
初始化一个文档对象可以这么写:
ui = UserIM()
此时, 所有的文档属性值都会被设为 None , 因为我们并没有给他传递任何值.
这可以通过传递一个字典对象或者JsOB对象来初始化属性值, 如:
ui = UserIM(dict(user_id=123, phone=456)) # 字典
ui = UserIM(JsOb(user_id=123, phone=456)) # JsOb 对象
但此时, 其它的没有被初始化的值还是会被设为 None, 若要使我们设置的default_values生效, 可以通过将第二个参数设为True来实现, 如:
ui = UserIM(dict(user_id=123, phone=456), True)
更新¶
下面我们想更新数据, 如:
ui = UserIm()
ui.user_id = 123
ui.mail = 'abc@gmail.com'
ui.save()
这将会添加一个user_id为123, mail为abc@gmail.com 的记录.
其中未被赋值的属性会被设为None, 不存在的属性会被忽略. 如果要添加的记录已存在, 那么旧的记录会被替换掉, 否则,会创建一个新的记录.
除此之外, 还有一种更优雅的方式可以实现数据的更新:
ui = UserIM({'mail': 'abc@gmail.com'})
user_im.upsert({'user_id': '123'})
这里使用了upsert这个函数, 它的效果和 save 是一样的.但用起来更优雅更简单.
查询¶
常用的查询要用到两个函数:
UserIM.find(dict(phone=456))
这会返回所有的phone值为456的Python列表.
UserIM.find_one(dict(user_id=123))
这会返回一个用户记录, 其 id 为123.
当然, 还可以添加更多的查询条件来实现复杂的查询, 如:
UserIM.find(
{'$or': [{'phone' :456}, {'mail': abc@gmail.com}]},
limit=10,
skip=0
)
如上会返回最多包含10条的, phone 为456或者 mail 为 abc@gmail.com 的记录列表
备份和恢复¶
Mongodb自带了mongodump和mongorestore这两个工具来实现对数据的备份和恢复。 mongodump能够在Mongodb运行时进行备份,它的工作原理是对运行的Mongodb做查询,然后将所有查到的文档写入磁盘。但是存在的问题时使用mongodump产生的备份不一定是数据库的实时快照,如果我们在备份时对数据库进行了写入操作,则备份出来的文件可能不完全和Mongodb实时数据相等。另外在备份时可能会对其它客户端性能产生不利的影响。
备份:
mongodump -d SITE -o ~/download/mongobak/SITE/
恢复:
mongorestore -d SITE --directoryperdb ~/download/mongobak/SITE/ --drop
注意: –drop 参数代表恢复前删除原数据
Redis¶
开发规范¶
42WEB 框架使用不完全手册¶
如何写文档¶
开发服务器上,文档的默认路径是
~/42web/static/doc/source
写完之后,在
~/42web/static/doc/
运行
make html
可以生成html, 访问 http://doc.你的域名, 可以浏览你新生成的文档
编码规范¶
我们python编码风格参见 Python 编码风格指南
一般而言,我们尽量使用英文单词的完整写法,而不使用缩写,以免陷入每个人缩写不统一的混乱局面。
html / css / coffee / model 命名(函数名,文件名)保持一致,这样找到了其中一个,就能方便地定位其他的所有。
html 的编码规范 我们参考 Google HTML/CSS代码风格指南
简单的说, 单元素标记(比如input,br,img,link,meta,hr等等)不要闭合。
不要view中直接调用redis,mongo去操作数据库,通过model层将其封装为接口再调用
redis¶
首先请阅读
使用演示 zapp/SITE/model/password_reset.py
import _env
from b64uuid import b64uuid
from z42.config import HOST
from zapp.SITE.model._db import redis, R
EXPIRE = 7*3600*24
R_PASSWORD_RESET = R.PASSWORD_RESET('%s')
def password_reset_link(user_id):
key = R_PASSWORD_RESET%user_id
token = redis.get(key)
if not token:
token = b64uuid()
redis.setex(key, EXPIRE, token)
return 'http://auth.%s/password_reset_verify/%s_%s'%(HOST, user_id, token)
def password_reset_verify(user_id, token):
return token and (token == redis.get(R_PASSWORD_RESET%user_id))
用法说明
因为redis的内存数据库,所以我们通过 R 来生成 redis 的 key 以节省内存占用 , R的用法如
R_AAA = R.AAA()
R_BBB = R.BBB('%s')
开发流程¶
- 代码结构
- 内部函数
- 代码结构
- 代码规范
新建一个页面通常需要创建几个文件:
- 模板 zapp/SITE/model/模块名.py
- 视图 zapp/SITE/view/模块名.py
- Coffee Script 脚本 coffee/SITE/auth/模块名/视图名.coffee
- Make 模板 html/SITE/auth/模块名/视图名.html
- CSS 样式文件 css/SITE/auth/模块名.css
并在 _url.py
中注册视图。
Mako 模板¶
Mako 模板的存放路径通常是 42web/html/SITE/模块名/文件名.html。
Mako 模板的使用见 教程 ,通用部分通常需要剥离成一个 _base.html 文件中,
不被直接 render 的模板命名以下划线 _
开头。
一个基本的模板文件大概是这样的:
## 这里继承父模版
<%inherit file="/SITE/_base/default.html" />
## 添加头文件、CSS 文件
<%block name="head">
## 这里引入 CSS 文件,将目录名中的斜线换成下划线作为变量传入
<link rel="stylesheet" href="${css.SITE_auth_m}">
</%block>
<%block name="script">
## 在文件尾引入 JS 文件,变量名同为替换后的目录名,JS 文件来自于编译 Coffee Script
<script src="${js.SITE_auth_m_m}"></script>
</%block>
几个注意点:
- 每个html模板都应该继承对应的基模板,不要直接写html
- js如果不写在block中会造成无法加载的问题
Coffee Script¶
网页脚本用 Coffee Script,写完后需编译为 JavaScript (添加新的 CS 脚本需要手动重启 dev.sh 脚本,修改已存在的脚本会自动编译成 JS)。
Python Model¶
数据存储使用的是 MongoDB,通过封装过的 MongoKit 将数据 model 对应上 MongoDB 文档,
需要 from z42.web.mongo import mongo
。下面是一个简单的 model 文件示例:
from z42.web.mongo import Doc
from z42.web.mongo import mongo
class UserIM(Doc):
structure = {
'user_id': int,
'phone': basestring,
'qq': basestring,
'weixin':basestring
}
创建一个 UserIM 对象使用 upsert() 方法,如 UserIM({'phone': PHONE}).upsert({user_id: 1001})
,
这行代码的作用是:如果存在 user_id 为 1001 的 UserIM,则将其 ‘phone’ 设置为 PHONE,
否则在 MongoDB 中插入这样一个 JSON 文档: {‘user_id’: 1001, ‘phone’: PHONE}。
Python View¶
web 开发使用的框架是修改过的 Tornado,需要通过装饰器注册 URL。 新建一个简单的 view 如下:
from _route import route
from z42.web.view.j import JsonErrView
from jsob import JsOb
from zapp.SITE.view._base import HostView
@route('/m/register/')
class register(HostView):
def get(self, sign):
self.render()
@route('/j/m/')
class _(JsonErrView, HostView):
def post(self, sign):
err = JsOb() # 使用 JsOb 对象保存错误信息
o = self.json # 获取 JSON 化的 POST 信息
if not o.title:
err.title = "链接已失效!"
if not err:
do_something()
self.render(err)
这个 module 注册了两个 view,一个注册页面和一个 Ajax 接口。route 方法是一个用于注册 URL 的装饰器, 装饰在 Handler class(通常继承自XxxView)上即可。
register class 就是视图 Handler 的最简写法。对于 Ajax 视图,Handler 名意义不大,可以使用下划线命名。 需要返回错误提示的视图,可以继承 JsonErrView。View 的继承用法详见 视图介绍
扩展阅读¶
开发流程¶
- 开发流程
- Fork 代码
- 代码提交
- 代码审查
- Pull Request
前端技术¶
director.js¶
作者: | 王然 kxxoling@gmail.com |
---|
简介¶
director 提供前端和后端的 路由解决方案,可以用于控制前端路由以及页面代码的显示与否。
使用很简单:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Director Example</title>
<div id="results"></div>
<script src="http://www.javascriptoo.com/application/html/js/flatiron/director/director.min.js"></script>
<script>
var r = document.getElementById('results');
var data = {
people: [
{ 'firstName': 'Clark', 'lastName': 'Kent' },
{ 'firstName': 'Bruce', 'lastName': 'Wayne' },
{ 'firstName': 'Peter', 'lastName': 'Parker' }
]
}
var viewPerson = function(personId) { r.innerHTML = data.people[personId].firstName + ' ' + data.people[personId].lastName; };
var routes = {'/person/view/:bookId': viewPerson};
var router = Router(routes);
router.init();
</script>
</head>
<body>
<ul>
<li><a href="#/person/view/0">Clark</a></li>
<li><a href="#/person/view/1">Bruce</a></li>
<li><a href="#/person/view/2">Peter</a></li>
</ul>
</body>
</html>
效果预览: GitHub Pages
使用 FontIcon¶
作者: 王然 kxxoling@gmail.com
为什么使用 FontIcon¶
位图图片不能很好地进行缩放,当图片进行放大时会失真(即变模糊),当图片进行缩小时就会浪费掉像素。而且加载每一张图片都需要一次“http请求”,因此也拖慢了整个加载页面的时间。另外,要是没有图片编辑器(软件)的话就很难对图片进行编辑、处理等操作。
字体就不会有以上这些问题,字体可以进行随意缩放并且每一个字符都不需要进行额外的“http请求”。
其它优势:
很容易任意地缩放; 很容易地改变颜色; 很容易地产生阴影; 可以拥有透明效果; 一般来说,有先进的浏览器支持; 可以使用CSS来装饰(可以得到CSS很好支持); 可以快速转化形态(做出一些变化,如 :hover等); 可以做出跟图片一样可以做的事情(改变透明度、旋转度,等); 本身体积更小,但携带的信息并没有削减。
扩展阅读:
http://www.w3cplus.com/css3/icon-fonts.html
如何使用¶
上传自己的图片格式 icon:http://www.iconfont.cn/icons/uploadShow
收藏:点开特定的图标库,将鼠标移动到图标上,点击“购物车按钮”或者图标本身。
下载:点击搜索框左侧的“购物车按钮”,选择“下载至本地”。
在线存储:点击搜索框左侧的“购物车按钮”,选择“存储为项目”即可在线使用。 存储后会会生成自己的项目,点击“获取在线链接”橙色按钮,即可生成如下 CSS 代码:
@font-face {
font-family: 'iconfont';
src: url('http://at.alicdn.com/t/font_1425368696_9550455.eot'); /* IE9*/
src: url('http://at.alicdn.com/t/font_1425368696_9550455.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
url('http://at.alicdn.com/t/font_1425368696_9550455.woff') format('woff'), /* chrome、firefox */
url('http://at.alicdn.com/t/font_1425368696_9550455.ttf') format('truetype'), /* chrome、firefox、opera、Safari, Android, iOS 4.2+*/
url('http://at.alicdn.com/t/font_1425368696_9550455.svg#iconfont') format('svg'); /* iOS 4.1- */
}
复制按钮对应的 Unicode 编码,如 
即可在项目中作为文字使用。
在线演示: http://angelcrunchdev.github.io/z42-doc/fonticon.html
注:文件类型请选择 Unicode(默认)而非 FontClass。
HTML + CSS¶
HTML¶
- label for属性
绑定表单元素id,实现点击label选中相应radio或checkbox * 链接都必须写上href属性, 空链接请写成:
::
<a href=”javascript:void(0)”></a>
- 反复出现的按钮图标用 a标签 配合 css设置背景图 来实现,不要反复的写img标签(减少代码的冗余度)
CSS¶
- 模块分级
- 全局级
- 模块级
- 页面级
- 分栏布局
例如左宽665px,父容器宽1000px,在layout.css中定义:
.R665{float: left; margin-left: 688px; width:312px;}
.L665{float: left; width: 665px; margin-left: -100%;}
参考:
- 绝对底部
CSS Sticky Footer <http://paranimage.com/css-sticky-footer/>
_ *
清除浮动 * 子选择器
利用父级元素id进行选择
图文混排 <http://dabblet.com/gist/4094139>
_CSS盒模型
垂直居中
如何制作三角
:first-child 和 :last-child
- 案例 : 圆圈 , padding
如果内容可变,就不要设置高度
写完页面依次检查
- 对齐
- 字体
- 大小
- 粗细
- 颜色
- 留白
邮件
Css Inliner Tool <http://templates.mailchimp.com/resources/inline-css/>
_42web
- HTML中如何引用图片
图片上传至七牛,使用外链地址
CSS中如何引用图片:
background:url(/css/\_img/xxx)
不要引用站外的图片
checkbox 和 radio 的 样式
文字对齐 <http://www.zhangxinxu.com/wordpress/?p=56>
_ *
不要用空格做间距
我们常用的CSS样式¶
- 按钮
- 功能
- 强调
设计¶
- 对齐
- 留白的一致性
- 粗体
- 字号
javascript¶
获取时间戳:
(new Date).geTime()
在js中取得当前用户:
$.current\_user
$$
例如调用弹窗(可有多个参数):
::
$$(‘SITE/auth/login’)
require
$.require
$.dialog * 需要登录调用.login_dialog(参考submit_project.coffee)
$.errtip
err = {} if xxx: err.xxx = "xx" if xx : err.xx ="xx" :: if not errtip.set err: xxxxx
jQuery¶
- $.extend([deep],target,object)
jQuery 自定义扩展¶
- $.timeago
接受一个时间戳作为参数,返回距离当前时间描述 * $.isotime * $.getJSON1 * jsonp 跨域调用 * $.postJSON1 * $.html 模版
参考egg_new.coffee
jQuery UI¶
- Accordion
- Datepicker
- Tagit
CoffeeScript¶
在页面中直接写coffee <http://coffeescript.org/#scripts>
_
avalon¶
命名规则的修改
“-“改为”_”
ms_view
操作类似view的复用
view与数据结构的模块划分原则(每一个保存的url对应一个view)
$remove <http://limodou.github.io/avalon-learning/zh_CN/event.html>
_$watch <http://limodou.github.io/avalon-learning/zh_CN/watch.html>
_如何定义avalon组建
- 创建既可以单独使用,也可以在循环中使用的avalon组件
参考ui_follow.coffee
Firebug¶
- 控制台面板中,点击“保持”按钮,页面重新载入时不清空面板
杂项¶
七牛剪裁 <http://developer.qiniu.com/docs/v6/api/reference/fop/image/imageview2.html>
_- 上传文件
- 上传头像
- 地址选择
工具¶
- Chrome插件
- PerfectPixel
- Page Ruler
- Windows
- Color Picker
入门篇¶
- 网页设计师 , 初学者可以从其中 » 循序渐进 章节开始自己的学习之旅
- HTML中文手册
- CSS中文手册
- CSS3 系列教程
- Javascript教程
- 15天学会jquery
- jquery中文手册
内部函数¶
- 前端函数
- $$
- $import
- View
jQuery Extensions¶
- $.postJSON1
- $.getJSON1
- $.host_id
- $.current_user
- $.current_user_id
- $.ajax_submit
- $.errtip
- $.cnenlen
- $.cookie
- $.islogin
- $.login
- $.loader.show
- $.loader.hide
textillate.js¶
作者: | 王然 kxxoling@gmail.com |
---|
简介¶
textillate.js 依赖于 lettering.js 和 animate.css ,主要用于文字出现时的动画效果。
WOW.js¶
作者: | 王然 kxxoling@gmail.com |
---|
基本使用¶
WOW.js
依赖于 animate.css ,所以使用前需引用 animate.css
。
<link rel="stylesheet" href="css/animate.css">
<script src="js/wow.min.js"></script>
初始化
<script>
new WOW().init();
</script>
WOW.js
根据 wow
类标记需要添加动画效果的元素:
<div class="wow">
Content to Reveal Here
</div>
再通过特定的类型设置动画类型,比如 bounceInUp
可以设置 自上而下的反弹效果 :
<div class="wow bounceInUp">
Content to Reveal Here
</div>
至此,已经实现了滚动时的动画效果。
高级设置¶
data-wow-duration:动画的持续时间 data-wow-delay:动画出现的延迟 data-wow-offset:动画的偏移距离(相对于浏览器底部) data-wow-iteration:动画出现的重复次数
<section class="wow slideInLeft" data-wow-duration="2s" data-wow-delay="5s">
</section>
<section class="wow slideInRight" data-wow-offset="10" data-wow-iteration="10">
</section>
配置¶
boxClass: Class name that reveals the hidden box when user scrolls.
animateClass: Class name that triggers the CSS animations (’animated’ by default for the animate.css library)
offset: Define the distance between the bottom of browser viewport and the top of hidden box. When the user scrolls and reach this distance the hidden box is revealed.
wow = new WOW(
{
boxClass: 'wow', // default
animateClass: 'animated', // default
offset: 0, // default
mobile: true, // default
live: true // default
}
)
wow.init();
内部工具¶
42qu.cc 简明实用教程¶
作者: | 王然 kxxoling@gmail.com |
---|
关于 42qu.cc¶
42qu.cc 是在线的随手贴,可以随意地自定义网址来自己记录或与朋友分享文字。
保存¶
42qu.cc 提供在线分享文本文件的功能。在命令行中输入
42qucc < 某个文件名
即可获得诸如 http://42qu.cc/6nhxuqpg 格式的网址,打开该链接即可看到分享的内容。
自定义网址¶
其它内部工具¶
- html2plim
- deltem
- dir_replace
- replace_line
seafile指南¶
这里介绍了如何使用seafile共享文件。
获取账户¶
发邮件给我moujunqiu@pe.vc(牟俊秋),写明你的邮箱地址,我会给你开通账户的,密码会随注册邮件发到您的邮箱。
从网页登陆¶
网页登陆地址是:http://seafile.mushapi.com
客户端安装和使用¶
seafile支持windows、mac、linux以及苹果和android手机,下载适合的版本并安装。
这里以ubuntu下的客户端为例说明客户端使用方法
登录
服务器处填入http://seafile.mushapi.com
填入邮箱和密码
创建资料库
- 从网页创建
- 从客户端创建
创建和加入群组
创建和加入群组的操作需要在 网页 上进行,所有用户都可以创建群组,群组的创建者自动成为该群组的管理员,其他成员申请加入该群组时需要群组管理员批准。
- 创建群组
登陆到seafile后,点击上方导航条的 群组 然后再点击下拉菜单中的 所有群组 。
在 我的群组 中点击 创建群组 按钮,输入群组相关信息完成创建。
- 加入群组
如何加入群组
- 管理员审核加入群组的请求
有用户申请加入群组后,群组管理员的首页上会显示一个通知,如下图所示
点击那个小铃铛,打开通知页面,首先点击该用户。
然后将该用户添加到你的通讯录里
最后在 群组 的 管理 里从通讯录中将该用户添加到群组。(我知道这里的操作很蠢,但我并没发现别的途径,如果有请告诉我)
共享资料库
资料库有三种共享方式,共享给个人、共享给群组、共享给机构。
- 共享给个人
通过个人的邮箱共享,共享之后只有指定的用户可以访问该资料库。
- 共享给群组
可以通过直接在群组中创建资料库或者将指定的资料库共享给您 已经加入 的群组,共享后群组内的所有成员都能访问该资料库。
- 共享给机构
这里的 机构 是指该网站下的所有用户,跟上一条相同也可通过直接在机构中创建和共享已有资料库的形式共享。
使用pc客户端同步资料库
右单击要同步的资料库,选择‘同步该资料库’选项,未同步的资料库的图标显示为一个云彩,同步完成的显示成一个绿色的对号。
技术栈¶
后端技能¶
- Python
- Mako
- Plim
docker¶
预习材料¶
windows使用¶
可以用xshell登录到虚拟机方便使用
基本用法¶
从镜像文件新建一个虚拟机
docker run -t -i -p 80:80 -p 2200:22 --name 42 6e469ec45c90 /bin/bash
docker run -d -p 80:80 -p 2222:22 --name 42 zuroc/42web /usr/sbin/sshd -D
ifconfig 可以看到docker母机的ip
重新进入一个虚拟机
docker start -i 42
浏览所有虚拟机
docker ps -a
一次性删除所有的容器
docker rm $(docker ps -q -a)
一次性删除所有的镜像。
docker rmi $(docker images -q)
docker commit 37a3eb81fb77 zuroc/42web 保存一个虚拟机为镜像 docker
export 42 \| xz -c > 42.txz
rsync -avhP docker.txz root@42py.com:/data
docer export 对应
导入的命令是 cat docker_42web.bz2 | docker import - zuroc/42web
我这里用的是niubi:latest ......
$ sudo ifconfig docker0 docker0 Link encap:Ethernet HWaddr xx:xx:xx:xx:xx:xx inet addr:172.17.42.1 Bcast:0.0.0.0 Mask:255.255.0.0
http://linuxwiki.github.io/Services/Docker.html#62docker0-ip
- ::
docker export bb6ce0f8e59c |bzip2 -c > 42.tar.bz2
sudo iptables -t nat -A PREROUTING -i eth0 -p tcp –dport 8000 -j DNAT –to 172.17.0.17:8000
mysql 密码 42web 解析
修改本机host , 加入
a.com xx.xxx.xx.xx sso.a.com xx.xxx.xx.xx
进入虚拟机后先运行boot sudo /etc/init.d/sshd start 可以启动ssh服务用xshell来登录
sudo /etc/init.d/sshd start
~/ac/zapp/TECH2IPO $ ./dev.sh
brew install dnsmasq
brew install dnsmasq
安装Homebrew¶
请打开 终端 (应用程序>实用工具),并运行
ruby -e "$(curl -fsSL https://raw.github.com/Homebrew/homebrew/go/install)"
你需要按照提示来继续安装。这个过程或许会很慢,受限于网络状况。如果实在很慢,你可以在VPN环境下安装。
安装完成之后,你就可以使用brew命令来安装dnsmasq了。
安装并配置dnsmasq组件!
仍然在终端运行
brew install dnsmasq
等待安装完成后,请在 /usr/local/ 文件下新建一个 etc 文件夹。
现在把 /usr/local/opt/dnsmasq/dnsmasq.conf.example 文件拷贝至并重命名为 /usr/local/etc/ dnsmasq.conf 。
在刚刚的 /usr/local/etc/ 文件夹下新建一个 resolv.dnsmasq.conf 文件。
用sublime text,textmate,bbedit等纯文本编辑器打开这个 resolv.dnsmasq.conf 文件,输入以下内容
nameserver 223.5.5.5 nameserver 223.6.6.6 nameserver 178.79.131.110
这些都是你常用的DNS地址,你可以添加更多,比如OpenDNS。
用sublime text,textmate,bbedit等纯文本编辑器打开同文件夹下的 dnsmasq.conf 文件,增加以下内容
resolv-file=/usr/local/etc/resolv.dnsmasq.conf
strict-order
no-hosts
cache-size=32768
listen-address=127.0.0.1
address=/c.cc/192.168.59.103 address=/a.com/192.168.59.103
这就是最简单的配置文件。需要说明的是,listen-address后面的可以是多个IP用英文逗号隔开,例如你写listen-address=127.0.0.1,192.168.1.102,其中192.168.1.102是你的计算机的内网IP,就可以实现同一个局域网内的设备,通过设置DNS为这个IP,来实现都通过你的dnsmasq来查询dns,即局域网范围内的DNS泛解析。
要运行并且开机自动运行dnsmasq,在终端运行
sudo cp -fv /usr/local/opt/dnsmasq/\*.plist /Library/LaunchDaemons sudo
launchctl load /Library/LaunchDaemons/homebrew.mxcl.dnsmasq.plist
现在,你可以通过把Mac系统的DNS改为127.0.0.1来使用dnsmasq。同局域网的用户也可以修改DNS到此台Mac的IP即可。前提是要把此台Mac的局域网IP写到listen-address里。
dnsmasq dns config 要检查运行情况,你可以在终端运行
dig g.cn
来检查是否在使用本地的dnsmasq进行dns解析。
DNSMASQ 泛解析¶
上面只是安装好了dnsmasq,下面来具体介绍DNSMASQ的泛解析功能,来突破墙,实现谷歌服务直连。要添加规则,只需在dnsmasq.conf文件里追加内容即可。
DNSMASQ的泛解析规则是这样的:
address=/baidu.com/1.1.1.1
这意味着,.baidu.com/都将被引导至IP为1.1.1.1。
前端库¶
- Avalon
- jQuery
- jQuer-UI
- FancyBox
- SCSS/SASS
- Stylus
- CoffeeScript
- Semantic UI
Hyper Estraier 简明教程¶
作者: | tonghs tonghuashuai@gmail.com |
---|
About¶
Hyper Estraier is a full-text search system. You can search lots of documents for some documents including specified words. If you run a web site, it is useful as your own search engine for pages in your site. Also, it is useful as search utilities of mail boxes and file servers.
http://fallabs.com/hyperestraier/
目前 天使汇 网站的全文搜索部分使用 Hyper Estraier 实现。
Install¶
emerge hyperestraier
Configuration¶
建立工作目录:
mkdir /mnt/data1/42web
设置路径读写权限
在工作目录下执行:
estmaster init .
删除工作目录下的配置文件,并执行:
ln -s ~/42web/zapp/SITE/misc/config/hyperestraier/_conf .
启动 hyperestraier:
estmaster start .
启动服务:
zapp/SITE/model/rpc/server/run.py zapp/SITE/model/rpc/server/search.py
访问 http://域名:1978,进入 web 管理页面(默认用户名密码 admin admin)
建立索引数据库 ob0 ob10000 ob20000
单击 Manage Nodes,在出现的页面填写 node 信息,第一个文本框为 name,第二个文本框为 label。
Other¶
- 用户管理
Select Manage Users. There are input boxes for user name, password, flags, full name and miscellaneous information at bottom. Enter following data for new user: “clint”, “tnilc”, “s”, “Clint Eastwood” and “Dirty Harry”. Flag “s” denotes user with super user privileges. User name is limited to alphanumeric characters only.
详细见:http://fallabs.com/hyperestraier/nguide-en.html 中的 Administration Interface 章节
Linux¶
Gentoo¶
- emerge –autounmask-write 然后 etc-update 然后 -3
- emerge =xxx-版本号
自定义的命令 .................................. * dirreplace * replace_line.py * deltmp
高级篇 .................................. * dstat * dirreplace * replace_line.py
- eix
- eix-update
- etc-update -3
- emerge –auto-unmaskwrite
- emerge =
- rc-update
- rc-update add 服务名称 default
- rc-update remove 服务名称 default
reStructuredText简明教程¶
作者: | 刘斗 redfork@gmail.com |
---|
图形化 web 编辑工具: rst.ninjs.org
段落¶
REST 是松散的文本结构,使用预定义的模式描述文章的结构。首先学习最基本的结构:段落。
段落是被空行分割的文字片段,左侧必须对齐(没有空格,或者有相同多的空格)。
缩进的段落被视为引文。
继续缩进……恢复
恢复
文字样式¶
最简单的样式是 斜体 和 粗体.
- *斜体*. 被*包围的文字是斜体
- **粗体**. 被**包围的文字是粗体
注意: * 两侧必须留有空格, 英文标点符号. 输入法设置为英文标点, 并使用正确的英文标点规范 (逗号, 句号后留一个空格, 引号, 括号两侧留一个空格).
列表¶
有三种列表:
- 顺序,
- 公告牌,
- 定义.
列表前后, 以及条目之间必须有空行隔开. 列表下面可以插入任意的内容, 段落, 图片都可以, 只要他们的左侧和列表的第一个文字左对齐.
顺序列表 - 符号样式¶
符号:
1. 数字
a. 小写字母
A. 大写字母
i) 小写罗马数字
(I) 大写罗马数字
顺序列表 - 符号样式 效果
符号:
- 数字
- 小写字母
- 大写字母
- 小写罗马数字
- 大写罗马数字
公告牌列表¶
和顺序列表相似, 使用 “*” “+” “-” 代替数字:
* 列表第一级
+ 第二级
- 第三级
+ 第二级的另一个项目
公告牌列表 生成:
- 列表第一级
- 第二级
- 第三级
- 第二级的另一个项目
嵌入程序代码¶
如果需要嵌入大段的程序代码(SQL, 业务逻辑设置, 配置文件等), 在段落末尾添加两个’:’. 代码的左侧必须缩进, 代码引用到没有缩进的行为止. 例如:
如果数据库有问题, 执行下面的 SQL::
# Dumping data for table `item_table`
INSERT INTO item_table VALUES (
0000000001, 0, 'Manual', '', '0.18.0',
'This is the manual for Mantis version 0.18.0.\r\n\r\nThe Mantis manual is modeled after the [url=http://www.php.net/manual/en/]PHP Manual[/url]. It is authored via the \\"manual\\" module in Mantis CVS. You can always view/download the latest version of this manual from [url=http://mantisbt.sourceforge.net/manual/]here[/url].',
'', 1, 1, 20030811192655);
嵌入程序代码生成:
如果数据库有问题, 执行下面的 SQL:
# Dumping data for table `item_table`
INSERT INTO item_table VALUES (
0000000001, 0, 'Manual', '', '0.18.0',
'This is the manual for Mantis version 0.18.0.\r\n\r\nThe Mantis manual is modeled after the [url=http://www.php.net/manual/en/]PHP Manual[/url]. It is authored via the \\"manual\\" module in Mantis CVS. You can always view/download the latest version of this manual from [url=http://mantisbt.sourceforge.net/manual/]here[/url].',
'', 1, 1, 20030811192655);
嵌入程序代码 续¶
如果没有合适的段落添加 ::, 也可以在一个空行上添加, 这个双冒号行被忽略:
::
#
# Dumping data for table `item_table`
#
INSERT INTO item_table VALUES (
0000000001, 0, 'Manual', '', '0.18.0',
'This is the manual for Mantis version 0.18.0.\r\n\r\nThe Mantis manual is modeled after the [url=http://www.php.net/manual/en/]PHP Manual[/url]. It is authored via the \\"manual\\" module in Mantis CVS. You can always view/download the latest version of this manual from [url=http://mantisbt.sourceforge.net/manual/]here[/url].',
'', 1, 1, 20030811192655);
嵌入程序代码 续 生成:
#
# Dumping data for table `item_table`
#
INSERT INTO item_table VALUES (
0000000001, 0, 'Manual', '', '0.18.0',
'This is the manual for Mantis version 0.18.0.\r\n\r\nThe Mantis manual is modeled after the [url=http://www.php.net/manual/en/]PHP Manual[/url]. It is authored via the \\"manual\\" module in Mantis CVS. You can always view/download the latest version of this manual from [url=http://mantisbt.sourceforge.net/manual/]here[/url].',
'', 1, 1, 20030811192655);
程序引用体例¶
可以 用 code-block::
追加各种语法高亮声明:
.. code-block:: python
:linenos:
def foo():
print "Love Python, Love FreeDome"
print "E文标点,.0123456789,中文标点,. "
效果:
1 2 3 | def foo():
print "Love Python, Love FreeDome"
print "E文标点,.0123456789,中文标点,. "
|
外部包含:
.. literalinclude:: example.py
:language: python
效果:
#!/usr/bin/env python
#coding:utf-8
print "Hello"
章节¶
章节是文章的主体结构, 分为 标题 章 节 小节 等. 定义章节的方式是在行的下面添加 ‘=======’, 比如:
标题
====
章
--
节
~~
小节
####
说明 [1]:
- ‘====’ 至少和文字行一样长, 更长也行
- 相同级别必须使用统一的符号, 否则会被识别为更小的级别
- = - ~ ` : ‘ ” ^ _ * _ # < > 这些符号都可以, 级别足够多了.
[1] | 由于幻灯片系统的限制, 效果无法在幻灯片内演示 |
标题¶
标题和章节在结构上的作用相同, 但是可能有不同的显示格式. 标题的区别是在章节的上方也加上 ‘====’ 行:
====
标题
====
-----------
第一章 概述
-----------
表格¶
普通表格¶
+------------+------------+-----------+
| Header 1 | Header 2 | Header 3 |
+============+============+===========+
| body row 1 | column 2 | column 3 |
+------------+------------+-----------+
| body row 2 | Cells may span columns.|
+------------+------------+-----------+
| body row 3 | Cells may | - Cells |
+------------+ span rows. | - contain |
| body row 4 | | - blocks. |
+------------+------------+-----------+
普通表格 生成:
Header 1 Header 2 Header 3 body row 1 column 2 column 3 body row 2 Cells may span columns. body row 3 Cells may span rows.
- Cells
- contain
- blocks.
body row 4
简单表格¶
注意: 表格包含中文时,基本无法对齐,,,
===== ===== ======
Inputs Output
------------ ------
A B A or B
===== ===== ======
False False False
True False True
False True True
True True True
===== ===== ======
简单表格 生成:
Inputs Output A B A or B False False False True False True False True True True True True
CSV 表格¶
.. csv-table:: Frozen Delights!
:header: "Treat", "Quantity", "Description"
:widths: 15, 10, 30
"Albatross", 2.99, "On a stick!"
"Crunchy Frog", 1.49, "If we took the bones out, it wouldn't be
crunchy, now would it?"
"Gannet Ripple", 1.99, "On a stick!"
CSV 表格生成:
Treat | Quantity | Description |
---|---|---|
Albatross | 2.99 | On a stick! |
Crunchy Frog | 1.49 | If we took the bones out, it wouldn’t be crunchy, now would it? |
Gannet Ripple | 1.99 | On a stick! |
列表表格¶
.. list-table:: Frozen Delights!
:widths: 15 10 30
:header-rows: 1
* - Treat
- Quantity
- Description
* - Albatross
- 2.99
- On a stick!
* - Crunchy Frog
- 1.49
- If we took the bones out, it wouldn't be
crunchy, now would it?
* - Gannet Ripple
- 1.99
- On a stick!
列表表格 生成:
Treat | Quantity | Description |
---|---|---|
Albatross | 2.99 | On a stick! |
Crunchy Frog | 1.49 | If we took the bones out, it wouldn’t be crunchy, now would it? |
Gannet Ripple | 1.99 | On a stick! |
rST排版技巧¶
跨章节指引¶
行文中,经常要对其它章节进行指引,在 html 中对应的就是 锚点链接
- rST 中提供了非常优雅的解决:
- 使用通用元素定义
- 比如説:
各个章节的首页一般是 index.rst
头一行,习惯性加个聲明:
.. _chapter6index:
那么,在其它任意文本中,随时可以使用:
:ref:`构建 buzz <chapter6index>`
来生成一个指向第二章 首页的链接!
插图/表格指代¶
行文中,经常对指定插图/表格 进行指代
- rST 中提供了非常优雅的解决:
- 进行通用元素定义
- 比如说
.. _fig_0601:
.. figure:: ../_static/figs/magic-2.png
插图 6-1 神奇的2
然后,就可以在任意地方使用 插图 6-1 神奇的2 来指代, 实际输出的就是 “插图 6-1 神奇的2”
上下标号¶
有时要进行数学/化学的表示,在 html 中就需要上/下标( <sub>
, <sup>
) 的表达,
rST 中当然也有:
H\ :sub:`2`\ O
E = mc\ :sup:`2`
效果:
H2O
E = mc2
注解
注意:
这里的 只是为了制造语法空间,输出时,是没有空格的了,,,
段落层次约定¶
使用
共分4级
=======================
大标题
=======================
-----------------------
小标题
-----------------------
^^^^^^^^^^^^^^^^^^^^^^^
二级标题
^^^^^^^^^^^^^^^^^^^^^^^
"""""""""""""""""""""""
三级标题
"""""""""""""""""""""""
再小,就使用列表!:
- 列表项目1
- 列表项目2
- ...
Unix/Linux 常用 shell 命令¶
作者: | 王然 kxxoling@gmail.com |
---|
简介¶
shell 是 Unix/Linux 上常见的用户与计算机的交互接口,根据用户输入执行系统命令。 现如今,主流 Linux 发行版中默认的 shell 多是 bash。
开发服务器上使用的 shell 也是 bash,并安装了一些第三方命令和自己编写的批处理命令。
常用 sh 命令及操作¶
- table 键自动补全
- ls 列出目录
- ls -al 使用格式化列出隐藏文件
- pwd 显示当前目录
- cd <dir> 切换到 dir 目录
- cd 切换到 home 目录
- cd .. 切换到父目录
- mkdir <dir> 创建目录
- touch <file> 创建文件
- cat <file> 显示文件内容
- less <file> 逐页显示文件内容
- more <file>
- head <file> 显示文件头 10 行
- tail <file> 显示文件后 10 行
- tail -f <file> 从后 10 行开始查看文件内容
- ctrl+c 结束程序
- ctrl+z 停止当前程序,可使用 fg 恢复
- ctrl+w 删除当前行中文字
- ctrl+u 删除整行文字
- ctrl+a/e 将光标移动至行首/尾
- ctrl+r 搜索最近使用的命令
- bg 列出已停止或者后台程序
- fg 将最近作业带到前台
- locate <file> 查找某个文件所在位置
常用第三方命令¶
tree 以树形显示当前目录结构
- tree 以树形结构显示当前目录下所有文件和目录
- tree -d 仅显示目录
- tree -L <num> 限制目录的最大深度
ag 搜索
- ag <something> 在目录所有文件中寻找 something
- ag <something> <–python> 在所有 Python 文件中搜索 something
autojump
- j <dir> 根据最近工作目录记录跳转到最合适的位置。
VPS 开发服务器初始配置¶
作者: | 王然 kxxoling@gmail.com |
---|
注:部分内容已失效
将域名配置到 DNSPOD¶
首先需要注册一个 DNSPOD 账号,并拥有一个未使用的一级域名,没有的话需要在域名提供商 (比如 GoDaddy )那里购买。
- 在 DNSPOD 中添加你已注册的域名信息
- 添加一级域名记录以及泛域名记录,并指向你的 VPS IP
- 在域名购买商那里将域名解析服务器修改为 DNSPOD 提供的域名解析服务器
配置 VPS¶
根据邮件提示以 root 用户登录 VPS(ssh root@your.domain),系统已为你创建了一个叫做 zz 的用户,现在为他创建密码::
passwd zz
根据提示完成后退出 ssh。
接下来配置无密码登录 VPS。首次使用 ssh 密钥登录需要在本地创建 ssh 密钥:
Mac & Linux: ssh-keygen
,该命令会在 home 目录 .ssh 文件夹中创建两个文件:
id_rsa 和 id_rsa.pub。形式如下:
将密钥拷贝到服务器:
Linux
`ssh-copy-id zz@your.domain`
Mac 下等价命令
`cat ~/.ssh/id_rsa.pub | ssh zz@your.domain "mkdir ~/.ssh; cat - >> authorized_keys"`
windows用户可以参考 xshell 客户端 配置xshell
配置开发环境¶
使用 zz 用户登录 VPS,并在本地生成密钥 ssh-keygen
将 pub
中全部内容(公钥)复制到 BitBucket
。 https://bitbucket.org/account/user/youritbucket-b-id/ssh-keys/。
fork 42web 源代码
修改 ~/.hgrc 文件,在此设置全局用户名&邮箱
修改 ~/42web/.hg/hgrc 文件,修改修改为如下:
[paths]
default = ssh://hg@bitbucket.org/your-bitbucket-id/42web
zsp = ssh://hg@bitbucket.org/zuroc/42web
- 接下来将代码更新到最新(要求当前目录在 hg 版本控制的目录)::
- hg fetch zsp
如何 pull request
运行初始化脚本¶
在 ~/42web/zapp/SITE/misc/once 目录中运行脚本 ./init.sh (~/42web/zapp/SITE/misc/once/init.sh )
在 ~/42web/zapp/SITE/misc/config/_host/主机名.py 文件修改为如下内容,并注意将 HOST 修改为自己的域名:
import _env
from z42 import config
def prepare(o):
config.SMTP.SENDER = config.SMTP.USERNAME = 'postmaster@42.sendcloud.org'
config.SMTP.PASSWORD = '密码见Google Docs'
config.SMTP.HOST = 'smtpcloud.sohu.com'
config.HOST = "hi-acg.com"
config.MYSQL_PASSWORD = "密码见Google Docs"
config.MYSQL_HOST = "127.0.0.1"
config.MYSQL_USER = "zz"
def finish(o):
pass
因为用户配置的优先级 > 主机配置 > 全局
启动开发脚本,首次运行会比较缓慢。运行完成后请勿关闭此脚本:
~/42web/zapp/SITE/dev.sh
如开发过程中涉及到邮件功能,需要启另外一个脚本:
python ~/42web/zapp/SITE/model/gearman/server/run.py
(如需要启动 Gearman 请输入 sudo service gearmand restart
)
配置数据库¶
在 42web/zapp/SITE/misc/backup/mysql/
目录下运行以下语句修改数据库:
mysql -h127.0.0.1 -uzz -prstfsgbcedh zz_42web < zz_42web.sql
配置 SMTP¶
修改配置文件中的邮件服务器配置。
全局配置:42web/z42/config/default.py 个人配置:42web/zapp/SITE/misc/config/_host/主机名.py
如个人配置与全局配置冲突,个人配置将覆盖全局配置。可以在 42web 目录下运行 ipython
,并输入
from z42.config import SMTP; print SMTP.HOST; print SMTP.PASSWD
测试是否覆盖配置成功。
最后,修改 42web/z42/web/smtp.py 中的邮箱并运行,测试是否配置成功。
配置 phpMyAdmin 访问域名¶
修改文件 /etc/nginx/config/phpmyadmin.conf
,将其中 server_name 修改为自己想用的二级域名,比如 admin.hi-acg.com。
安装 RockMongo¶
下载 RockMongo 源代码:
sudo git clone https://github.com/iwind/rockmongo.git /var/www/rockmongo
会将源代码下载在 /var/www 目录。
下载依赖:
sudo emerge =dev-php/pecl-mongo-1.5.1 --autounmask-write
sudo etc-update
-3
y
sudo emerge =dev-php/pecl-mongo-1.5.1
添加配置文件: sudo vi /etc/nginx/conf/rockmongo.conf
并添加以下内容:
server{
listen 80;
server_name mongo.kanrss.com; #这里修改为自己的域名
index index.php;
root /var/www/rockmongo;
location ~ \.php$ {
root /var/www/rockmongo;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include /etc/nginx/fastcgi.conf;
include fastcgi_params;
}
}
再修改 rockmongo 配置文件 /var/www/rockmongo/config.php 中变量 $MONGO[“servers”][$i][“mongo_auth”] 和 $MONGO[“servers”][$i][“control_auth”] 为 false,以配置 rockmongo 无密码登录。
重新启动 php-fpm :sudo service php-fpm restart
Nginx 重新加载文件:sudo service nginx reload
开发工具¶
hg 简明教程¶
作者: 王然 kxxoling@gmail.com
关于 hg¶
hg 即 Mercurial,是一个跨平台的分布式版本控制软件,主要由Python语言实现, 但也包含一个用C语言实现的二进制比较工具。其使用方式即原理与 git 相似, 如果你已经有 git 使用经验,可以访问 git 和 hg 面对面
hg 基本流程¶
以 42web https://bitbucket.org/z42/z42 为例,演示 hg 开发流程。
- 从远程仓库复制到本地
https 协议从远程仓库获取代码:
hg clone https://bitbucket.org/z42/z42
或者也可以通过 ssh 协议:
hg clone ssh://hg@bitbucket.org/z42/z42
添加新创建的文件:
hg add file_name
修改本地代码并提交
保存修改后,提交本地代码::
hg commit -m "change log"
或者也可以简写为::
hg ci -m "change log"
-m 表示关于本次提交的相关信息
commit 时 hg 会自动 add 代码库中已修改的文件。
提交到远程仓库前,首先检查远程代码状态
可以使用 hg diff branches 查看不同分支间差异
使用 hg fetch 命令从其它分支拉取代码并合并,如合并代码出现问题, 需要手动合并后再提交。
将代码提交到远程仓库:
hg push
发起 pull request
在 https://bitbucket.org/你的用户名/项目名/pull-request/new 发起一个新的 pull request
解决冲突¶
在 fetch 他人代码的时候,时常会遇到合并冲突的问题,因为有可能两人同时修改了同一个文件,这时需要先解决冲突(直接修改有冲突的文件),解决冲突后将其标注为已解决:
hg resolve -m file.name
Tips¶
- 向版本库添加/删除文件
hg add/rm
- 移动版本库中的文件
hg mv
- 查找某段代码的责任人
hg blame
- 从现有代码初始化版本仓库
hg init
- 建立 hg 服务器
hg serve
- 更新代码库至最新提交
hg update
- 切换至分支
hg update -r
- 放弃所有修改,返回至上一个提交
hg update -C
- 搜索
hg grep
- 放弃某个文件的修改
hg revert
分支命名规则¶
命名示例: * bug/index_page * feature/founder_page
分支的目的如果是 bug 修复以 bug/
作为开头;同理,新需求则以
feature/
开头。这样能够明显地区分需求与 bug,并且以 /
为分隔符能够得到 SourceTree 这样的图形化版本控制工具更好的支持。
分支名中不需要添加创建者,因为一个分支通常会有多个开发者(一个前端一个后端)同时使用。
IPython 用法¶
作者: | 王然 kxxoling@gmail.com |
---|
启动¶
启动IPython就是运行可执行文件ipython。你会看到一个提示符,如果你曾经玩过标准Python命令行提示符,你会发现这个有点儿不同:
[jjones@cerberus ~]$ /usr/local/python24/bin/ipython
Python 2.4 (#2, Nov 30 2004, 09:22:54)
Type "copyright", "credits" or "license" for more information.
IPython 0.6.6 -- An enhanced Interactive Python.
? -> Introduction to IPython's features.
%magic -> Information about IPython's 'magic' % functions.
help -> Python's own help system.
object? -> Details about 'object'. ?object also works, ?? prints more.
In [1]:
要退出IPython(Linux系统上)就输入Ctrl-D(会要求你确认),也可以输入Exit或Quit(注意大小写)退出而不需要确认。
特性¶
Magic¶
IPython有一些”magic”关键字:
%Exit, %Pprint, %Quit, %alias, %autocall, %autoindent, %automagic,
%bookmark, %cd, %color_info, %colors, %config, %dhist, %dirs, %ed,
%edit, %env, %hist, %logoff, %logon, %logstart, %logstate, %lsmagic,
%macro, %magic, %p, %page, %pdb, %pdef, %pdoc, %pfile, %pinfo, %popd,
%profile, %prun, %psource, %pushd, %pwd, %r, %rehash, %rehashx, %reset,
%run, %runlog, %save, %sc, %sx, %system_verbose, %unalias, %who,
%who_ls, %whos, %xmode
IPython 会检查传给它的命令是否包含magic关键字。如果命令是一个magic关键字,IPython就自己来处理。如果不是magic关键字,就交给 Python(标准解释器)去处理。如果automagic打开(默认),你不需要在magic关键字前加%符号。相反,如果automagic是关闭的,则%是必须的。在命令提示符下输入命令magic就会显示所有magic关键字列表以及它们的简短的用法说明。良好的文档对于一个软件的任何一部分来说都是重要的,从在线IPython用户手册到内嵌文档(%magic),IPython当然不会在这方面有所缺失。
Tab自动补全¶
IPython一个非常强大的功能是tab自动补全。如果你对Python很了解,可能会想,标准Python交互式解释器也可以tab自动补全啊。你要做的只是:
[jjones@cerberus ~]$ /usr/local/python24/bin/python
Python 2.4 (#2, Nov 30 2004, 09:22:54)
[GCC 3.4.2 20041017 (Red Hat 3.4.2-6.fc3)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import rlcompleter, readline
>>> readline.parse_and_bind('tab: complete')
>>>
是的,标准Python交互式解释器和IPython都支持“普通”自动补全和菜单补全。使用自动补全,你要先输入一个匹配模型,然后按Tab键。如果是“普通”自动补全模式(默认),Tab后会:
- 匹配模型按最大匹配展开。
- 列出所有匹配的结果。
例如:
In [1]: import os
In [2]: os.po
os.popen os.popen2 os.popen3 os.popen4
In [2]: os.popen
输入os.po然后按Tab键,os.po被展开成os.popen(就象在In [2]:提示符显示的那样),并显示os所有以po开头的模块,类和函数,它们是popen,popen2, popen3和popen4。
- 菜单补全稍有不同。关闭默认Tab补全,使用菜单补全,你需要修改配置文件$HOME/.ipython/ipythonrc。注释掉:
- readline_parse_and_bind tab: complete
- 取消注释:
- readline_parse_and_bind tab: menu-complete
不同于“普通”自动补全的显示当前命令所有匹配列表,菜单补全会随着你每按一次Tab键而循环显示匹配列表中的项目。例如:
In [1]: import os
In [2]: os.po
结果是:
In [3]: os.popen
接下来每次按Tab键就会循环显示匹配列表中的其它项目:popen2,popen3,popen4,最后回到po。菜单补全模式下查看所有匹配列表的快捷键是Ctrl-L:
In [2]: os.po
os.popen os.popen2 os.popen3 os.popen4
In [2]: os.po
自省¶
Python有几个内置的函数用于自省。IPython不仅可以调用所有标准Python函数,对于那些Python shell内置函数同样适用。典型的使用标准Python shell进行自省是使用内置的dir()函数:
>>> import SimpleXMLRPCServer
>>> dir(SimpleXMLRPCServer.SimpleXMLRPCServer)
['__doc__', '__init__', '__module__', '_dispatch',
'_marshaled_dispatch', 'address_family', 'allow_reuse_address',
'close_request', 'fileno', 'finish_request', 'get_request',
'handle_error', 'handle_request', 'process_request',
'register_function', 'register_instance',
'register_introspection_functions', 'register_multicall_functions',
'request_queue_size', 'serve_forever', 'server_activate', 'server_bind',
'server_close', 'socket_type', 'system_listMethods',
'system_methodHelp', 'system_methodSignature', 'system_multicall',
'verify_request']
嗯,非常棒。事实上非常实用。几年来我一直这么做,对此非常满意。这是一个漂亮的列表,包含了 SimpleXMLRPCServer.SimpleXMLRPCServer的所有方法,类,模块等等。因为dir()是一个内置函数,在 IPython中也能很好的使用它们。但是IPython的操作符?和??功能还要强大:
In [1]: import SimpleXMLRPCServer
In [2]: ? SimpleXMLRPCServer.SimpleXMLRPCServer
Type: classobj
String Form: SimpleXMLRPCServer.SimpleXMLRPCServer
Namespace: Interactive
File: /usr/local/python24/lib/python2.4/SimpleXMLRPCServer.py
Docstring:
Simple XML-RPC server.
Simple XML-RPC server that allows functions and a single instance
to be installed to handle requests. The default implementation
attempts to dispatch XML-RPC calls to the functions or instance
installed in the server. Override the _dispatch method inherited
from SimpleXMLRPCDispatcher to change this behavior.
Constructor information:
Definition: SimpleXMLRPCServer.SimpleXMLRPCServer(self, addr,
requestHandler=, logRequests=1)
? 操作符会截断长的字符串。相反,?? 不会截断长字符串,如果有源代码的话还会以语法高亮形式显示它们。
历史¶
当你在IPython shell下交互的输入了大量命令,语句等等,就象这样:
In [1]: a = 1
In [2]: b = 2
In [3]: c = 3
In [4]: d = {}
In [5]: e = []
In [6]: for i in range(20):
...: e.append(i)
...: d[i] = b
...:
你可以快速查看那些输入的历史记录:
In [7]: hist
1: a = 1
2: b = 2
3: c = 3
4: d = {}
5: e = []
6:
for i in range(20):
e.append(i)
d[i] = b
要去掉历史记录中的序号(这里是1至6),使用命令hist -n:
In [8]: hist -n
a = 1
b = 2
c = 3
d = {}
e = []
for i in range(20):
e.append(i)
d[i] = b
这样你就可以方便的将代码复制到一个文本编辑器中。要在历史记录中搜索,可以先输入一个匹配模型,然后按Ctrl-P。找到一个匹配后,继续按Ctrl-P会向后搜索再上一个匹配,Ctrl-N则是向前搜索最近的匹配。
编辑¶
当在Python提示符下试验一个想法时,经常需要通过编辑器修改源代码(甚至是反复修改)。在IPython下输入edit就会根据环境变量$EDITOR调用相应的编辑器。如果$EDITOR为空,则会调用vi(Unix)或记事本(Windows)。要回到IPython提示符,直接退出编辑器即可。如果是保存并退出编辑器,输入编辑器的代码会在当前名字空间下被自动执行。如果你不想这样,使用edit -x。如果要再次编辑上次最后编辑的代码,使用edit -p。在上一个特性里,我提到使用hist -n可以很容易的将代码拷贝到编辑器。一个更简单的方法是edit加Python列表的切片(slice)语法。假定hist输出如下:
In [29]: hist
1 : a = 1
2 : b = 2
3 : c = 3
4 : d = {}
5 : e = []
6 :
for i in range(20):
e.append(i)
d[i] = b
7 : %hist
现在要将第4,5,6句代码导出到编辑器,只要输入:
edit 4:7
Debugger接口¶
IPython 的另一特性是它与Python debugger的接口。在IPython shell下输入magic关键字pdb就会在产生一个异常时自动开关debugging功能。在自动pdb呼叫启用的情况下,当Python遇到一个未处理的异常时Python debugger就会自动启动。你在debugger中的当前行就是异常发生的那一行。IPython的作者说有时候当他需要在某行代码处debug时,他会在开始debug的地方放一个表达式1/0。启用pdb,在IPython中运行代码。当解释器处理到1/0那一行时,就会产生一个 ZeroDivisionError异常,然后他就在指定的代码处被带到一个debugging session中了。
运行¶
有时候当你在一个交互式shell中时,如果可以运行某个源文件中的内容将会很有用。运行magic关键字run带一个源文件名就可以在IPython解释器中运行一个文件了(例如run <源文件> <运行源文件所需参数>)。参数主要有以下这些:
-n 阻止运行源文件代码时__name__变量被设为”__main__”。这会防止
if __name__ == "__main__":
块中的代码被执行
-i 源文件就在当前IPython的名字空间下运行而不是在一个新的名字空间中。如果你需要源代码可以使用在交互式session中定义的变量就会很有用。
-p 使用Python的profiler模块运行并分析源代码。使用该选项代码不会运行在当前名字空间。
宏¶
宏允许用户为一段代码定义一个名字,这样你可以在以后使用这个名字来运行这段代码。就象在magic关键字edit中提到的,列表切片法也适用于宏定义。假设有一个历史记录如下:
In [3]: hist
1: l = []
2:
for i in l:
print i
你可以这样来定义一个宏:
In [4]: macro print_l 2 Macroprint_l
created. To execute, type its name (without quotes). Macro contents: for i in l: print i
运行宏:
In [5]: print_l
Out[5]: Executing Macro...
在这里,列表l是空的,所以没有东西被输出。但这其实是一个很强大的功能,我们可以赋予列表l某些实际值,再次运行宏就会看到不同的结果:
In [6]: l = range(5)
In [7]: print_l
Out[7]: Executing Macro...
0
1
2
3
4
当运行一个宏时就好象你重新输入了一遍包含在宏print_1中的代码。它还可以使用新定义的变量l。由于Python语法中没有宏结构(也许永远也不会有),在一个交互式shell中它更显得是一个有用的特性。
环境(Profiles)¶
就象早前提到的那样,IPython安装了多个配置文件用于不同的环境。配置文件的命名规则是ipythonrc-。要使用特定的配置启动IPython,需要这样
ipython -p
一个创建你自己环境的方法是在$HOME/.ipython目录下创建一个IPython配置文件,名字就叫做ipythonrc- ,这里是你想要的环境的名字。如果你同时进行好几个项目,而这些项目又用到互不相同的特殊的库,这时候每个项目都有自己的环境就很有用了。你可以为每个项目建立一个配置文件,然后在每个配置文件中import该项目中经常用到的模块。
使用操作系统的Shell¶
使用默认的IPython配置文件,有几个Unix Shell命令(当然,是在Unix系统上),cd,pwd和ls都能象在bash下一样工作。运行其它的shell命令需要在命令前加!或!!。使用magic关键字%sc和%sx可以捕捉shell命令的输出。
pysh环境可以被用来替换掉shell。使用-p pysh参数启动的IPython,可以接受并执行用户$PATH中的所有命令,同时还可以使用所有的Python模块,Python关键字和内置函数。例如,我想要创建500个目录,命名规则是从d_0_d到d_500_d(译注:呵呵,作者这里犯了个小小的计算错误,你能看出来吗),我可以使用-p pysh启动IPython,然后就象这样:
jjones@cerberus[foo]|2> for i in range(500):
|.> mkdir d_${i}_d
|.>
这就会创建500个目录:
jjones@cerberus[foo]|8> ls -d d* | wc -l
500
注意这里混合了Python的range函数和Unix的mkdir命令。
注意,虽然ipython -p pysh提供了一个强大的shell替代品,但它缺少正确的job控制。在运行某个很耗时的任务时按下Ctrl-z将会停止IPython session而不是那个子进程。
问题和方法¶
虽然作为标准Python shell的替换,IPython总的来说很完美。还是有两个问题给我带来了一些麻烦。感谢IPython的开发者,这两个问题都可以通过配置来解决,每个配置都有清晰的文档。
第一个问题是关于颜色的。在我的一个系统上,我使用的是一个白色背景的xterm。当我使用?和??查询一个对象或模块的信息时,对象的定义会被显示,但看起来好象那些参数丢失了。那是因为在构造函数中的的参数默认显示为白色。我的解决办法是在IPython shell中输入colors LightBG。
第二个问题是关于自动缩进和代码粘贴的。如果autoindent被启用,IPython会对我粘贴的已排好缩进的代码再次应用缩进。例如下面的代码:
for i in range(10):
for j in range(10):
for k in range(10):
pass
会变成:
for i in range(10):
for j in range(10):
for k in range(10):
pass
在这里它并不是个问题,因为在它自身中缩进都保持一致。在其它一些情况下(例子一下子举不出来了),可能会成为真正的问题。可以使用magic关键字autoindent来开关自动缩进,告诉IPython不要添加多余的缩进──就象在vim中设置粘贴set paste一样。
结论¶
IPython 并不是囗囗性的,也不是完全创新的。Tab自动补全,历史记录搜索,配置环境,配置文件等都早已在其它shells中存在有些年头了。Python拥有各种级别的自省能力也有一段时间了。但IPython把来自成熟的Unix shell,标准Python shell以及Python语言中的一些最强大的功能整合到了一起。产生出了一个强大的令人难以置信的性能增强工具,我想我会很乐意在接下来的几年中一直使用它。套用阿基米德的话来说,给我一个强大而又灵活的文本编辑器(vim),一个交互式shell(IPython)以及一个语言(Python),我就能撬动整个世界。
其它开发工具¶
- 开发工具
- bitbucket
- iTerm2
- xshell
- filezilla
- Grunt
- Firefox
- firebug
- scrapbook
- sip(Mac)
- Postman
vim 快速入门¶
作者: | 王然 kxxoling@gmail.com |
---|
vim 简介¶
在这个蔚蓝色的星球上,流传着两大神器的传说:Emacs是神的编辑器,而Vim是编辑器之神。
VIM , 全称 Vi Improved , Vi的增强版 。
Vi 在 1976 年发布,奉行 Unix 传统的“Do one thing and do it well”哲学,每个程序只做一件事但做到最好,通过程序之间的配合得到强大的功能。
Emacs则奉行“Everything at reach”设计哲学,通过强大的扩展性,达到在一个软件里做所有的事。Emacs可以用来编辑文档、时间管理、浏览图片、阅读pdf、听音乐、写程序、运行程序、调试程序、接受发送邮件、看新闻组、玩游戏、管理系统、Telnet/FTP、版本控制、写LaTex…被称为“伪装成编辑器的操作系统”。
江湖中有一句话: “ 世界上的程序员分三种,一种使用Emacs,一种使用Vim,剩余的是其它” 。
基本概念¶
Vim 有两种模式——Normal 模式和 Insert 模,所有命令都是在 Normal 模式下执行。启动 Vim 后,默认进入 Normal 模式,
可以按 i
键进入 Insert 模式,或者 s
删除当前字符并进入 Insert 模式,退出 Insert 模式进入 Normal 按 ESC
。
下面的教程中约定 + 表示同时按其左右的按键,小写字母(如 i)表示按该字母一次,大写字母(如 G)表示同时按 shift+g。
基本用法¶
- i insert 输入
- v 行选中
- ctrl+v 列选中
- G 至文末
- gg 至文首
- :q 未修改退出
- :q! 强制不保存退出
- :x / :wq 保存并退出
- J 合并多行
- d 删除当前所选
- dd 删除多行并存在剪贴板中(剪切)
- y 复制当前所选
- yy 复制整行
- p 粘贴
- u 撤销操作
- w 光标移动到下一个单词处
- b 光标移动到上一个单词处
- ^ 光标移动到行首
- $ 光标移动到行尾
- kjhl 或者上下左右键移动光标
- shift+上下键 翻页
- shift+左右 光标乙至上/下一个单词(以空格/标点区分单词)词首
- u 撤销上一步操作
- zo/zn/zc 折叠/展开代码块
- :vsp 新建工作区
- ctrl+w 松手后再按
方向键
切换工作区 - :MR 选择最近打开的文件(需安装插件)
- F12 运行当前文件
- # 搜索光标处短语
- :set paste 进入粘贴模式
- :%s/target/something/g 替换全部 target 字段
- :s/target/something/g 替换选中区域 target 字段
如何配置¶
进阶文档¶
vim名词解释¶
模式¶
vim有5中基本模式,分别是
- Normal Mode 也就是最一般的普通模式,默认进入vim之后,处于这种模式。
- Visual Mode 一般译作可视模式,在这种模式下选定一些字符、行、多列。 在普通模式下,可以按v进入。
- Insert Mode 插入模式,其实就是指处在编辑输入的状态。普通模式下,可以按i进入。
- Select Mode 在gvim下常用的模式,可以叫作选择模式吧。用鼠标拖选区域的时候,就进入了选择模式。 和可视模式不同的是,在这个模式下,选择完了高亮区域后,敲任何按键就直接输入并替换选择的文本了。 和windows下的编辑器选定编辑的效果一致。普通模式下,可以按gh进入。 ps:这种模式好无用啊
- Command-Line/Ex Mode 就叫命令行模式和Ex模式吧。两者略有不同,普通模式下按冒号(:)进入Command-Line模式,可以输入各种命令, 使用vim的各种强大功能。普通模式下按Q进入Ex模式,其实就是多行的Command-Line模式。 ps:经常使用EX模式的都是神阶vimer
注:本文中所说的快捷键若无特殊说明则是Normal Mode下的模式
Windows/窗口¶
vim可以将窗口分成好多个独立的块来显示不同的文件,我们把这些块叫做窗口。当然你可以选择竖着分或者横着分,横着分的叫做split window,竖着分的叫做vsplit window。
Tab/标签页¶
就像chrome的标签页一样。
Buffer/缓冲区¶
缓冲区(Buffer)是一块内存区域,里面存储着正在编辑的文件。如果没有把缓冲区里的文件存盘,那么原始文件不会被更改。 可以通过:ls或:buffer命令查看缓冲区
插件¶
Vundle插件管理器¶
Vundle的功能是用于安装和管理其他插件,它能够直接从github上下载并自动安装置顶的插件。其本身也托管在github上,我们可以使用下面的命令快捷的安装它。
git clone https://github.com/gmarik/Vundle.vim.git ~/.vim/bundle/Vundle.vim
然后只需要在.vimrc文件中写入要安装的插件然后在vim中运行Vundle的插件安装命令就可以自动下载安装指定的插件了。 更详细的使用方法可参考Vundle的文档。
MRU最近打开的文件¶
MRU的功能是从底部弹出一个最近打开的插件列表,其默认启动命令是:MRU,为了使用方便我将其设为mr。
nerdtree文件目录树¶
nerdtree是一个用于显示目录树的工具默认启动方式是:NERDtree,好难打的样子,所以我把它设成了nt。
关于这个插件有一个非常实用的设置是它可以忽略指定类型的文件,例如我们希望将所有的pyc或者其他没用的文件从目录树中过滤调的时候就可以使用它的这个功能,就像这样
let NERDTreeIgnore=['\.pyc$', '\~$']
它在github上的readme比较渣,没有介绍什么具体的用法和功能,我这里列出一些我用过的,还有一些大家可以通过:help Nerdtree查看。
- o.......打开文件并将焦点移动到打开的文件或展开当前文件夹
- Enter...跟o一样
- go......跟o一样,但将焦点留在NerdTree
- t.......在新tab中打开文件
- T.......同t,但保留焦点
- i.......在一个新的 split window中打开文件
- gi......同i,保留焦点
- s.......在新的 vsplit 窗口打开文件
- gs......同s保留焦点
- O.......递归打开当前文件夹
- x.......关闭当前文件夹的父文件夹
- X.......递归关闭当前文件夹
- P.......跳到根目录
- p.......跳到当前目录的父目录
- q.......退出NerdTree
CtrlP模糊搜索文件¶
CtrlP是一个用于模糊搜索文件的插件,其文档比较健全看看它的readme就能学会其用法,而且其默认启动快捷键就是Ctrl+p。
其跟NerdTree一样,也可以在split(Ctrl+s)和vsplit(Ctrl+v)窗口以及新tab(Ctrl+t)打开文件。
还有一个使用的设置就是忽略指定类型文件,像这样
let g:ctrlp_custom_ignore = {
\'file' : '\v\.(pyc|html\.py)$',
\}
ag和CtrlSF¶
ag是一个linux下非常好用的代码搜索工具(代码在github上需要手动安装),它可以快速搜索你的代码内容。vim的ag插件允许我们在vim中使用ag命令搜索代码,CtrlSF插件跟ag插件的不同在于前者可以显示代码的上下文,显然是CtrlSF更为强大。
CtrlSF的默认命令就是:CtrlSF,然后输入要搜索的字符再敲回车。好难打,好难用,所以我设置了下面的快捷键:
nmap <C-S>f :CtrlSF
nmap <C-S>o :CtrlSFOpen<CR>
nmap ss :CtrlSF <C-R><C-W><CR>
vnoremap ss y:CtrlSF <C-R>"<CR>
- Ctrl+s+f................适用于normal模式,就跟:CtrlSF一样
- Ctrl+s+o................适用于normal模式,打开搜索结果的窗口
- ss......................适用于normal模式,搜索当前光标所在的单词
- ss......................适用于visual模式,搜索当前选中的文字
tpope/vim-commentary 批量注释¶
这货可以批量注释代码,就像eclipse的Ctrl+j一样。当然你以可以使用选中再批量插入的方式开实现批量注释,但你需要按5个键(Ctrl,v,Shift,I,Est)而commentry只需三个键就可以了。
首先,我们设个快捷键以及将python的注释符设为#
vnoremap <Backspace> :Commentary <CR>
autocmd FileType python set commentstring=#\ %s
这样在可视模式选中要注释的内容后可以按退格键批量注释,再次选中按退格键就解除注释。
Syntastic语法检查¶
该插件的功能是检查和标记语法错误及不规范的问题,在我们的项目下
supertab,补全插件¶
vim-coffee-script,CoffeeScript语法高亮¶
mako.vim,mako语法高亮¶
vim-mercenary 支持hg blame和diff¶
vim-colors-solarized 漂亮的颜色主题¶
luochen1990/rainbow 彩虹括号,匹配的括号显示为同一颜色¶
godlygeek/tabular 自动对齐¶
hynek/vim-python-pep8-indent python自动缩进¶
indentLine垂直缩进对齐线¶
MatchTag高亮显示匹配的html标签¶
移动¶
- :[n] 移动光标当第n行。
- H,M,L 分别移动光标到当前屏幕首行,中间行和尾行。
- Ctrl+f和Ctrl+b向下和向上翻页,相当于pageup和pagedown。
- h,j,k,l向左下上右移动一个字符。
- f和F加字符,将光标移动到下一个或上一个该字符的位置,例如fa会将光标移动到下一个a的位置。
- m设定标记,`跳转到指定标记。例如可以用ma在某行设定标记,再使用`a跳转到改行。
- shift+左右 光标移至上/下一个单词(以空格/标点区分单词)词首。
- w 光标移动到下一个单词处
- b 光标移动到上一个单词处
- ^ 光标移动到行首
- $ 光标移动到行尾
插入¶
- a和i分别在当前字符前和后插入。
- A和I分别在当前行尾和行首插入。
- 批量插入。首先在可视模式下选中要插入的行,然后按I可在选中处之前批量插入字符
复制、粘贴、替换和删除¶
- r可以替换当前字符。
- yy和dd可以分别复制和剪切当前行。
- y2y和d2d可以分别复制和剪切当前行开始的2行。
- :3,8y和:3,8d可以分别复制和剪切第3到第8行。
- yw和dw可以分别复制和剪切光标所在的单词。
- d(可视模式) 删除当前所选
- dd 删除多行并存在剪贴板中(剪切)
- y 复制当前所选
- p 粘贴
分屏相关¶
- :vsp和:sp分别竖着和横着分割当前窗口。
- Ctrl + v和Ctrl + s也可以竖向和横向分屏。
- Ctrl + w + 箭头键(hjkl)在不同窗口键移动。
- Ctrl + = 将所有的窗口大小调成相同大。
查找和替换¶
- / + 要搜索的内容搜索。
- n和N跳到下一个或上一个搜索结果。
- # 搜索当前光标所在的单词。
折叠代码¶
- zc,zC,zo,zO折叠或打开折叠当前行的代码,其中大写Z和O表示折叠或打开折叠所有层。
- zn,zm折叠或打开折叠当前文件的所有代码。
定制的快捷键¶
- F12..................运行python文件或使用zencode补全html
- F11..................格式化代码
- F5,F6,F7,F8..........调整窗口大小
- Ctrl+s+f.............使用ag搜索
- Ctrl+s+o.............打开ag搜索结果
- ss...................使用ag搜索光标所在的单词
- ss(可视模式).........搜索选中的单词
- Backspace(可视模式)..注释/解除注释代码
- nt...................打开NerdTree
- mr...................打开MRU
- tl...................打开taglist
- bn...................打开下一个buffer
- bp...................打开上一个buffer
其他¶
- u和CTRL+r分别是undo和redo的功能。
- :set nu和:set nonu分别为显示和不显示行号。
- Shift + < 或 >分表表示向左或向右缩进一层,也可以选中后批量缩进。
- n + Shift + < 或 >可批量缩进n层。
- i insert 输入
- v 行选中
- ctrl+v 列选中
- :q 未修改退出
- :q! 强制不保存退出
- :x / :wq 保存并退出
- J 合并多行
- shift+上下键 翻页
- :set paste 进入粘贴模式
- :%s/target/something/g 替换全部 target 字段
Vim 实用技巧¶
http://segmentfault.com/q/1010000000166577 文字
vim-multiple-cursors Sublime Text 支持多个光标选择功能,在重构时非常有用。这个插件将 Sublime Text 中的这个邪恶功能引入了 Vim。想要修改变量名时,只需要将光标放在变量名内,然后多次敲击 Ctrl + n,即可将多个同名变量选中,此时再按 s 就能同时将这些变量重命名了。
xshell 客户端¶
Xshell : 极好用的免费SSH客户端¶
创建session¶
安装好xshell后,打开软件,点击菜单栏“File”中的“new”,将出现下图所示弹窗,填写相应信息。其中Host为邮件中所给的主机ip地址(name栏可以不用修改,但一般为便于在xshell中区分不同的主机,自己一般会修改为“用户名@主机”,也可以用“用户名@42qu”),然后点击“ok”。
登录¶
在随后弹出的弹窗中选择自己创建的帐号,点击“connect”,在弹出窗口中输入邮件中提供的用户名,新窗口中选择“keyboard Interactive”
并确定,最后输入邮件中提供的密码,即可登录到自己的vps中。
配置密钥登录 , 无需每次输入密码¶
为避免每次登录vps都需要重复输入用户名和密码的步骤,可以通过生成.ssh/authorized_keys来减少麻烦。
执行:
cd ~
命令,来到home(家)目录
执行:
ssh-keygen
命令 , 然后按两次回车, 生成密钥
执行:
cd .ssh
进入.ssh目录
执行:
cat id_rsa.pub >> authorized_keys
将把当前目录下
id_rsa.pub中的数据拷贝一份到新建的authorized_keys档案中。
点击导航中的“new file transfer”图标,如下图所示。
弹出窗口中忽视警告,确定后输入密码,在.ssh目录下执行“get id_rsa”命令,id_rsa将被保存到下图红线所示的本地目录中。
在xshell菜单栏中依次点击“File”->“open”,选中你的session用户,并点击“Properties”,如下图所示。
做下图所示修改,点击“Browse”按钮。
点击import按钮,选择id_rsa,之后一路确定,再次登录是就可以不用再输入用户名和密码了。
克隆代码¶
重新登录后,为了方便学习各种命令; 我们可以首先克隆一份 42qu.com 的源代码, 执行:
hg clone https://bitbucket.org/zuroc/zpage
等上十分钟 , 会在当前目录下生成新目录zpage,其中包括了项目的所有代码,如图所示。
安装 virtualenv¶
首先运行
virtualenv .
然后修改 ~/.bash_profile 如下
[[ -f ~/.bashrc ]] && . ~/.bashrc
export PATH=$HOME/bin:$HOME/sbin:$PATH:/usr/sbin:/sbin
再运行
source ~/.bash_profile
再运行
pip install setuptools --upgrad
然后就可以使用 pip 或者 easy_install 安装python的库了
天使汇移动组¶
SSO¶
SSO App 示例¶
注册 App¶
注册脚本如下:
import requests
def get_token():
host = 'b.dev' # App 域名
app_name = 'test app' # App 名
sso_host = 'sso.%s' % host # App 的 SSO 域名
sync_url = 'http://%s/sso_sync' % host # 数据同步接口
login_url = 'http://%s/sso_login' % host # 登录回调接口
r = requests.get(SSO_REGISTER_URL, params=dict(
o='["%s","%s","%s","%s","%s"]'
% (app_name, host, sso_host, sync_url, login_url)))
return r.text
if __name__ == '__main__':
print get_token()
注册成功则会获得这样的结果:
[9912683,"VlO9Yt0J_fTFRxrEONVY6s4JZCK2myxwGTeNxfw7Dh-O4cx9WsHMUvDFJQOWtKks"]
其中 9912683
是应用的
app_id
,VlO9Yt0J_fTFRxrEONVY6s4JZCK2myxwGTeNxfw7Dh-O4cx9WsHMUvDFJQOWtKks
是 App 的身份认证 token。
身份验证¶
单点登录系统(SSO)使用教程¶
概念介绍¶
SSO(Single Sign-on)单一登录系统,用于实现不同软件系统中的用户信息同步。
本 SSO 系统通过 JSONP 实现跨域名登录支持,提供用户基础信息、登录历史的存储。 App 在存储这些数据时需要向 SSO 服务器发送请求以更新数据。 App 无需存储用户数据,用户数据存储在 SSO 上,App 只需要存储用户数据版本号。
开发之前¶
依赖¶
- 第三方库:
jQuery1.11
,json2.js
,jquery.fancybox.js
,avalon.js
- 本地 CSS:
css/_lib/fancybox*
,css/SSO/*
- 本地 JS/CoffeeScript
依赖:
js/_lib/cookie.js
,async.coffee
,jquery_ext.coffee
,jquery.poshytip.js
,uploader.coffee
(为个人设置提供的图片上传功能)
注册应用¶
在 SSO 服务器上注册应用,并提供 App 名称、App 域名,SSO
域名(建议统一使用 sso.[App 域名]
)、数据同步地址、登录地址。
使用 GET 方法注册应用:GET
http://sso.tech2ipo.com/rpc/app.new?o=["app_name","app_host","app_sso_host","app_sync_url","app_sso_login_url"]
例如:为 b.com 注册应用的 URL 可以是这样的:
http://sso.b.com/rpc/app.new?o=["SITE B","b.com","sso.b.com","http://b.com/rpc/sso.sync","http://b.com/rpc/sso.login"]
相应的,服务器会给返回一个 app_id
以及对应的
app_token
,作为你的身份认证标志。返回的结果类似这样:
[9912662,"wuVsjhBuBXDwv3wpTo5itE1WwtvjFXaozBNsce52keJw5J5_sOpPe-I8Ge5YuqPK"]
DNS 设置¶
将网站的 app_sso_host 的 CNAME 指向 sso.tech2ipo.com
,可以使用
dig 命令查看 CNAME 是否设置成功。
参数说明¶
App 需要实现注册时提交的 app_sync_url
和 app_sso_login_url
的
GET 方法调用。
app_sso_login_url¶
app_sso_login_url
的作用是接收 SSO
服务器的登录成功回调,并为用户设置登录状态。
app_sso_login_url
接收的参数为
session、user_info_id、expires_days,App 使用 app_token decode
session 获取 sso_user_id,如果成功则说明用户已登录,App 需要再根据
sso_user_id 从自己的数据库中查询对应的
app_user_id,并为用户设置已登录的状态,对应 cookie 和 session
的过期时间应该设置为 expires_days。
app_sync_url¶
app_sync_url
提供一个数据同步接口,由 Client 端向 App
端同步数据。数据的同步永远是单向的。
app_sync_url
接收的参数为
sso_id、user_info_id、mail、ico、name、sign、phone,其中仅有前两者为必需项,后四项如无则留空。
注意事项¶
urlsafe base64 encode¶
由于 base64 encode 的字符在存放在 url 中时会被再次 encode,导致数据失真,因此需要注意下 encode/decode 的实现,例如 Python 中可以直接导入:
from base64 import urlsafe_b64encode, urlsafe_b64decode
PHP 示例:
function urlsafe_b64encode($input) {
return strtr(base64_encode($input), '+/=', '-_,');
}
function urlsafe_b64decode($input) {
return base64_decode(strtr($input, '-_,', '+/='));
}
路线图¶
其他计划开发中的功能:
- 多账户系统(参照 DNSPOD 和 Google)
- IM、私信及系统通知(参照雪球)
- 友邻推荐系统(整合到通知系统)
- 各种社交账号登录(参照多说)
- 头像剪裁
- 移动网页适配以及移动应用开发的 API(登录、聊天)
- 插件、扩展(eg:鼠标移动到姓名上悬浮出现个人资料;点击姓名弹出展示卡片)
Docker 快速入门¶
基本概念¶
Docker 是基于 Linux kernel 的虚拟化工具,仅需要极低的系统资源使用就提供了 强大的虚拟化、资源隔离能力。使用 Docker,用户只需要几分钟即可以将应用程序 “Docker 化”,并且由于其易于复制分享的优点,能够保证开发与部署环境的一致性。
Docker 的基本结构包括:
- Docker 客户端和服务器(C/S)
- Image
- Registry
- Container
在本地安装 Docker 之后,即完成了 Docker C/S 的安装。用户使用 Docker 客户端向 Docker 的守护进程发送命令操作 Container。
Image(镜像)类似于应用的源代码,你可以通过修改源代码(Image)来构建出不同的 Container。 Registry()类似于源码的托管服务器,默认的 Registry 是 Docker 公司提供的 Docker Hub, 你可以将 Docker Hub 类比于 GitHub。
Container 是 Docker 最重要的概念,它通过操作相应的镜像提供一个执行环境。
使用 Docker,可以快速构建很分享应用程序部署服务器、开发环境、CI 环境或者一个应用服务。
首先声明,这里的系统环境设置为 Ubuntu 14.04,Mac OS 和 Windows 系统请在虚拟机里安装 Ubuntu, 其它 Linux 发行版 和 Ubuntu 不会有太大区别,请自行修改命令。
使用 Ubuntu(我自己安装的是 Xubuntu) 的好处:
- 相比 Boot2docker 来说更加强大,比如我可以通过安装 zsh + zsh-docker-completetion 提供 docker 自动补全功能。
- 获得最新最强大的官方支持,Docker 官方推荐使用 Ubuntu,对 Ubuntu 下的问题也能够最及时解决, 甚至某些工具不提供 Mac OS 或者 Windows 兼容方案。
- 相对于其它 Linux 发行版用户更多,使用更简单。
- 推荐在虚拟机中安装 Xubuntu,和 Ubuntu 相比,Xubuntu 更轻量,在虚拟机中性能更好; 在虚拟机中安装 Xubuntu 便于对开发环境的迁移以及内部共享。
Docker 命令¶
Docker 可以通过命令来构建镜像,也可以根据 Dockerfile 配置来构建。 docker 命令与 Dockerfile 的对应关系如下:
Dockerfile¶
命令¶
WORKDIR¶
ENV¶
USER¶
VOLUME¶
ADD¶
向镜像中添加特定文件,可以是主机中或者 web 文件。以 WordPress 的 Dockerfile 为例:
ADD http://wordpress.org/latest.zip /var/www/wordpress.zip
ONBUILD¶
RUN¶
CMD¶
ENTRYPOINT¶
CentOS¶
MongoDB¶
FROM centos:latest
MAINTAINER Kane Blueriver <kxxoling@gmail.com>
RUN yum -y update; yum clean all
RUN yum -y install epel-release; yum clean all
RUN yum -y install mongodb-server; yum clean all
RUN mkdir -p /data/
# 设置挂载点
VOLUME ["/data/mongo"]
# Define working directory.
WORKDIR /data
CMD ["mongod"]
EXPOSE 27017
ENTRYPOINT ["/usr/bin/mongod"]
Redis¶
FROM centos:latest
MAINTAINER Kane Blueriver <kxxoling@gmail.com>
RUN yum -y update; yum clean all
RUN yum -y install epel-release; yum clean all
RUN yum -y install redis; yum clean all
# 设置挂载点
VOLUME ["/data/redis"]
# Define working directory.
WORKDIR /data
EXPOSE 6379
CMD ["redis-server"]
Memcached¶
FROM centos:latest
MAINTAINER Kane Blueriver <kxxoling@gmail.com>
RUN yum -y update; yum clean all
RUN yum -y install epel-release; yum clean all
RUN yum -y install memcached; yum clean all
VOLUME ["/data/mc"]
WORKDIR /data
CMD ["memcached"]
EXPOSE 11211
CMD ["memcached", "-u", "daemon"]
Ubuntu¶
FROM dockerfile/ubuntu
# 从官网安装 MongoDB
RUN \
apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 7F0CEB10 && \
echo 'deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen' > /etc/apt/sources.list.d/mongodb.list && \
apt-get update && \
apt-get install -y mongodb-org && \
rm -rf /var/lib/apt/lists/*
# 设置挂载点
VOLUME ["/data/db"]
# Define working directory.
WORKDIR /data
CMD ["mongod"]
# 27017: process
# 28017: http
EXPOSE 27017
EXPOSE 28017
分享¶
构建好自己的镜像后可以将其 push 到 Registry 上进行分享,默认的 Registry 由 Docker Hub 提供, 如果镜像中存在隐私内容也可以使用 Docker 公司的源代码搭建内部的共享服务器。
登录¶
Push¶
自动构建¶
搭建自己的 Docker Registry¶
快速编配¶
Docker 公司还提供了快速编配工具 compose(原 Fig)用于加速 Docker 环境的构建。
安装:
pip install docker-compose
下面以一个标准的 Python WSGI 应用为例,介绍 compose 的使用方法。
WSGI 应用¶
首先你需要一个 WSGI 应用,这里以一个简单的 Flask 应用为例:
from flask import Flask
from redis import Redis
import os
app = Flask(__name__)
redis = Redis(host='redis', port=6379)
@app.route('/')
def hello():
redis.incr('hits')
return 'Hello World! I have been seen %s times.' % redis.get('hits')
if __name__ == "__main__":
app.run(host="0.0.0.0", debug=True)
标准的 Python 应用还需要提供一个 requirements.txt 记录其依赖——flask 和 redis:
flask
redis
Dockerfile¶
定制一个 Flask 应用的运行环境:
FROM python:2.7
ADD . /code
WORKDIR /code
RUN pip install -r requirements.txt
定义服务¶
定义 docker-compose.yml
配置文件,装配应用运行环境所需组件(Container、Volume 等):
web:
build: .
command: python app.py
ports:
- "5000:5000"
volumes:
- .:/code
links:
- redis
redis:
image: redis
上面的配置文件定义了 2 个服务:
- web:根据本地 Dockerfile 构建出的 Image,提供一个 WSGI 应用的运行环境,将 Docker 中的 5000 端口
映射到主机的 5000 端口,并将本目录挂载到 Container 的 /code 目录。并且链接到 redis 服务。
redis:基于 Docker Hub 的 redis 公开镜像构建的 Container。
程序员知识点考评大纲¶
常用工具¶
Gentoo¶
- emerge –autounmask-write 然后 etc-update 然后 -3
- emerge =xxx-版本号
自定义的命令¶
- dirreplace
- replace_line.py
- deltmp
高级篇¶
- dstat
- dirreplace
- replace_line.py
tmux¶
- Ctrl+B
xshell¶
vim¶
- F12
- MR
- 批量注释
- = 排版
- vsp
- 替换
- 替换选中部分
版本控制¶
- hg
- blame
- log + -l
- fetch
- st
- ignore
- diff
- grep
- bisect 定位BUG出现的版本
- serve
- resolve + -l + -m
42web小工具 :
./hg_close_branch ./hg_update_branch
前端¶
HTML¶
label for属性
绑定表单元素id,实现点击label选中相应radio或checkbox
链接都必须写上href属性, 空链接请写成:
<a href="javascript:void(0)"></a>
反复出现的按钮图标用 a标签 配合 css设置背景图 来实现,不要反复的写img标签(减少代码的冗余度)
CSS¶
- 模块分级
- 全局级
- 模块级
- 页面级
分栏布局
例如左宽665px,父容器宽1000px,在layout.css中定义:
.R665{float: left; margin-left: 688px; width:312px;} .L665{float: left; width: 665px; margin-left: -100%;}
参考:
绝对底部
清除浮动
子选择器
利用父级元素id进行选择
CSS盒模型
垂直居中
如何制作三角
- :first-child 和 :last-child
- 案例 : 圆圈 , padding
如果内容可变,就不要设置高度
- 写完页面依次检查
对齐
- 字体
- 大小
- 粗细
- 颜色
留白
- 42web
- HTML中如何引用图片
图片上传至七牛,使用外链地址 * CSS中如何引用图片:
background:url(/css/_img/xxx)
- 不要引用站外的图片
checkbox 和 radio 的 样式
不要用空格做间距
我们常用的CSS样式¶
- 按钮
- 功能
- 强调
设计¶
- 对齐
- 留白的一致性
- 粗体
- 字号
javascript¶
获取时间戳:
(new Date).getTime()
在js中取得当前用户:
$.current_user
$$
例如调用弹窗(可有多个参数):
$$('SITE/auth/login')
require
$.require
- $.dialog
- 需要登录调用$.login_dialog(参考submit_project.coffee)
$.errtip
err = {} if xxx: err.xxx = "xx" if xx : err.xx ="xx" if not errtip.set err: xxxxx
jQuery¶
- $.extend([deep],target,object)
jQuery 自定义扩展¶
$.timeago
接受一个时间戳作为参数,返回距离当前时间描述
$.isotime
- $.getJSON1
- jsonp 跨域调用
$.postJSON1
$.html 模版
参考egg_new.coffee
jQuery UI¶
- Accordion
- Datepicker
- Tagit
CoffeeScript¶
avalon¶
Firebug¶
- 控制台面板中,点击“保持”按钮,页面重新载入时不清空面板
Photoshop¶
工具¶
- Chrome插件
- PerfectPixel
- Page Ruler
- Windows
- Color Picker
后端¶
python¶
- 闭包
- 正则表达式
- collections - defaultdict
- itertools
- enum - IntEnum
- enumerate
- time.mktime(time.strptime(“2007-03-04 21:08:12”, “%Y-%m-%d %H:%M:%S”))
- dateparser
- python 的 新式类与旧式类 , 以及super的意义
mongodb¶
- find
- limit
- skip
- sort
delete
remove(删除条件)
- save
- 填充默认值
upsert
MySQL¶
- get
- mc_get
- mc_get_list
Kv¶
- id_by_value
- get
- mc_get
nginx¶
mako¶
- this 比如 this.get_argument(‘q’)
- ${json_encode(xxx)|n}
redis¶
- hset
- set
- zset
- list
- expire
mongo¶
- 时间用int保存
- mongo默认值需要是一个生成函数 * pyhton常见的默认值陷阱,以create_time=time()为例
gearman¶
supervisor¶
- 线上服务器如何看异常
tornado¶
- 通过编写 Base View简化业务开发
42web¶
- 新建url页面
- render
- css,js的引用
- merge.conf
- 新建css,js,修改merge.conf需要重启开发服务器
- View的类型
- 分页
- 在页面取得当前用户
- 搜索
- 自动补全
- gearman 异步调用
- JsOb
- rendermail 发送邮件
- redis key的定义 , R.
- model 中 使用绝对路径import以防止redis提示key重复定义
- import _env
- 配置文件 的 定义 与 自适应
- make.py 生成配置文件
开发习惯¶
修改函数接口后, 用ag查找并修改些调用过的地方
函数命名规则 :名词在前动词在后 , 常用命名如下
- user_new 新建
- user_rm 删除
- user_dumps 返回一个包含各种相关数据的json对象
- user_id_list_by_com_id(limit, offset) 查询
- user_new 新建
- user_rm 删除
- user_dumps 返回一个包含各种相关数据的json对象
- user_id_list_by_com_id(limit, offset) 查询
- user_id_count_by_com_id
我们通常把user_id作为第一个参数
如何编译 reST 文档¶
reST 文档的编译依赖 make 和 sphinx,安装完依赖后在文档的根目录执行
make html
构建 HTML 文档,如无错误即可在 _build/html
目录中生成对应的 HTML 文件,
可以在浏览器中直接打开 _build/html/index.html
预览生成的 HTML。
本文档托管在 ReadTheDocs,文档合并之主分支后将会自动构建,预览请访问 RTFD 。
蘑菇碎碎念¶
HG¶
fetch 某个分支
hg fetch http://xxx.xxx.xxx.xxx:8000 -r
在docker中互相fetch
docker额外映射了一个端口到8000,可以通过这个端口
关闭无名分支
hg update -r <版本号> hg commit --close-branch -m 'Closing old branch' hg update -C default
翻墙有道¶
gentoo下emerge访问墙外资源¶
emerge设置HTTP代理
在
/etc/make.conf
写入代理配置http_proxy="http://127.0.0.1:8080" https_proxy="http://127.0.0.1:8080"
安装配置HTTP代理工具polipo
sudo emerge polipo
即可完成安装,安装后在/etc/polipo/conf
中写入daemonise=false diskCacheRoot=/var/cache/polipo/ proxyAddress=127.0.0.1 proxyName=localhost cacheIsShared=true allowedClients=127.0.0.1 proxyPort=8080 socksParentProxy = 127.0.0.1:1080 socksProxyType = socks5
配置shadowsocks
{ "server":"vpn.mushapi.com", "server_port":1081, "local_address": "127.0.0.1", "local_port":1080, "password":"btyh17mxy", "timeout":300, "method":"aes-256-cfb", "fast_open": false, "workers": 1 }
vim黑科技¶
遇到gbk乱码囧木办
set encoding=utf-8 set fenc=cp936 set fileencodings=cp936,ucs-bom,utf-8 if v:lang =~? '^\(zh\)\|\(ja\)\|\(ko\)' set ambiwidth=double endif set nobomb
粘贴后格式错乱怎么办
有的时候,在插入模式下从系统粘贴板粘贴文本到vim中会出现缩进异常的情况,为了解决这种问题,在粘贴前应该设置vim为粘贴模式并在粘贴完成后取消粘贴模式
:set paste
:set nopaste
vim插件及使用¶
syntastic 在错误之间跳转
:lnext 跳到下一个
:lprev 跳到上一个
使用pyflakes进行语法检查
:SyntasticCheck pyflakes
iptables¶
列出所有规则
iptables -nvL -t nat --line-number
列出nat表的所有规则并显示行号
清零流量统计
iptables -Z
删除
iptables -t nat -D DOCKER 13
删除nat表DOCKER链的第13行的规则
用iptables给Docker添加端口映射
iptables -t nat -A DOCKER --in-interface !docker0 -p tcp --dport 6666 -j DNAT --to 172.17.0.5:6666
docker会在系统中创建一个叫docker0的网卡,本例中172.17.0.5就是docker0的IP地址
linux命令¶
ssh客户端配置文件¶
当主机较多的时候,不方便记住所有的IP、用户、端口以及密码,为了解决这个问题我们可以使用一个ssh的配置文件来记录这些服务器。
常用的配置有
Host 主机别名 HostName 主机地址 User 登陆用户名 Port 端口号 IdentityFile 公钥
在~/.ssh/目录下创建一个config文件,在config中写入相应的配置后就可以使用 ssh <主机别名>
直接连接服务器了
多线程下载工具axel¶
curl和wget是单线程的,使用这货的多线程方式下载文件会显著提高下载速度
安装
gentoo下
sudo emerge axel
centos下
sudo yum install axel
使用
axel -n <线程数> -o <保存文件的目录> <下载地址>
docker 的一个奇怪命令¶
docker run -e MYSQL_ROOT_PASSWORD=rstfsgbcedh –expose 3306 –entrypoint=”/entrypoint.sh” –name mysql-hg -d mush/mysql-hg mysqld
如果遇到 TERM environment variable not set. 就执行 export TERM=dumb
redis批量删除key¶
EVAL "local keys = redis.call('keys', ARGV[1]) \n for i=1,#keys,5000 do \n redis.call('del', unpack(keys, i, math.min(i+4999, #keys))) \n end \n return keys" 0 investment_0*
EVAL "local keys = redis.call('keys', ARGV[1]) \n for i=1,#keys,5000 do \n redis.call('del', unpack(keys, i, math.min(i+4999, #keys))) \n end \n return keys" 0 s_idx_cache_*
EVAL "local keys = redis.call('keys', ARGV[1]) \n for i=1,#keys,5000 do \n redis.call('del', unpack(keys, i, math.min(i+4999, #keys))) \n end \n return keys" 0 autocom*
开发服务器环境介绍¶
开发服务器上通过使用docker来为每人提供一个独立的开发环境,通过主机上的nginx来将每人的域名分别通过反代指向他的docker。 我们使用了一个数据卷容器充当数据库文件目录,启动ssh供登陆开发.
添加一个新的开发docker¶
启动一个数据卷容器
docker run -d -v /data --name <your name>_data pevc/data echo data_only for database
启动一个开发容器
docker run -d -i -p 9005:80 -p 10005:22 -p 8005:8000 --volumes-from <your name>_data --name <your name>_42web mush/ac /usr/sbin/sshd -D -f /etc/ssh/sshd_config
需要注意端口号,run之前先看下别人用了哪些端口了,一般就将端口号加一就行了。
配置dns和主机的nginx反向代理
在/etc/dnsmasq.conf解析你要使用的域名。
address=/mushapi.info/192.168.10.169 address=/*.mushapi.info/192.168.10.169
在/etc/nginx/conf.d中加入你的反向代理配置。
server {
listen 80;
server_name mushapi.info *.mushapi.info;
location / {
proxy_pass http://127.0.0.1:9000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
dnsmasq配置¶
解析和泛解析
在`/etc/dnsmasq.conf`中添加下面的代码
address=/mushapi.info/192.168.10.169 address=/*.mushapi.info/192.168.10.169
cname解析
假设我们要将a.com用cname指向b.com,则需要首先在本地hosts中增加b.com的解析,再向/etc/dnsmasq.conf中添加cname解析。
修改/etc/hosts,增加一行
<some ip> b.com
在dnsmasq.conf中增加
cname=a.com,b.com
不要依赖工具¶
Python抽象方法¶
Python中抽象方法有两种实现,一是通过抛出 NotImplementedError
异常, 而是通过abc模块.
例如
class Base:
def foo(self):
raise NotImplementedError()
def bar(self):
raise NotImplementedError()
和
from abc import ABCMeta, abstractmethod
class Base(metaclass=ABCMeta):
@abstractmethod
def foo(self):
pass
@abstractmethod
def bar(self):
pass
使用Docker的正确姿势¶
压缩Docker镜像的体积¶
docker export <要压缩的容器> | docker import - <新镜像名字>
使用go语言编写一个可以放到Docker中的静态可执行文件并生成为一个Docker容器¶
go语言是个好东西,吉祥物都那么萌.
go build -a -ldflags '-s' <要编译的Go文件>
然后再DockerFile里这么写
FROM scratch
ADD <编译粗来的可执行文件> /
ENTRYPOINT ["<编译粗来的可执行文件>"]
我研究这个问题的起因是我只想弄个echo到Docker里面,因为你run一个Docker的时候必须指定一个运行的命令.但我把echo这个可执行文件搞进去发现不能用.具体的可以参看这里,http://blog.xebia.com/2014/07/04/create-the-smallest-possible-docker-container/
监控Docker容器内存使用情况
cat /sys/fs/cgroup/memory/system.slice/docker-88018f8043d00669bbf865855ebc8a6ccc93a04ce588111e01d4e63739250340.scope/memory.stat
应对怪需求的好方法¶
关于dict顺序的问题¶
经常的我们有一些字段为枚举,然后在页面上要用select的形式展现,往往善变的产品会要求改变下拉菜单条目出现的顺序,我们可以这样应对.
<select name="stage" ms_duplex="o.com_base_info.stage" class="spinput">
<option value="0">请选择阶段</option>
% for k, v in COM_STAGE_DICT.iteritems():
<option value="${k.value}">${v}:${COM_STAGE_COMMENT_DICT[k.value]}</option>
% endfor
</select>
COM_STAGE_DICT = collections.OrderedDict()
COM_STAGE_DICT[COM_INFO_STAGE.CONCEPT] = '概念阶段'
COM_STAGE_DICT[COM_INFO_STAGE.DEVELOPING] = '研发阶段'
COM_STAGE_DICT[COM_INFO_STAGE.RELEASED] = '正式发布'
COM_STAGE_DICT[COM_INFO_STAGE.GETUSERS] = '已有用户'
COM_STAGE_DICT[COM_INFO_STAGE.PROFIT] = '已有收入'
# COM_STAGE_DICT = {
# COM_INFO_STAGE.CONCEPT : '概念阶段',
# COM_INFO_STAGE.DEVELOPING : '研发阶段',
# COM_INFO_STAGE.RELEASED : '正式发布',
# COM_INFO_STAGE.GETUSERS : '已有用户',
# COM_INFO_STAGE.PROFIT : '已有收入',
# }
程序员评级与待遇草案¶
菜鸟 :4k
能在别人的指导下,参考现有代码完成功能的开发。
对于不能迅速从菜鸟成长为新手的coder,应该持放弃态度。
新手 :7k-1w
能理解基本的运作逻辑,可以依葫芦画瓢的进行前后端开发。
按照产品要求独立完成功能模块。
产品品质有初步保障,能进行自我测试,交付的产品少有各种低级BUG。
熟练工 :1w - 2w
能熟练进行前端和后端的开发,工作效率高。
思维缜密,在开始写之前就能想清楚有几种情况,做到胸有成竹。
有良好的代码审美,会主动对代码抽象并复用。
资深开发者 :2w - 3w
能从产品的角度出发去思考需求,常常能可以给出更好的解决方案。
对整个代码有深入的理解,遇到问题有能力去翻查底层的代码并找到原因。
团队中其他人遇到奇怪的BUG时,能给予技术支援,快速定位并修复。
有能力为公司快速培养新的人才。
专家 :3w - 5w
在某些有难度的技术领域有深入研究,能人之所不能。
有极强的自学能力和技术敏感性,会主动研究的新的技术,并分析优势劣势和应用场景。
能通过技术手段和流程改进,来创造性的提高整个团队的技术水平和生产力。 会从公司的角度去思考产品,与产品团队一起制定开发计划,管理开发团队。
大师 :
曾经领导开发过一个有口皆碑的作品。
在技术社区中有很强的影响力,可以为公司吸引优秀的技术人才。
应用开发教程¶
熟悉项目目录结构¶
目录结构
-z42
-z42 ------配置和公用库
-zapp ------所有应用目录
-ANGELCRUNCH -------- AngelCrunch网站目录
-html ----------- Mako 模板和静态 HTML 目录
-_html ---------- Mako 模板缓存路径
-plim ----------- Plim 模板目录
-css ----------- CSS 文件目录
-coffee --------- CoffeeScript
-javascript ----- JavaScript 库和 CoffeeScript 编译生产的文件目录
-model ---------- Python 对象
-view ----------- Python 应用视图
-dev.sh --------- 应用启动脚本
-... -------- 其它网站目录
对于 CoffeeScript、JavaScript、CSS、SASS、SCSS,其文件目录下的 _lib
用于存放第三方库/框架。
配置路由&编写视图¶
View 与 tornado.web.RequestHandler
@route
# root.py
...
@route
class hello_world(View):
def get(self):
o = 'world'
self.render()
...
第一个 Mako 文件¶
<h1 id="hello" class="mako plim" data-height="10">Hello, ${ o }</h1>
<div class="d1">
<div class="d2">
<span>div</span>
</div>
</div>
<%include file="file.html"/>
第一个 Plim 文件¶
h1#hello.mako.plim data-height=10
Hello, ${ o }
.d1
.d2
span
|div
-include file.html
第一个 SCSS/SASS 文件¶
SCSS
$font-stack: Helvetica, sans-serif;
$primary-color: #333;
body {
font: 100% $font-stack;
color: $primary-color;
}
nav {
ul {
margin: 0;
padding: 0;
list-style: none;
}
li { display: inline-block; }
a {
display: block;
padding: 6px 12px;
text-decoration: none;
}
}
第一个 CoffeeScript 文件¶
obj = {
a: 1
b: 2
c: ->
alert 'Hello World!'
}
输出:
var obj = {
a: 1,
b: 2,
c: function(){
alert('Hello World');
}
}