一,前台

1,添加文章 /views/admin/content_add.html

{% extends 'layout.html' %}
{% block main %}
<ol class="breadcrumb">
<li><a href="/admin">管理首页</a></li>
<li><span>添加分类</span></li>
</ol>
<h3>添加分类</h3>
<form method="POST">
<div class="form-group">
<label for="category_name">分类名称</label>
<input type="text" class="form-control" name="category_name" id="category_name" placeholder="Category Name">
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
 
{% endblock %}
 
2,查看文章  /views/admin/content.html
 
{% extends 'layout.html' %}
{% block main %}
<ol class="breadcrumb">
<li><a href="/admin/content">内容首页</a></li>
<li><span>内容列表</span></li>
</ol>
<h3>内容列表</h3>
<table class="table table-bordered">
<tr>
<th>ID</th>
<th>标题</th>
<th>分类</th>
<th>简介</th>
<th>作者</th>
<th>添加时间</th>
<th>阅读量</th>
<th>操作</th>
</tr>
<!-- 循环输出数组 . id是对象,需要转换成字符串 -->
 
{% for content in contents %}
<tr>
<td> {{content._id.toString()}}</td>
<td> {{content.title}}</td>
 
<!-- 关联的具体使用 -->
<td> {{content.category.category_name}}</td>
 
<td> {{content.description}}</td>
<td> {{content.user.username}}</td>
<td> {{content.addTime|date('Y-m-d h:i:s')}}</td>
<td> {{content.views}}</td>
<td>
<!-- 【 错误的案例 : 忘记加路由 】 <a href="/content/edit?id={{content._id.toString()}}">修改</a> | -->
<a href="/admin/content/edit?id={{content._id.toString()}}">修改</a> |
<a href="/admin/content/delete?id={{content._id.toString()}}">删除</a>
</td>
{% endfor %}
</tr>
</table>
<div class="btn-group" role="group" aria-label="...">
<a href="/admin/content?page={{page-1}}" class="btn btn-default">上一页</a>
<a href="/admin/content?page={{page+1}}" class="btn btn-default">下一页</a>
<li>一共有 {{count}} 条数据</li>
<li>每页显示 {{limit}} 条数据</li>
<li>一共有 {{pages}} 页</li>
<li>当前是在 {{page}} 页</li>
</div>
{% endblock %}

3, 修改文章 /views/admin/content_edit.html

{% extends 'layout.html' %}
{% block main %}
<ol class="breadcrumb">
<li><a href="/admin">管理首页</a></li>
<li><span>文章内容编辑</span></li>
</ol>
<h3>文章内容编辑 -- {{content.title}}</h3>
<hr> <h4>调试</h4>
{% for category in categories %}
{{category._id.toString()}} , {{category.category_name}}
{% endfor %}
<hr>
<form method="POST">
<div class="form-group">
<label for="category">分类</label>
<select name="category" id="category" class="form-control">
<!--
var categories = []
 
【 读取category表 】
Content.find().populate('category').then((rs) => {
categories = rs
-->
{% for category in categories %}
{% if category._id==content.category._id%}
<option value="{{category._id.toString()}}" selected>{{category.category_name}}</option>
{% else %}
<option value="{{category._id.toString()}}">{{category.category_name}}</option>
{% endif %}
{% endfor %}
</select>
</div>
<div class="form-group">
<label for="title">标题</label>
<input type="text" class="form-control" value="{{content.title}}" name="title" id="title" placeholder="Title">
</div>
<!-- 自动截取简介 -->
<div class="form-group">
<label for="description">简介</label>
<textarea class="form-control" name="description" id="description" cols="30" rows="3"
placeholder="Description">{{content.description}}</textarea>
</div>
<div class="form-group">
<label for="content">内容</label>
<textarea class="form-control" name="content" id="content" placeholder="Content" cols="30" rows="6">{{content.content}}</textarea>
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
{% endblock %}
 
二,数据库
 
1,定义文章表 /schemas/contents.js
 
var mongoose = require('mongoose')
/**
* 创建表结构
*/
module.exports =new mongoose.Schema({
 
// 关联字段(object) ———— 与分类表的 _id , category_name 是一样的
category:{
// 类型
type:mongoose.Schema.Types.ObjectId, //【 要指定ObjectId的类型,请在声明中使用Schema.Types.ObjectId。 】
 
/** 引用 【 引用另一张表的原型 】 => 实现关联
*
* 1, Category 指的是 /models/Category模型
* 2, 配合路由数据库查询的 populate('category'),
* 3, populate('category') 中的category 表示 category字段
* 4, 具体使用, 模板文件中 : {{content.category.category_name}}
*/
ref:'Category' //
},
title:String,
description:{
type:String,
default:''
},
 
content:{
type:String,
default:''
},
 
/**
* 拓展 */
/**
* 关联字段 : 用户 ID
*
* 具体使用 : 在admin/content.add 路由的数据库保存字段中添加 user:req.userInfo._id.toString() 即可
*/
user:{
type:mongoose.Schema.Types.ObjectId,
ref:'User'
},
/**
* 添加时间
*
* 具体使用 :(自动生成)
*/
addTime:{
type:Date,
default:new Date()
},
/**
* 点击量(阅读量)
*
* 具体使用 :(自动生成)
*/
views:{
type:Number,
default:0
}
})
 
2,定义文章数据模型  /models/Content.js 
var mongoose = require('mongoose')
var contentSchema = require('../schemas/contents')
/**
* 创建模型
*/
module.exports= mongoose.model('Content',contentSchema)
 
 
 
三,后台路由和业务逻辑   /router/admin.js
 
/**内容首页 */
router.get('/content',(req,res)=>{
 
var page = Number(req.query.page || 1) // 如果没有传值,默认为1
var limit = 10
var pages = 1
Content.count().then((count)=>{
// 计算总页数,向上取整数,去最大值
pages = Math.ceil(count / limit)
 
// 页数取值不能超过总页数的值
page = Math.min(page,pages)
 
// 取值不能小于1
page = Math.max(page,1)
var skip = (page-1)*limit
// 排序 : sort({第一个参数表示根据什么排序 : 第二个参数只能是( 1 和 -1 : 1 表示升序 ,-1 表示降序 )})
// _id 值包含了时间戳
Content.find().sort({_id:-1}).limit(limit).skip(skip).populate(['category','user']).then((contents) => {
// console.log(contents)
res.render('admin/content',{
userInfo: req.userInfo,
contents:contents,
page:page,
pages:pages,
count:count,
limit:limit
})
 
})
})
 
 
})
/**文章添加 */
router.get('/content/add',(req,res)=>{
/**读取分类内容 */
Category.find().sort({_id:-1}).then(categories=>{
res.render('admin/content_add',{
userInfo:req.userInfo,
categories:categories
})
})
})
/** 文章添加 */
router.post('/content/add',(req,res)=>{
/** 一,验证 */
if(req.body.category==''){
res.render('admin/error',{
user:req.userInfo,
message:'分类不能为空'
})
return Promise.reject()
}
if(req.body.title==''){
res.render('admin/error',{
user:req.userInfo,
message:'标题不能为空'
})
return Promise.reject()
}
if(req.body.description==''){
res.render('admin/error',{
user:req.userInfo,
message:'简介不能为空'
})
return Promise.reject()
}
if(req.body.content==''){
res.render('admin/error',{
user:req.userInfo,
message:'内容不能为空'
})
return Promise.reject()
}
/** 二,保存 */
/**1,错误的示例 */
// Content.save().then(fs=>{
// if(fs){
// res.render('admin/success',{
// user:req.userInfo,
// message:'添加内容成功'
// })
// }
// })
new Content({
content:req.body.content,
title:req.body.title,
category:req.body.category,
description:req.body.description,
user:req.userInfo._id.toString()
}).save().then(fs=>{
if(fs){
res.render('admin/success',{
user:req.userInfo,
message:'添加内容成功',
url:'/admin/content'
})
}
})
})
/** 文章的修改 */
router.get('/content/edit',(req,res)=>{
var id = req.query.id || ''
// console.log('id=>'+id)
/**
* 从外部获取 categories (1)
*/
var categories = []
// 读取category表
 
/** ——————————————————————————————————————————————————————————————————————————【Bug】
* Content.find().sort({_id:-1}).populate('category').then((rs) => {
* —————————————————————————————————————————————————————————————————————————— 【Bug】
* */
Category.find().sort({_id:-1}).populate('category').then((rs) => {
 
/**
* 从外部获取 categories (2)
*/
categories = rs
 
return Content.findOne({
_id:id
}).populate('category')
}).then(content=>{
// console.log(('categories=>'+categories).yellow)
if(!content){
res.render('admin/error',{
user:req.userInfo,
message:'要修改的内容不存在',
url:'/admin/content'
})
}else{
res.render('admin/content_edit',{
user:req.userInfo,
content:content,
categories:categories
})
}
})
})
/**
* 保存修改的文章
*/
router.post('/content/edit',(req,res)=>{
var id = req.query.id || ''
console.log(('req.body.category=>'+req.body.description).yellow)
if(req.body.category==''){
res.render('admin/error',{
user:req.userInfo,
message:'分类不能为空'
})
return Promise.reject()
}
if(req.body.title==''){
res.render('admin/error',{
user:req.userInfo,
message:'标题不能为空'
})
return Promise.reject()
}
Content.update({
/**条件 */
_id:id
},{
/**更新的内容 */
content:req.body.content,
title:req.body.title,
category:req.body.category,
description:req.body.description,
}).then((fs)=>{
if(fs){
res.render('admin/success',{
user:req.userInfo,
message:'修改内容成功',
url:'/admin/content'
})
}
})
})
/**
* 文章删除
*/
router.get('/content/delete',(req,res)=>{
 
//获取要删除分类的id
var id = req.query.id || ''
//直接删除
Content.remove({
_id:id
}).then((rs)=>{
if(rs){
res.render('admin/success',{
user:req.userInfo,
message:'文章删除成功',
url:'/admin/content'
})
}
})
 
})

19 ~ express ~ 文章的增加 , 查看 ,修改 ,删除的更多相关文章

  1. ASP.NET MVC3 实例(六) 增加、修改和删除操作(二)

    http://www.jquery001.com/asp.net-mvc3-instance-add-update-delete2.html 上篇我们在 ASP.NET MVC3 中实现了添加操作,由 ...

  2. 在linux中,如何增加、修改、删除、暂停和冻结用户名

    在Linux中,如何增加.修改.删除.暂停和冻结用户名 在操作增加.修改和删除用户名前,先认识linux中两个最重要的文件,它们就是账号管理最重要文件“/etc/passwd”与“etc/shadow ...

  3. MongoDB增加用户、删除用户、修改用户读写权限及只读权限(注:转载于http://www.2cto.com/database/201203/125025.html)

    MongoDB  增加用户 删除用户  修改用户  读写权限 只读权限,   MongoDB用户权限分配的操作是针对某个库来说的.--这句话很重要.   1. 进入ljc 数据库:       use ...

  4. ASP.NET 操作Cookie详解 增加,修改,删除

    ASP.NET 操作Cookie详解 增加,修改,删除 Cookie,有时也用其复数形式Cookies,指某些网站为了辨别用户身份而储存在用户本地终端上的数据(通常经过加密).定义于RFC2109.它 ...

  5. Oracle 增加修改删除字段

    Oracle 增加修改删除字段 添加字段的语法:alter table tablename add (column datatype [default value][null/not null],…. ...

  6. MySql增加字段、删除字段、修改字段

    MySql增加字段.删除字段.修改字段名称.修改字段类型   1.增加一个字段 alter table user add COLUMN new1 VARCHAR(20) DEFAULT NULL; / ...

  7. Oracle-表的字段增加修改删除操作

    表结构修改 ALTER TABLE SCOTT.TEST RENAME TO TEST1--修改表名 ALTER TABLE SCOTT.TEST RENAME COLUMN NAME TO NAME ...

  8. EF里查看/修改实体的当前值、原始值和数据库值以及重写SaveChanges方法记录实体状态

    本文目录 查看实体当前.原始和数据库值:DbEntityEntry 查看实体的某个属性值:GetValue<TValue>方法 拷贝DbPropertyValues到实体:ToObject ...

  9. Laravel大型项目系列教程(四)显示文章列表和用户修改文章

    小编心语:不知不觉已经第四部分了,非常感谢很多人给小编提的意见,改了很多bug,希望以后能继续帮小编找找茬~小编也不希望误导大家~这一节,主要讲的 是如何显示文章列表和让用户修改文章,小编预告一下(一 ...

随机推荐

  1. SciPy 信号处理

    章节 SciPy 介绍 SciPy 安装 SciPy 基础功能 SciPy 特殊函数 SciPy k均值聚类 SciPy 常量 SciPy fftpack(傅里叶变换) SciPy 积分 SciPy ...

  2. JuJu团队12月27号工作汇报

    JuJu团队12月27号工作汇报 JuJu   Scrum 团队成员 今日工作 剩余任务 困难 飞飞 完成data processing 待安排 无 婷婷 调试代码 提升acc 无 恩升 修正eval ...

  3. 第1节 IMPALA:2、架构介绍

    impala的架构以及查询计划: impalad :从节点 对应启动一个impala-server的进程 ,主要负责各种查询计划,官方建议与所有的datanode安装在同一台机器上面 impala-s ...

  4. Java的SPI机制

    目录 1. 什么是SPI 2. 为什么要使用SPI 3. 关于策略模式和SPI的几点区别 4. 使用介绍或者说约定 4.1 首先介绍几个名词 4.2 约定 5. 具体的demo实现 5.1 创建服务提 ...

  5. Java笔记: 初始化块

    Java语言提供了很多类初始化的方法,包括构造器.初始化器等.除了这两种方法之外,我们还可以用初始化块(initialization block)来实现初始化功能. 基本语法 初始化块是出现在类声明中 ...

  6. docker安装并设置开机启动(Linux)

    docker 开机启动: systemctl enable docker 使用的linux系统为CentOS7.2 docker分为CE和EE版本,EE版本收费,一般我们使用CE版本就满足要求了 do ...

  7. UVA 12511/CSU 1120 virus 最长公共上升子序列

    第一次接触一个这最长公共上升子序列 不过其实搞清楚了跟最长公共子序列和 最长上升子序列如出一辙 两重循环,对于当前不相等的,等于前一个的值,相等的,等于比当前A[i]小的最大值+1.弄个临时变量记录最 ...

  8. Day 25:XML解析

    XML解析 xml文件除了给开发者看,更多的情况使用程序读取xml文件的内容.这叫做xml解析 XML解析方式(原理不同) DOM解析 SAX解析 XML解析工具 DOM解析原理: JAXP (ora ...

  9. 【剑指Offer】面试题32 - II. 从上到下打印二叉树 II

    题目 从上到下按层打印二叉树,同一层的节点按从左到右的顺序打印,每一层打印到一行. 例如: 给定二叉树: [3,9,20,null,null,15,7], 3 / \ 9 20 / \ 15 7 返回 ...

  10. CAN网络上新增加的设备与网络上已有设备MAC地址冲突的软件解决方案

    已知 1号的CAN节点的地址是0x1f 2号的CAN 节点的地址是0x1f 要达到的要求是 假设 网络上 CAN1 节点已经工作了,我现在需要在网络上接入CAN2节点. 那么CAN2节点首次上电的时候 ...