目录
一.管理后台主页
需求:1.希望服务器有记录,登录过的管理员用户可以直接进入详情页面
2.密码验证成功,跳转后台详情页面(需要用到session)
后端代码如下:
@admin_blue.route("/login", methods=["GET", "POST"])
def admin_login():
if request.method == "GET":
user_id = session.get("user_id", None)
is_admin = session.get("is_admin", False)
if user_id and is_admin:
return redirect(url_for("admin.admin_index"))
return render_template("admin/login.html")
username = request.form.get("username")
password = request.form.get("password")
user = User.query.filter(User.mobile == username, User.is_admin == True).first()
if not user:
return render_template("admin/login.html", errmsg="没有该管理员账户")
if not user.check_password(password):
return render_template("admin/login.html", errmsg="密码错误")
session["user_id"] = user.id
session["mobile"] = username
session["nick_name"] = username
session["is_admin"] = True
# return render_template("admin/index.html") # 这样登录成功会显示user undefined
return redirect(url_for("admin.admin_index"))
@admin_blue.route("/index")
@user_login_data
def admin_index():
user = g.user
return render_template("admin/index.html", user=user.to_dict())
二.后台访问权限控制
需求:1.在用户登录之前用请求钩子函数判断用户是否为管理员(普通用户强行跳转到后台详情页),不是跳转到首页
2.普通用户强行跳转至后台详情页面,直接返回首页
2.退出删除session信息
在蓝图的__init__.py中书写代码
@admin_blue.before_request
def check_admin():
is_admin = session.get("is_admin",False)
if not is_admin and not request.url.endswith("/admin/login"):
return redirect("/")
三.用户统计
需求:1.如何获取进一个月的活跃用户量?
2.熟悉timedelta的用法
由于数据库中存放的是假数据,所以用的是创建时间来做的活跃量
@admin_blue.route("/user_count")
def admin_user_count():
total_count = 0
mon_count = 0
day_count = 0
total_count = User.query.filter(User.is_admin == False).count()
t = time.localtime()
mon_begin = "%d‐%02d‐01" % (t.tm_year, t.tm_mon)
mon_begin_date = datetime.strptime(mon_begin, '%Y‐%m‐%d')
mon_count = User.query.filter(User.is_admin == False, User.create_time >= mon_begin_date).count()
t = time.localtime()
day_begin = "%d‐%02d‐%02d" % (t.tm_year, t.tm_mon, t.tm_mday)
day_begin_date = datetime.strptime(day_begin, '%Y‐%m‐%d')
day_count = User.query.filter(User.is_admin == False, User.create_time >= day_begin_date).count()
t = time.localtime()
today_begin = "%d‐%02d‐%02d" % (t.tm_year, t.tm_mon, t.tm_mday)
today_begin_date = datetime.strptime(today_begin, '%Y‐%m‐%d')
active_count = []
active_date = []
for i in range(0, 30):
begin_data = today_begin_date - timedelta(days=i)
end_data = today_begin_date - timedelta(days=(i - 1))
count = User.query.filter(User.create_time >= begin_data, User.create_time < end_data).count()
active_count.append(count)
active_date.append(begin_data.strftime('%Y‐%m‐%d'))
active_count.reverse()
active_date.reverse()
data = {
"active_time": active_date,
"active_count": active_count,
"total_count": total_count,
"mon_count": mon_count,
"day_count": day_count
}
return render_template("admin/user_count.html", data=data)
这个获取时间的方法自己写不出来不要紧,但一定要弄懂其中的方法,换成别的项目也要能灵活运用
四.用户列表
需求:1.分页展示全部用户
2.根据需要展示的用户信息选择转换字典方式
@admin_blue.route("/user_list")
def user_list():
p = request.args.get("p", 1)
try:
p = int(p)
except Exception as e:
p = 1
paginate = User.query.filter(User.is_admin == False).order_by(User.create_time.desc()).paginate(p, 10, False)
items = paginate.items
current_page = paginate.page
total_page = paginate.pages
users = []
for user in items:
users.append(user.to_admin_dict())
data = {
"users": users,
"current_page": current_page,
"total_page": total_page
}
return render_template("admin/user_list.html", data=data)
很多分页代码C来C取的,导致过滤器和表名有些忘记改,需要注意
五.新闻审核
需求:1.分页展示需要被审核的新闻
2.搜索关键字的实现
3.审核通过改变新闻状态码,审核不通过返回新闻状态码并返回不通过的原因(注意原因可有可无,接收时需判断)
新闻审核
@admin_blue.route("/news_review")
def news_review():
p = request.args.get("p", 1)
keywords = request.args.get("keywords")
try:
p = int(p)
except Exception as e:
p = 1
filter = [News.status != 0]
if keywords:
filter.append(News.title.contains(keywords))
paginate = News.query.filter(*filter).order_by(News.create_time.desc()).paginate(p, 10, False)
items = paginate.items
current_page = paginate.page
total_page = paginate.pages
news_list = []
for news in items:
news_list.append(news.to_review_dict())
data = {
"news_list": news_list,
"current_page": current_page,
"total_page": total_page
}
return render_template("admin/news_review.html", data=data)
审核详情
@admin_blue.route("/news_review_detail", methods=["GET", "POST"])
def news_review_detail():
if request.method == "GET":
news_id = request.args.get("news_id")
news = News.query.get(news_id)
data = {
"news": news.to_dict(),
}
return render_template("admin/news_review_detail.html", data=data)
action = request.json.get("action")
news_id = request.json.get("news_id")
news = News.query.get(news_id)
if action == "accept":
news.status = 0
else:
reason = request.json.get("reason")
if not reason:
return jsonify(errno=RET.PARAMERR, errmsg="缺少参数")
news.status = -1
news.reason = reason
db.session.commit()
return jsonify(errno=RET.OK, errmsg="新闻审核成功")
优化:前端未过审的把字体改成红色吧
六.新闻版式编辑
需求:1.根据创建时间排序分页展示全部新闻数据
2.GET请求实现将新闻分类传到前端
3.接收到前端传过来的参数,新闻id将所有信息更改后上传到数据库
展示全部新闻:
@admin_blue.route("/news_edit")
def news_edit():
p = request.args.get("p", 1)
try:
p = int(p)
except Exception as e:
p = 1
paginate = News.query.order_by(News.create_time.desc()).paginate(p, 10, False)
items = paginate.items
current_page = paginate.page
total_page = paginate.pages
news_list = []
for news in items:
news_list.append(news.to_review_dict())
data = {
"news_list": news_list,
"current_page": current_page,
"total_page": total_page
}
return render_template("admin/news_edit.html", data=data)
编辑新闻:
@admin_blue.route("/news_edit_detail", methods=["GET", "POST"])
def news_edit_detail():
if request.method == "GET":
news_id = request.args.get("news_id")
news = News.query.get(news_id)
categories = Category.query.all()
category_list = []
for category in categories:
category_list.append(category.to_dict())
category_list.pop(0)
data = {
"news": news.to_dict(),
"categories": category_list
}
return render_template("admin/news_edit_detail.html", data=data)
title = request.form.get("title")
category_id = request.form.get("category_id")
digest = request.form.get("digest")
index_image = request.files.get("index_image")
content = request.form.get("content")
news_id = request.form.get("news_id")
if not all([title, digest, content, category_id]):
return jsonify(errno=RET.PARAMERR, errmsg="参数有误")
# news = None
news = News.query.get(news_id)
if not news:
return jsonify(errno=RET.NODATA, errmsg="未查询到新闻数据")
if index_image:
try:
index_image = index_image.read()
key = storage(index_image)
except Exception as e:
current_app.logger.error(e)
return jsonify(errno=RET.THIRDERR, errmsg="第三方系统错误")
news.index_image_url = constants.QINIU_DOMIN_PREFIX + key
news.title = title
news.digest = digest
news.content = content
news.category_id = category_id
db.session.commit()
return jsonify(errno=RET.OK, errmsg="新闻编辑成功")
优化:这里要求必须每个参数都要有,照片不是每次都要更改,所以可以判断是否有这个参数,否则老是报第三方错误
七.新闻分类管理
需求:1.GET请求实现将新闻分类传到前端
2.实现添加新闻分类
3.实现修改新闻分类(判断传过来的cid,有是新增,没有是修改)
4.尝试增加删除新闻分类(递归删除)
显示新闻分类:
@admin_blue.route("/news_type")
def news_type():
categories = Category.query.all()
category_list = []
for category in categories:
category_list.append(category.to_dict())
category_list.pop(0)
data = {
"categories": category_list
}
return render_template("admin/news_type.html", data=data)
添加或修改新闻分类:
@admin_blue.route("/add_category",methods = ["GET","POST"])
def add_category():
cid = request.json.get("id")
name = request.json.get("name")
if not name:
return jsonify(errno=RET.PARAMERR, errmsg="参数错误")
if cid:
category = Category.query.get(cid)
category.name = name
else:
category = Category()
category.name = name
db.session.add(category)
db.session.commit()
return jsonify(errno=RET.OK, errmsg="修改成功")
删除新闻分类:
@admin_blue.route("/delete")
def delete():
"""从前端获取分类的category_id"""
category_id = request.args.get("category_id")
news_list = News.query.filter(News.category_id == category_id).all()
if news_list:
for news in news_list:
db.session.delete(news)
db.session.commit()
category = Category.query.get(category_id)
db.session.delete(category)
db.session.commit()
return redirect(url_for("admin.news_type"))
八.后端管理员页面的退出登录
@admin_blue.route("/user_logout")
def user_logout():
session.pop("user_id")
session.pop("nick_name")
session.pop("mobile")
session.pop("is_admin")
return redirect("http://127.0.0.1:5000/admin/login")
redirect写的有些迷幻,应该可以别的方式的,我懒,懒得试了
九.点赞功能的实现
说好的晚上来讲的呢....还不来
总结:
是说后端不要懂前端,excuseme...一个ajax写不出来强行写路径也是没谁了....
今天卡的最久的地方居然是前端获取参数眼瞎然后多加了个S,神奇..
疑问点依然还是后端获取的前端参数和路径没有接口文档在前端找的能力需要加强..!
user_id = session.get("user_id",None) 这句活是获取user_id的session值,没有给user_id指定默认值为None
is_admin = session.get("is_admin",None)同用法
return redirect(url_for("admin.admin_index"))当蓝图中添加前缀后,重定向到函数也需要加前缀