安裝成功:一系列的問題 有一個 是否建立新文件夾,要選n,而後才能在當前文件夾下node keystone.javascript
按照官網的教程學學 : http://keystonejs.com/zh/docs/configuration/css
簡介html
項目結構java
//--------------------------------------------node
lib:自定義的庫和其餘代碼web
models:數據模型mongodb
public數據庫
routes:api:api控制器express
views:視圖控制器npm
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的工做流程。