keystonejs
安装成功:一系列的问题 有一个 是否创建新文件夹,要选n,然后才能在当前文件夹下node keystone.
按照官网的教程学学 : http://keystonejs.com/zh/docs/configuration/
简介
项目结构
//--------------------------------------------
lib:自定义的库和其他代码
models:数据模型
public
routes:api:api控制器
views:视图控制器
index.js:路由和视图的初始化
middleware.js:路由的自定义中间件
templates:includes:常用的jade
layouts:基础的jade架构
mixins:常用的jade mixin
views:视图模板
updates:迁移脚本
package.json:npm的项目配置
web.js:开启项目的脚本
//--------------------------------------------
Keystone在生产和开发模式下会使用不同的设定。默认环境为development,为了提升性能,你应该在生产服务器上将环境变量NODE_ENV设为production。
keystone.get('env'); 获取和设置
还引入了underscore库
可以使用自带Express和Mongoose->
将routes/views和templates/views目录的内部结构做镜像式对应
提供认证和会话管理:user model; session; auth; cookie secret; canAccessKeystone
参数user model必须是Keystone在其中查找用户的模型名称。如果你的模型用了其它名称,一定确保正确设定这个参数。 如果你的程序要支持会话管理,将参数session设为true。加载会话会有点小开销,所以如果你的程序不需要会话,可以把这个关了。 Keystone有内置的登录和退出视图。可以将参数auth设为true启用它们。你也可以在程序视图中定制登录和退出界面。 会话是用存有用户ID的加密cookie持久化的。一定要将参数cookie secret设成一个长长的随机字符串。 用户模型必须有个canAccessKeystone属性(可以是虚拟方法或存储的boolean型域)指出用户是否可以访问Keystone的管理界面。
var importRoutes = keystone.importer(__dirname); //引入__dirname目录下的路由
在model/index.js中设置404,500;app为express中的app,这里可以加post和all
把你的通用路由中间件放在单独的routes/middleware.js文件中,以保持路由index的干净整洁。 如果中间件文件太大,最好把所有重大功能重构到定制的模块中,放在项目的/lib文件夹下。
templates/layouts/default.jade调用templates/mixins/flash-messages
如果在public文件夹下有.less文件,它还会自动生成相应的.css或缩小化的.min.css文件, 这个在web.js中由less参数指定
为此我们将要创建一个更新脚本,Keystone会在启动web服务器之前自动运行它。在web.js中设定参数auto update就可以启用Keystone的自动更新功能。当这个参数被设为true时,Keystone会扫描updates目录寻找.js文件,更新是用语义版本排序的,并且Keystone只会运行它们一次 (成功执行的更新会存在你的数据库里,一个名为app_updates的集合中)。更新文件名应该符合x.x.x-description.js的模式 - 所有跟在第一个连字符之后的字符串都会被忽略,所以你可以在那里描述这个更新。所以,为了在程序第一次启用时自动添加一个新的管理员用户,我们要创建一个updates/0.0.1-admin.js文件:
简介看了一遍,不会的都已记录。
配置
设定参数:设定很多行为,有三种方法
keystone.init(options);
keystone.set(key, value);
process.env;
如果你不想把秘钥和配置放在代码库中(这对于开源项目,或者不是所有开发人员都可以访问生产配置设定的项目来说非常重要) ,用dotenv模块很容易实现。
参数有很多种:
项目参数
name
brand
module root:keystone.get('module root'); keystone.getPath('views');
frame guard:sameorigin,deny(true), false 如何处理iframe标签
nav:指定管理界面导航结构的对象
keystone.set('nav', { 'posts': ['posts', 'post-categories'], 'galleries': 'galleries', 'enquiries': 'enquiries', 'users': 'users' });
csv field:自定义csv的分隔符
app
mongoose
web服务器参数
env:要用的环境设定。支持development和production,这个参数会影响缓存已编译模板之类的事情。默认为process.env.NODE_ENV || "development"。你真的应该用环境变量NODE_ENV在生产服务器上将这个设为production。
port:监听请求的端口。默认为process.env.PORT || 3000
host:监听请求的ip地址。默认为process.env.IP || '127.0.0.1' 必须设定了port(通过参数或环境变量) host参数才能生效。
views
view engine
custom engine
view cache:一般为true
locals:传给视图模板的默认local变量
static:public
static options
less:如果你想让Keystone将.less文件自动编译成.css文件,把它的值也设成static参数指定的路径。设了这个参数之后,所有对.css或.min.css文件的请求处理都会先检查有没有同名的.less文件,如果有,则生成css文件。
less options
sass:同less,需要在package.json中加入node-sass
sass option
favicon
compress
logger
trust proxy:设定这个启用HTTP请求头X-Forwarded-For。提取出来的IP地址会放在数组req.ips (相关文档)。
https服务器
这个不常用
监听unix socket
这个不常用
数据库和用户认证参数
mongo:MongoDB连接的url。一般应该设为process.env.MONGO_URI || "mongodb://localhost/your-db"
model prefix:模型的前缀
auth:登录
user model:用户的Keystone列表的键,如果auth设为true,则是必需的。一般这个会设为User。
cookie secret
session store:
session store options:
back url
signin url:当访问者没能通过默认的认证检查(比如没能登录)时弹出的href 默认为/keystone/signin,只有auth被设为true时才用。
signin redirect:访问者通过内置的登录路由成功登录后弹出的href 默认为/keystone
signout url
signout redirect
管理界面参数
都是关于编辑器的
服务有很多种:谷歌分析,谷歌地图,亚马逊S3,微软存储,cloudinary, embed.ly, mandrill。有很多都用不上。
应用程序更新
auto update:true
简介的时候讲过
禁用管理员界面
headless:true
数据库:model中定义管理页面
域类型:有效地域类型或基本的数据类型
列表参数:可以作为list()的第二个参数;也可以作为域参数
label:列表在管理页面中的标签
path:列表在管理页面中的路径
autokey: { from: 'name', path: 'key', unique: true, fixed:true } key为'key', 内容来自form
singular : 列表中条目的单数标签
plural : 列表中条目的双数标签
schema:列表的Mongoose模式的参数,这个参数可以给集合指定一个定制的名称。
drilldown : 以空格分隔的关系清单,在管理界面中显示为下钻项。看不出来是神马效果
sortable : 给模式添加一个隐藏的sortOrder域,并在管理界面中启用拖拽式的排序。
sortContext : 管理界面中有拖拽式排序时用来控制的List:relationship对。
searchFields 在管理界面中用于搜索的路径清单,用空格分隔。
defaultSort
defaultColumns: Post.defaultColmuns 有的不是直接做为List选项用的 其实都一样
map:将域映射到特定列表路径上的对象。如果添加了带那个键的域,则每个路径都默认为它的键。
track:在列表上添加一个插件,追踪谁在什么时候(比如哪个Keystone用户)创建和最后修改了一个条目
noedit Boolean 禁止在Keystone管理界面中编辑列表中的条目。
nocreate Boolean 禁止在Keystone管理界面中创建列表的新条目。
nodelete Boolean 禁止在Keystone管理界面中删除列表中的条目。
hidden Boolean 在Keystone管理界面中隐藏这个列表。
promise 处理错误
list.paginate 分页
创建save,删除remove
var newPost = new Post.model({ title: 'New Post' });
域
数据类型 域类型:用哪个都可以
String Text
Number Number
Date DateTime
Boolean Boolean
域参数:通用的index default label
label String 每个域的标签都是由域路径生成的;设置这个参数会覆盖默认值。
required Boolean 在条目保存前验证这个域是有值的(还会传给mongoose并强制使用数据库索引)。
initial Boolean 让这个域出现在管理界面中的创建条目表单中。
noedit Boolean 在管理界面中将这个域渲染为只读域。
note String 在管理界面中跟着域显示。
hidden Boolean 如果设为true,则该域在管理界面中一直是隐藏域。
条件域
collapse Boolean 该域没有值时在管理界面中显示一个+ 添加链接。当noedit也被设为true时,该域没值时则完全隐藏。
dependsOn Object 只有对象中指定的路径跟条目的当前数据匹配时才会显示 你可以在每个路径上用数组对准多个值。
观测域
watch
value
underscore方法:有的有
关系域
Post.add({ author: { type: Types.Relationship, ref: 'User' }, categories: { type: Types.Relationship, ref: 'PostCategory', many: true } });
filters参数是一个键/值对对象,其中键对应要过滤的相关模型的域,其中的值或者是字面值,或者是当前模型的域名,值会用来过滤关系。
也可以用模型中其它域的值过滤。将过滤器的值设为那个域的名称,前面加上分号(:)。
还可以用当前模型的_id域过滤
域类型
Embedly:管理界面显示只读数据
AzureFile:管理界面显示上传文件:Windows Azure Storage
S3File:管理界面显示上传文件:亚马逊S3
LocalFile:管理界面显示上传文件:本地
CloudinaryImage:在管理界面中显示为一个图片上传控件
location:一组输入控件的组合
password
name:first last
markdown
select
money
number
key:文本输入域
Datatime
Date
color:取色器的文本控件
html
url
textarea
text
boolean
技巧
使用html模板引擎:
'view engine': 'html', 'custom engine': require('ejs').renderFile,
view.render('index')->index.html
模块contact
contact.js enquiry.js contect.jade
早上自己敲了contact和post,感觉mongoose不会的比较多,所以先看一下mongoose。这两个模块都有MVC组成,M有固定的流程,V有固定的流程。
post模块:
如果一个域类型为type: Types.Relationship:则会显示当前存储在那个关系域中的条目,如author和categories
如果一个域类型为type:Types.Html:管理界面中显示为一个文本控件或WYSIWYG编辑器
条件域:dependsOn:只有对象中指定的路径跟条目的当前数据匹配时才会显示
关系域:many:如果你想将Post模型链到多个PostCategories上时 ,1对多的关系
blog模块
exec err
if(err || !results.length){ return next(err); }
async.each
model.count()
.in([category.id])
.paginate()
list的方法
list.schema.virtual
list.relationship
list.schema.methods.mymethod
list.schema.pre/post
属性
list.defaultSort
list.defaultColumns
自己写的简化版
models-post.js
var keystone = require('keystone'), Types = keystone.Field.Types; var Post = new keystone.List('Post'); Post.add({ name: { type: Types.Name, required: true}, content: { brief: {type: Types.Textarea, height: 150}, extended: {type: Types.Textarea, height: 400} } }); Post.register();
routes-view-posts.js
var keystone = require('keystone'); var Post = keystone.list('Post'); // 引入了post数据模型 exports = module.exports = function(req, res){ var view = new keystone.View(req, res), // 视图类的实例 locals = res.locals; locals.section = 'posts'; // 初始化本地变量,将传到template locals.data = { posts: [] } view.on('init', function(next){ // 初始化之前需要去数据库找 Post.model.find({}) .exec(function(err, posts){ locals.data.posts = posts; // 找到的结果绑定到本地变量中 next(); }); }); view.render('posts'); // 显示视图 }
template-views-posts.jade
block content if data.posts.length > 0 h3 there are #{data.posts.length} posts each post, index in data.posts h1 #{post.name.first} #{post.name.last} p #{post.content.brief} p #{post.content.extended} if data.posts.length != index+1 hr
routes-index.js:
app.get('/posts', routes.views.posts); //只保留这一个route
以上过程可以简单理解一下,keystone的工作流程。