前言:本文是学习网易微专业的《python全栈工程师 - Flask高级建站》课程的笔记,欢迎学习交流。同时感谢老师们的精彩传授!
一、课程目标
- 重构目标
- 钩子函数Blueprint.before_request
- 网站配置加载
二、详情解读
2.1.重构目标
2.1.1.用户角色
一个用户因为他的身份的不同,在网站中所具有的权限也不同,这种就称为用户角色,最简单的网站用户角色分为:匿名用户、登录用户、管理员
用户角色 | 说明 |
---|---|
匿名用户 | 没有进行登录的用户,即使已经注册成为网站会员 |
登录用户 | 经过登录后,赋予了会员身份的用户 |
管理员 | 具有管理网站能力的登录用户 |
2.1.2.匿名用户行为
2.1.3.登录用户行为
2.1.4.管理员行为
2.1.5.重构目标
1.更有效的根据用户的角色控制用户的行为
匿名用户可访问路径:
网站首页 - /
登录页面 - /login
注册页面 - /register
文章分类浏览 - /artilce/cate/
文章详细浏览 - /article/view/
2.登录用户可以访问匿名用户访问的所有页面
登录用户可访问路径:
注册信息修改 - /member/info/edit
文章发布 - /memeber/article/add
文章管理 - /member/article/list
文章删除 - /member/article/delete
文章修改 - /member/article/edit
3.管理员用户可以访问匿名用户访问的所有页面,管理员角色与普通会员并不相同,一般不需要拥有进入普通会员相关页面
管理员可访问路径:
会员管理 - /admin/user/list
、/admin/user/edit
、/admin/user/delete
文章管理 - /admin/article/list
、/admin/article/add
分类管理 - /admin/cate/list
、/admin/cate/add
、/admin/cate/edit
、/admin/cate/delete
2.2.代码调整
2.2.1.代码调整 - 后台管理
新增admin
目录,所有与管理员操作相关的视图函数移到此目录下。后台管理有专用的后台界面
2.2.1.代码调整 - 会员中心
新增member
目录和,所有会员操作相关的视图函数移到此目录下。会员中心有专用的界面
实操1:后台管理部分
Step1
:在项目目录下,新建admin
目录,并新建admin_app.py
文件,写入以下代码:
# -*- coding=utf-8 -*-
from flask import request, session, redirect, url_for, render_template
from flask import Blueprint
from libs import login_required
admin_app = Blueprint('admin_app', __name__)
# before_request钩子函数的作用:
# 当请求进来的时候,首先执行下面的is_admin()函数
# 只要访问admin_app,就会检查是否已经登录
@admin_app.before_request
@login_required
def is_admin():
print(session['user'])
if session['user'] != 'admin':
return redirect(url_for('login'))
@admin_app.route('/')
def admin_index():
return render_template('admin/admin_index.html')
Step2
:新建admin/article.py
文件,写入以下代码:
# -*- coding=utf-8 -*-
from flask import request, session, render_template, redirect, url_for
from .admin_app import admin_app
from models import Article, Category
from libs import db
import json
@admin_app.route('/article/post', methods=['GET', 'POST'])
def article_post():
if request.method == 'POST':
cate_id = request.form['cate']
title = request.form['title']
intro = request.form['intro']
content = request.form['content']
article = Article(
cate_id = cate_id,
title = title,
intro = intro,
content = content,
author = session['user']
)
message = None
try:
db.session.add(article)
db.session.commit()
message = {'message': '发布成功'}
except Exception as e:
db.session.rollback()
message = {'message': str(e)}
return json.dumps(message)
return render_template('admin/article/article_post.html')
# 获得文章列表
@admin_app.route('/article/list/<int:page>', methods=['GET', 'POST'])
@admin_app.route('/article/list', default={'page': 1}, methods=['GET', 'POST'])
def article_list(page):
if request.method == 'POST':
q = request.form['q']
condition = { request.form['field']: q}
if request.form['field'] == 'title':
condition = Article.title.like('%%%s%%' % q)
else:
condition = Article.content.like('%%%s%%' % q)
if request.form['order'] == '1':
order = Article.id.asc()
else:
order = Article.id.desc()
res = Article.query.filter(condition).order_by(order).paginate(page, 10)
else:
res = Article.query.paginate(page, 10)
# 无论搜索还是默认查看,都是翻页处理
articles = res.items
pageList = res.iter_pages()
return render_template('admin/article/article_list.html', articles = articles,
pageList = pageList
)
# 根据文章id删除文章
@admin_app.route('/article/delete/<int:article_id>')
def article_delete(article_id):
article = Article.query.get(article_id)
db.session.delete(article)
db.session.commit()
return redirect(url_for('.article_list'))
# 文章修改
@admin_app.route('/article/edit/<int:article_id>', methods=['GET', 'POST'])
def article_edit(article_id):
article = Article.query.get(article_id)
if request.form == 'POST':
article.cate_id = request.form['cate']
article.title = request.form['title']
article.intro = request.form['intro']
article.content = request.form['content']
db.session.commit()
return redirect(url_for('.article_list'))
return render_template('admin/article/article_edit.html', article = article)
Step3
:新建admin/category.py
文件,写入以下代码:
# -*- coding=utf-8 -*-
from flask import request, session, render_template, redirect, url_for
from .admin_app import admin_app
from models import Article, Category
from libs import db
import json
#分类视图部分
# 添加分类
@admin_app.route('/category/add_cate', methods=['GET', 'POST'])
def addCate():
message = None
if request.method == 'POST':
cate_name = request.form['name']
cate_order = request.form['order']
category = Category(
cate_name = cate_name,
cate_order = cate_order
)
try:
db.session.add(category)
db.session.commit()
message = '分类添加成功'
except Exception as e:
db.session.rollbck()
message = '发生了错误:' + str(e)
return render_template('amdin/category/category_add.html', message=message)
# 获得分类列表
@admin_app.route('/category/cate_list')
def cateList():
cates = Category.query.order_by(Category.cate_order.desc()).all()
return render_template('admin/category/category_list.html', cates=cates)
# 删除分类
@admin_app.route('/category/cate_delete/<int:cate_id>')
def deleteCate(cate_id):
cate = Category.query.get(cate_id)
db.session.delete(cate)
db.session.commit()
return render_template('admin/category/category_list.html')
# 分类修改
@admin_app.route('/cate_edit/<int:cate_id>', methods=['GET', 'POST'])
def editCate(cate_id):
category = Category.query.get(cate_id)
if request.method == 'POST':
category.cate_name = request.form['name']
category.cate_order = request.form['order']
db.session.commit()
return redirect(url_for('.cateList'))
return render_template('category/edit.html', category=category)
Step4
:新建admin/user.py
文件,写入以下代码:
# -*- coding=utf-8 -*-
from flask import request, session, render_template, redirect, url_for
from .admin_app import admin_app
from models import User
from libs import db
import json
# 验证用户名是否重复
def validate_username(username):
return User.query.filter_by(username=username).first()
# 获得用户列表
# 如果用户刚进入列表页是访问http://127.0.0.1/user/list
# 与“/list/<int:page>"不匹配,提供一个默认带有page默认值的路由
@admin_app.route('/user/list/<int:page>', methods=['GET', 'POST'])
@admin_app.route('/user/list', defaults={'page': 1}, methods=['GET', 'POST'])
def userList(page):
if request.method == 'POST':
q = request.form['q']
condition = { request.form['field']: q}
if request.form['field'] == 'realname':
condition = User.realname.like('%%%s%%' % q)
else:
condition = User.username.like('%%%s%%' % q)
if request.form['order'] == '1':
order = User.id.asc()
else:
order = User.id.desc()
res = User.query.filter_by(condition, User.sex==request.form['sex']).order_by(order).paginate(page, 10)
else:
res = User.query.paginate(page, 10)
#无论搜索还是默认查看,都是翻页处理
users = res.items
pageList = res.iter_pages()
return render_template('admin/user_list.html', users=users,
pageList=pageList,
page=res.pages,
total=res.total
)
# 根据用户id删除用户
@admin_app.route('/delete/<int:user_id>')
def deleteUser(user_id):
user = User.query.get(user_id)
db.session.delete(user)
db.session.commit()
return redirect(url_for('.userList'))
# 用户信息修改
@admin_app.route('/user/edit/<int:user_id>', methods=['GET', 'POST'])
def editUser(user_id):
user = User.query.get(user_id)
if request.method == 'POST':
user.username = request.form['username']
user.realname = request.form['name']
user.sex = request.form['sex']
user.mylike = '|'.join(request.form.getlist('like'))
user.city = request.form['city']
user.intro = request.form['intro']
db.session.commit()
return redirect(url_for('.userList'))
return render_template('admin/user/user_edit.html', user=user)
Step5
:新建admin/__init__.py
文件,写入以下代码:
from .admin_app import admin_app, admin_index, is_admin
from .article import *
from .category import *
from .user import *
实操2:会员中心部分
Step1
:在项目目录下,新建member
目录,并新建member_app.py
文件,写入以下代码:
# -*- coding=utf-8 -*-
from flask import request, session, redirect, session, url_for, render_template
from flask import Blueprint
from libs import login_required
member_app = Blueprint('member_app', __name__)
@member_app.before_request
@login_required
def is_login():
print(session['user'])
@member_app.route('/')
def member_index():
print('hello')
return render_template('member/member_index.html')
Step2
:新建member/article.py
文件,写入以下代码:
# -*- coding=utf-8 -*-
from flask import request, session, render_template, redirect, url_for
from .member_app import member_app
from models import Article, Category
from libs import db
import json
@member_app.route('/article/post', methods=['GET', 'POST'])
def article_post():
if request.method == 'POST':
cate_id = request.form['cate']
title = request.form['title']
intro = request.form['intro']
content = request.form['content']
article = Article(
cate_id = cate_id,
title = title,
intro = intro,
content = content,
author = session['user']
)
message = None
try:
db.session.add(article)
db.session.commit()
message = {'message': '发布成功'}
except Exception as e:
db.session.rollback()
message = {'message': str(e)}
return json.dumps(message)
return render_template('member/article/article_post.html')
# 获得文章列表
@member_app.route('/article/list/<int:page>', methods=['GET', 'POST'])
@member_app.route('/article/list', defaults={'page': 1}, methods=['GET', 'POST'])
def article_list(page):
if request.method == 'POST':
q = request.form['q']
condition = { request.form['field']: q}
if request.form['field'] == 'title':
condition = Article.title.like('%%%s%%' % q)
else:
condition = Article.content.like('%%%s%%' % q)
if request.form['order'] == '1':
order = Article.id.asc()
else:
order = Article.id.desc()
res = Article.query.filter(Article.author == session['user']).filter(condition).order_by(order).paginate(page, 10)
else:
res = Article.query.filter(Article.author == session['user']).paginate(page, 10)
# 无论搜索还是默认查看,都是翻页处理
articles = res.items
pageList = res.iter_pages()
return render_template('member/article/article_list.html', articles = articles,
pageList = pageList
)
# 根据文章id删除文章
@member_app.route('/article/delete/<int:article_id>')
def article_delete(article_id):
article = Article.query.get(article_id)
# 只能删除自己的文章
if article.author == session['user']:
db.session.delete(article)
db.session.commit()
return redirect(url_for('.article_list'))
# 文章修改
@member_app.route('/article/edit/<int:article_id>', methods=['GET', 'POST'])
def article_edit(article_id):
article = Article.query.get(article_id)
if request.form == 'POST':
# 只能修改自己的文章
if article.author == session['user']:
article.cate_id = request.form['cate']
article.title = request.form['title']
article.intro = request.form['intro']
article.content = request.form['content']
db.session.commit()
return redirect(url_for('.article_list'))
return render_template('member/article/article_edit.html', article = article)
Step3
:新建member/user.py
文件,写入以下代码:
# -*- coding=utf-8 -*-
from flask import request, session, render_template, redirect, url_for
from .member_app import member_app
from models import User
from libs import db
import json
# 用户信息修改
@member_app.route('/user/Edit', methods=['GET', 'POST'])
def userEdit():
# 普通会员只能修改自己的资料
# 修改资料的时候还需要验证密码
user = User.query.filter_by(username=session['user']).one()
if request.method == 'POST':
user.username = request.form['username']
user.realname = request.form['name']
user.sex = request.form['sex']
user.mylike = '|'.join(request.form.getlist('like'))
user.city = request.form['city']
user.intro = request.form['intro']
db.session.commit()
return render_template('member/info/info_edit.html', user=user)
Step3
:新建member/__init__.py
文件,写入以下代码:
# -*- coding=utf-8 -*-
from .member_app import member_app, is_login, member_index
from .article import *
from .user import *
Step4
:在app.py
中引入admin_app
和member_app
并注册蓝印:
.
.
.
from flask import session
# 新增下面这两行
from admin import admin_app
from member import member_app
.
.
.
app.register_blueprint(upload_app, url_prefix="/upload")
# 新增下面这两行
app.register_blueprint(admin_app, url_prefix="/admin")
app.register_blueprint(member_app, url_prefix="/member")
.
.
.
2.3.钩子函数before_request
2.3.1.Blueprint.before_request
通过before_request
装饰的函数是在request
被视图处理之前就会执行,因此我们可以在蓝印实例上,使用此装饰函数,这样就避免在每一个需要验证身份的视图函数上通过@login_required
装饰
@admin_app.before_request
@login_required
def is_admin():
pass
2.4.网站配置加载
2.41.网站配置
随着网站的功能越来越多,网站的各种参数配置也在增加,可以在一个文件里专门配置各类参数,然后通过在app.py
中加载参数,从而提高代码的整洁性。
增加配置文件settings.py
,通过app.config.from_object(配置对象)
方式加载。
实操3:
Step1
:在项目目录下,新建settings.py
文件,写入以下代码:
# -*- coding=utf-8 -*-
class BaseConfig:
SQLALCHEMY_TRACK_MODIFICATIONS = True
SQLALCHEMY_DATABASE_URI = "sqlite:///my.db"
ALLOW_UPLOAD_TYPE = ["image/jpeg", "image/png", "image/gif"]
SECRET_KEY = "123456"
class DevelopmentConfig(BaseConfig):
pass
class ProductionConfig(BaseConfig):
pass
config = {
'development': DevelopmentConfig,
'produciton': ProductionConfig
}
Step2
:修改app.py
文件:
.
.
.
from member import member_app
# 新增下面这一行
from settings import config
app = Flask(__name__)
# 将下面这四个配置删除,因为配置已经移到settings.py文件了
# app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
# app.config['SQLALCHEMY_DATABASE_URI'] = "sqlite:///my.db"
# app.config['ALLOW_UPLOAD_TYPE'] = ["image/gif", "image/png", "image/jpg", "image/jpeg"]
# app.secret_key = "123456"
# 新增下面这一行,这里表示加载开发环境的配置
app.config.from_object(config['development'])
.
.
.
三、课程小结:
- 用户角色
实现用户角色管理,需要通过代码重构来实现。 - 代码重构
- 配置加载
通过配置加载,可以根据不同的环境加载不同的配置