一,前台

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. AJAX的兼容处理方式

    AJAX在网站服务中使用到频率很高,也需要考虑各个浏览器版本的兼容性,本示例中详细介绍简单快捷的处理兼容性问题. <!DOCTYPE HTML> <html> <head ...

  2. window进行缩放时左侧菜单高度随之变化

    window.onresize = function(){ $(); }

  3. IDEA 单行注释与代码对齐

    效果 修改步骤 Settings -> Editor -> Code Style (1)修改.java文件的注释 comment   评论.注释.意见. (2)修改.html文件的注释 ( ...

  4. Python 2 与 3 共存了 11 年,新年就要和它道别

    在 Python 3.9 都已经进入 dev 版本的 2020 年,Python 2 终于要和我们告别了. 2 and 3 Python 2 第一个版本发布于 2000 年 10 月 16 日,到今年 ...

  5. 软件环境常识 --dev sit uat

    DEV环境:DEV顾名思义就是develop,即代码开发的环境. SIT环境:System Integration Test系统集成测试,开发人员自己测试流程是否走通. UAT环境:User Acce ...

  6. sklearn调用逻辑回归算法

    1.逻辑回归算法即可以看做是回归算法,也可以看作是分类算法,通常用来解决分类问题,主要是二分类问题,对于多分类问题并不适合,也可以通过一定的技巧变形来间接解决. 2.决策边界是指不同分类结果之间的边界 ...

  7. 吴裕雄--天生自然JAVA面向对象高级编程学习笔记:包装类

    public class WrapperDemo01{ public static void main(String args[]){ int x = 30 ; // 基本数据类型 Integer i ...

  8. ubuntu安装discourse论坛----结合在apache服务上建立虚拟主机

    指导操作:https://github.com/discourse/discourse/blob/master/docs/INSTALL-cloud.md 一.先安装 Docker / Git: wg ...

  9. sessionManager配置

    在sessionManager配置的时候,有两个属性, 在这个类中,cacheManager是要注入到sessionDao中的,但要求sessionDao实现CacheManagerAware接口 C ...

  10. HiBench成长笔记——(7) 阅读《The HiBench Benchmark Suite: Characterization of the MapReduce-Based Data Analysis》

    <The HiBench Benchmark Suite: Characterization of the MapReduce-Based Data Analysis>内容精选 We th ...