博客项目

上一篇内容完善

  • 自定义字段验证函数

    class RegisterForm(FlaskForm):
    ...
    def validate_username(self, field):
    user = User.query.filter(User.username == field.data).first()
    if user:
    raise ValidationError('该用户名已注册,请选用其他名称注册') def validate_email(self, field):
    user = User.query.filter(User.email == field.data).first()
    if user:
    raise ValidationError('该邮箱已注册,请选用其他邮箱注册')
  • 加密存储密码

    from werkzeug.security import generate_password_hash, check_password_hash
    
    class User(db.Model):
    ...
    @property
    def password(self):
    raise AttributeError('你瞅啥?!密码不可读') @password.setter
    def password(self, password):
    # 加密保存密码
    self.password_hash = generate_password_hash(password) # 密码校验,True:校验成功,False:校验失败
    def verify_password(self, password):
    return check_password_hash(self.password_hash, password)

用户登录退出

  • 登录校验逻辑

    @user.route('/login/', methods=['GET', 'POST'])
    def login():
    form = LoginForm()
    if form.validate_on_submit():
    u = User.query.filter(User.username == form.username.data).first()
    if not u:
    flash('无效的用户名')
    elif not u.confirmed:
    flash('账户尚未激活,请激活后再登录')
    elif not u.verify_password(form.password.data):
    flash('无效的密码')
    else:
    flash('登录成功')
    return redirect(url_for('main.index'))
    return render_template('user/login.html', form=form)
  • flask-login扩展

    • 说明:它是一个专门用来管理用户登录退出的扩展库,使用非常方便。
    • 安装:pip install flask-login
    • 使用:
    # 第一步:添加扩展
    from flask_login import LoginManager login_manager = LoginManager() def init_extensions(app):
    ...
    login_manager.init_app(app)
    # 指定登录端点
    login_manager.login_view = 'user.login'
    # 设置提示信息
    login_manager.login_message = '登录后才可访问' # 第二步:让模型类类基础子UserMixin类,以便拥有状态相关方法
    from flask_login import UserMixin class User(UserMixin, db.Model):
    ... # 第三步:实现回调函数(根据用户id返回用户对象)
    @login_manager.user_loader
    def load_user(uid):
    return User.query.get(uid)
    • 总结
    状态切换:
    login_user # 还可以完成记住我的功能(时间也可以指定)
    logout_user
    状态查询:
    is_authenticated # 登录状态
    is_anonymous # 匿名状态
    路由保护:
    login_required # 保护需要登录才可访问的路由
    当前用户:
    current_user # 在模板中使用不需要分配

用户信息管理

  • 详情信息展示

    • 添加点击跳转链接及逻辑
    • 书写详情页面的展示效果
  • 修改密码
    • 添加点击跳转链接
    • 模板文件中添加表单(原始密码、新密码、确认密码)
    • 添加点击提交校验的逻辑
#修改密码
@user.route('/modifypassword/',methods=['GET','POST'])
def modify_password():
form = ModifyPasswordForm()
if form.validate_on_submit():
if current_user.verify_password(form.password.data):
current_user.password = form.password_new1.data
flash('修改密码成功')
return redirect(url_for('user.login'))
else:
flash('原始密码错误')
return render_template('user/modify_password.html', form=form)
  • 修改邮箱

    • 添加点击跳转链接
    • 模板文件中添加表单(新邮箱)
    • 添加点击提交校验的逻辑(向新的邮箱地址发送确认邮件,需要携带用户信息及新邮箱地址)
    • 添加邮箱修改确认的校验视图函数(解析携带数据,修改用户邮箱)
#修改邮箱
@user.route('/modifyemail/',methods=['GET','POST'])
def modify_email():
form = ModifyEmailForm()
if form.validate_on_submit():
if current_user.email == form.email.data:
s = Serializer(current_app.config['SECRET_KEY'],expires_in=3600)
token = s.dumps({'id':current_user.id,'email':form.email_new.data})
send_mail('邮箱修改',form.email_new.data,'email/modify_email_activate.html',username=current_user.username,token=token)
flash('请前往新邮箱确认修改')
return redirect(url_for('user.profile'))
else:
flash('原始邮箱不正确')
return render_template('user/modify_email.html',form=form)
  • 找回密码

    • 在登录页面添加找回密码的跳转链接
    • 跳转的模板文件中添加表单(用户名/邮箱地址),提交改为下一步
    • 添加提交的校验逻辑(向用户的邮箱发送邮件,需要携带用户身份信息)
    • 添加重新设置密码的视图函数(给出再次设置密码的表单,并处理提交)
# 找回密码
@user.route('/findpassword/<way>/', methods=['GET', 'POST'])
def find_password(way):
form = FindPasswordForm()
s = Serializer(current_app.config['SECRET_KEY'], expires_in=3600)
if form.validate_on_submit():
u = User.query.filter(
or_(User.username == form.username_email.data, User.email == form.username_email.data)).first()
if u:
token = s.dumps({'id': u.id})
# send_mail('通过用户名找回密码',u.email,'email/find_password_activate.html',username=u.username,token=token)
flash('请前往邮箱确认找回密码')
else:
flash('用户名错误')
return redirect(url_for('user.login'))
return render_template('user/find_password.html', form=form) @user.route('/findpasswordactivate/<token>/', methods=['GET', 'POST'])
def find_password_activate(token):
form = NewPasswordForm()
s = Serializer(current_app.config['SECRET_KEY'])
try:
data = s.loads(token)
except SignatureExpired as e:
flash('token已过期,找回密码失败')
return redirect(url_for('user.login'))
except BadSignature as e:
flash('token有误,找回密码失败')
return redirect(url_for('user.login'))
u = User.query.get(data['id'])
if form.validate_on_submit():
u.password = form.password2.data
db.session.add(u)
flash('找回密码成功')
return redirect(url_for('user.login'))
return render_template('user/new_password.html', form=form)
  • 修改头像

    • 添加点击跳转的链接
    • 添加flask-uploads扩展
    • 添加上传文件表单及校验逻辑
    • 添加上传文件的处理(生成随机文件名、生成缩略图、展示上传文件)
    • 将头像文件名保存到数据库(User模型需要添加字段)
    • 练习:用户详情页面展示用户头像
# 修改头像
@user.route('/icon/', methods=['GET', 'POST'])
def icon():
form = UploadForm()
if form.validate_on_submit():
# 提取上传文件信息
photo = form.photo.data
# 提取文件后缀带点
suffix = os.path.splitext(photo.filename)[1]
# 生成随机文件名
filename = random_string() + suffix
# 用上传对象保存图片,并指定名字
photos.save(photo, name=filename)
# 拼接完整的图片路径
pathname = os.path.join(current_app.config['UPLOADED_PHOTOS_DEST'], filename)
# 缩略图操作,打开文件
img = Image.open(pathname)
# 设置图片尺寸
img.thumbnail((32, 32))
# 重新保存,指定完整路径
img.save(pathname)
# 如果当前用户用的是默认头像,则不用删除
# 若果用的不是默认头像,为减少存储需要先删除原来的头像
if current_user.icon != 'default.jpg':
# os.remove删除项目本地文件
os.remove(os.path.join(current_app.config['UPLOADED_PHOTOS_DEST'], current_user.icon))
# 新的头像准备好了,添加到model里
current_user.icon = filename
# 手动保存,可有可无
db.session.add(current_user)
# 头像已经保存到了static和model中,为了展示头像,可以把图片的路径传给模板
# 静态文件是固定格式 注:不能直接写图片名,那样就写死了
# 不同用户有独自的头像,所以用current_user.icon进行拼接
img_url = url_for('static', filename='upload/' + current_user.icon)
return render_template('user/icon.html', form=form, img_url=img_url)

博客管理

  • 博客发表

    • 添加发表博客表单及校验逻辑
    • 添加博客模型,用来保存博客
    • 添加博客校验保存
  • 博客展示(练习)

Flask—08-建立自己的博客(02)的更多相关文章

  1. 用 Flask 来写个轻博客 (37) — 在 Github 上为第一阶段的版本打 Tag

    Blog 项目源码:https://github.com/JmilkFan/JmilkFan-s-Blog 目录 目录 前文列表 第一阶段结语 打 Tag 前文列表 用 Flask 来写个轻博客 (1 ...

  2. 用 Flask 来写个轻博客 (32) — 使用 Flask-RESTful 来构建 RESTful API 之一

    目录 目录 前文列表 扩展阅读 RESTful API REST 原则 无状态原则 面向资源 RESTful API 的优势 REST 约束 前文列表 用 Flask 来写个轻博客 (1) - 创建项 ...

  3. 用 Flask 来写个轻博客 (25) — 使用 Flask-Principal 实现角色权限功能

    目录 目录 前文列表 扩展阅读 Flask-Principal 使用 Flask-Principal 来实现角色权限功能 添加 Role Model 在 Manager shell 中手动的添加角色 ...

  4. 用 Flask 来写个轻博客 (6) — (M)VC_models 的关系(one to many)

    Blog 项目源码:https://github.com/JmilkFan/JmilkFan-s-Blog 目录 目录 前文列表 扩展阅读 前言 一对多 再一次 sync db How to use ...

  5. 用 Flask 来写个轻博客 (3) — (M)VC_连接 MySQL 和 SQLAlchemy

    目录 目录 前文列表 扩展阅读 前言 Models 模型 SQLAlchemy 安装 SQLAlchemy 安装 Mysql 建立 SQLAlchemy 和 Mysql 的连接 前文列表 用 Flas ...

  6. 用 Flask 来写个轻博客

    用 Flask 来写个轻博客 用 Flask 来写个轻博客 (1) — 创建项目 用 Flask 来写个轻博客 (2) — Hello World! 用 Flask 来写个轻博客 (3) — (M)V ...

  7. 用 Flask 来写个轻博客 (36) — 使用 Flask-RESTful 来构建 RESTful API 之五

    目录 目录 前文列表 PUT 请求 DELETE 请求 测试 对一条已经存在的 posts 记录进行 update 操作 删除一条记录 前文列表 用 Flask 来写个轻博客 (1) - 创建项目 用 ...

  8. 用 Flask 来写个轻博客 (35) — 使用 Flask-RESTful 来构建 RESTful API 之四

    Blog 项目源码:https://github.com/JmilkFan/JmilkFan-s-Blog 目录 目录 前文列表 POST 请求 身份认证 测试 前文列表 用 Flask 来写个轻博客 ...

  9. 用 Flask 来写个轻博客 (34) — 使用 Flask-RESTful 来构建 RESTful API 之三

    目录 目录 前文列表 应用请求中的参数实现 API 分页 测试 前文列表 用 Flask 来写个轻博客 (1) - 创建项目 用 Flask 来写个轻博客 (2) - Hello World! 用 F ...

  10. 用 Flask 来写个轻博客 (33) — 使用 Flask-RESTful 来构建 RESTful API 之二

    Blog 项目源码:https://github.com/JmilkFan/JmilkFan-s-Blog 目录 目录 前文列表 扩展阅读 构建 RESTful Flask API 定义资源路由 格式 ...

随机推荐

  1. python全栈开发之路

    一.Python基础 python简介 python数据类型(数字\字符串\列表) python数据类型(元组\字典) python数据类型(集合) python占位符%s,%d,%r,%f prin ...

  2. zookeeper安装及使用

    0. 下载并安装 1. 开机启动 cd  /etc/rc.d/init.d touch zookeeper vi zookeeper #!/bin/bash #chkconfig #descripti ...

  3. Python基础-I/O模型

    一.I/O模型 IO在计算机中指Input/Output,也就是输入和输出.由于程序和运行时数据是在内存中驻留,由CPU这个超快的计算核心来执行,涉及到数据交换的地方,通常是磁盘.网络等,就需要IO接 ...

  4. AdobeCS3DesignPremiumChs_Greendown.cn使用注册机激活失败重新激活操作方法

    解决Adobe Acrobat 9 Pro序列号无效/重新激活方法 1.删除C:\Program Files\Common Files\Adobe\Adobe PCD\cache\cache.db和C ...

  5. Sqlite 数据库分页查询(ListView分页显示数据)

    下面介绍一下我的这个demo. 流程简述: 我在raw文件夹下面放了名称为city的数据库,里面包含全国2330个城市,以及所属省,拼音简写等信息. 首先 在进入MainActivity的时候,创建数 ...

  6. 【Python】卸载完Python3 之后 Python2 无法打开IDLE

    安装官方的Python带Idle但是却无法打开,百度谷歌了几种解决方法,加上自己的实际境况予以解决. 我的python是直接安装在C盘下的. 1.首先是设置环境变量: Path=C:\Python27 ...

  7. ES6入门——正则的扩展

    1.RegExp构造函数 在ES5中,RegExp构造函数的参数有两种情况.第一种情况是参数是字符串,这时第二个参数表示正则表达式的修饰符:第二种情况是,参数是一个正则表示式,这时会返回一个原有正则表 ...

  8. DevExpress 中 GridControl 的数据源DataTable 内容改变后 重新绑定

    1.datatable dt=new datatable(); 2.dt 内容改变 dt.columns.add("col1"); dt.columns.add("col ...

  9. LeetCode-Container With Most Water-zz

    先上代码. #include <iostream> #include <vector> #include <algorithm> using namespace s ...

  10. .net 面向对象程序设计深入](2)UML

    1.用例图简介 定义:用例图主要用来描述“用户.需求.系统功能单元”之间的关系.它展示了一个外部用户能够观察到的系统功能模型图. 类型:动态图 应用:需求分析阶段 2.用例图元素 2.1 参与者(Ac ...