狼书和狗书里面都有博客这个案例,但狼书相对更加详细。
要点如下:
1.工厂函数
工厂函数里完成创建app
app = Flask('blog')
插件的初始化
博客里用到不少插件,可以规整到extensions.py里面,然后在工厂函数中进行初始化。
Bootstrap,SQLAlchemy,Mail,CKEditor,Moment,LoginManager,CSRFProtect
举例说明:
extension.py
from flask_bootstrap import Bootstrap
from flask_sqlalchemy import SQLAlchemy
bootstrap = Bootstrap()
db = SQLAlchemy()
__init.py__ 初始化
def register_extensions(app):
bootstrap.init_app(app)
db.init_app(app)
蓝图
蓝图的定义:蓝本实例以及一系列注册在蓝本实例上的操作的集合被称为一个蓝本。可以吧蓝本想象成一个模子,它描述了程序某一部分的细节,定义了路由,错误处理器,上下文处理器等等,然而它本身不发挥作用,只有注册到程序上时,才会有作用。
看起来不是很好理解,举个例子。
admin.py
admin_bp = Blueprint('admin',__name__) 实例
操作
@admin_bp.route('/post/manage')
@login_required
def manage_post():
page = request.args.get('page',1,type=int)
pagination = Post.query.order_by(Post.timestamp.desc()).paginate(page,per_page=10)
posts = pagination.items
return render_template('admin/manage_post.html',pagination=pagination,posts=posts)
注册
app.register_blueprint(admin_bp,url_prefix='/admin')
上下文处理器
翻一下上下文处理器的定义。
如果多个模板需要使用同一变量,最好的方法是设置一个模板全局变量。flask 提供了app.context_processor装饰器。
当我们调用render_template()函数渲染任意一本模板时,所有使用app.context_processor 注册的模板都会被执行,这些函数的返回值将会被添加模板中。
看例子西面返回的这个dict,其中的admin,categories,unread_comments 将可以在后面任意的模板中调用,而不需要再额外传参。
def register_template_context(app):
#上下文处理器
@app.context_processor
def make_template_context():
admin = Admin.query.first()
categories = Category.query.order_by(Category.name).all()
if current_user.is_authenticated:
unread_comments = Comment.query.filter_by(reviewed=False).count()
else:
unread_comments = None
return dict(admin=admin,categories=categories,unread_comments=unread_comments)
2.数据模型
有一个特殊的点:邻接链表关系,外键是自己的id,详细可以看书。
3.宏
1)render_nav_item 渲染导航链接,点哪个链接,哪个会被激活
激活状态和非激活状态,调用这个宏,自动实现
2)分页 render_pagination(pagination)
传参过来就行了,自动实现分页效果
4.分页
分页除了在模板中调用宏之外,在蓝图中也需要对此进行处理
我这里因为没有写配置文件,所以直接将每页的条数写死的。配合上面的分页宏一起使用。
这里依赖于page这个传参,默认是1,点到后面的时候page会发生改变,因此页面数据发生改变。
@blog_bp.route('/')
def index():
posts = Post.query.order_by(Post.timestamp.desc()).all()
page = request.args.get('page',1,type=int)
#per_page = current_app.config['BLOG_POST_PER_PAGE']
pagination = Post.query.order_by(Post.timestamp.desc()).paginate(page=page,per_page=10)
posts = pagination.items
return render_template('blog/index.html',pagination=pagination,posts=posts)
5.模态框
点击分享,弹出模态框,里面是固定链接
都是使用的bootstrap里面的组件。说实话哪些样式看得头大,不如去官方看看,一般都能找到示例
可查阅资料bootstrap官方组件中文文档:https://v4.bootcss.com/docs/components/buttons/
6.flask-login,管理用户认证
1)将flask-login的插件引入,同之前的插件方式 ,然后去工厂函数里去初始化
from flask_login import LoginManager
login_manager = LoginManager()
2)判断用户的状态,让用户类继承Flask-login提供的UserMixin类
class Admin(db.Model,UserMixin):
3)用户加载函数
当我们调用current_user的时候,flask-login会调用用户加载函数并返回对应的用户对象
@login_manager.user_loader
def load_user(user_id):
from blog.models import Admin
user = Admin.query.get(int(user_id))
return user
调用:
4)视图保护
要求用户登录后才能进行某些操作,通过装饰器@login_required
5)未登录访问了@login_required的视图会自动重定向到登录视图,设置一下提示信息及其等级
login_manager = LoginManager()
login_manager.login_view = 'auth.login'
login_manager.login_message_category = 'warning'
login_manager.login_message = '请先登录'
7.CSRF保护
同样先去插件里去注册下
from flask_wtf import CSRFProtect
csrf = CSRFProtect()
__init__.py
csrf.init_app(app)
表单中必须使用CSRFProtect提供的csrf_token()函数渲染包含CSRF令牌的隐藏字段,字段的name值需要设为csrf_token.