flask——简单博客示例教程(四)

原文:https://blog.csdn.net/u014793102/article/category/9285123

Flask从入门到做出一个博客的大型教程(四)

在开始之前,先来看下项目的整体结构。

 1 flask
 2 ├── app
 3 │   ├── forms.py
 4 │   ├── __init__.py
 5 │   ├── models.py
 6 │   ├── routes.py
 7 │   └── templates
 8 │       ├── base.html
 9 │       ├── index.html
10 │       └── login.html
11 ├── config.py
12 ├── migrations
13 │   ├── alembic.ini
14 │   ├── env.py
15 │   ├── README
16 │   ├── script.py.mako
17 │   └── versions
18 │       ├── 3884184ade03_tables.py
19 ├── myblog.py

5 用户登录模块

在上一部分讲了数据库,也建立了表,但是用户表里的密码字段一直没用,所以这里讲一讲密码字段。如果密码不加密就明文存储在数据库中,这是一个非常不安全而且愚蠢的行为,所以咱们要一起先看看密码的加密存储。

1 (venv) [email protected]:~/flask_tutorial/flask$ flask shell
2 Python 3.6.4 (default, May  3 2018, 19:35:55)
3 [GCC 5.4.0 20160609] on linux
4 App: app [production]
5 Instance: /home/duke/flask_tutorial/flask/instance
6 >>> from werkzeug.security import generate_password_hash
7 >>> hash = generate_password_hash(‘mima‘)
8 >>> hash
9 ‘pbkdf2:sha256:50000$S9FPhxbX$4f164ff06b409769e44556bcd9d8f906ca82998e433410f85898245e40ecd4d3‘

这样就对密码进行了加密,存储在数据库中。但是用户登录输入的密码要怎么和存储在数据库中的这一大串密码进行比对呢?这是就要用到另外一个函数了。

1 >>> from werkzeug.security import check_password_hash
2 >>> check_password_hash(hash,‘haha‘)
3 False
4 >>> check_password_hash(hash,‘mima‘)
5 True

这样就可以根据返回的布尔值来判断用户输入的密码是否正确了。既然掌握了密码的加密和核对,那么就要model进一步完善了。

app/models.py : 完善user模型

 1 # ...
 2 from werkzeug.security import generate_password_hash, check_password_hash
 3
 4
 5
 6 class User(db.Model):
 7     # ...
 8
 9     def set_password(self, password):
10         self.password_hash = generate_password_hash(password)
11
12     def check_password(self, password):
13         return check_password_hash(self.password_hash, password)

user模型修改好了,现在到flask shell中去试一试是否成功能用?

 1 (venv) [email protected]:~/flask_tutorial/flask$ flask shell
 2 Python 3.6.4 (default, May  3 2018, 19:35:55)
 3 [GCC 5.4.0 20160609] on linux
 4 App: app [production]
 5 Instance: /home/duke/flask_tutorial/flask/instance
 6 >>> from app.models import User
 7 >>> u = User(username=‘duke‘,email=‘[email protected]‘)
 8 >>> u.set_password(‘mytest‘)
 9 >>> u.check_password(‘yourtest‘)
10 False
11 >>> u.check_password(‘mytest‘)
12 True

flask中有很多写的非常不错的插件,像flask-migrate就很不错,这里介绍一个flask-login,当然你肯定可以自己从写一个,但是有别人造好的轮子为什么先不体验一下试试呢?

它会:

  • 在会话中存储当前活跃的用户 ID,让你能够自由地登入和登出。
  • 让你限制登入(或者登出)用户可以访问的视图。
  • 处理让人棘手的 “记住我” 功能。
  • 帮助你保护用户会话免遭 cookie 被盗的牵连。
  • 可以与以后可能使用的 Flask-Principal 或其它认证扩展集成。

但是,它不会:

  • 限制你使用特定的数据库或其它存储方法。如何加载用户完全由你决定。
  • 限制你使用用户名和密码,OpenIDs,或者其它的认证方法。
  • 处理超越 “登入或者登出” 之外的权限。
  • 处理用户注册或者账号恢复。
1 (venv) [email protected]:~/flask_tutorial/flask$ pip install flask-login

app/_ _ init_ _.py : 登录模块初始化

1 # ...
2 from flask_login import LoginManager
3
4 app = Flask(__name__)
5 # ...
6 login = LoginManager(app)
7
8 # ...

你用来表示用户的类需要实现这些属性和方法:

  • is_authenticated

    只有通过验证的用户会满足 login_required的条件。

  • is_active

    如果这是一个活动用户且通过验证,账户也已激活,未被停用,也不符合任何你 的应用拒绝一个账号的条件,返回 True 。不活动的账号可能不会登入(当然, 是在没被强制的情况下)。

  • is_anonymous

    如果是一个匿名用户,返回 True 。(真实用户应返回 False 。)

  • get_id()

    返回一个能唯一识别用户的,并能用于从 user_loader 回调中加载用户的 unicode。注意 必须 是一个 unicode —— 如果 ID 原本是 一个 int 或其它类型,你需要把它转换为 unicode

要简便地实现用户类,你可以从 UserMixin 继承,它提供了对所有这些方法的默认 实现。所以上面哔哔这么多,都可以无视它们,哈哈。

app/models.py : 为了使用flask-login,继承UserMixin

1 # ...
2 from flask_login import UserMixin
3
4 class User(UserMixin, db.Model):
5     # ...

因为flask-login对数据库是真的一无所知啊,那怎么获得用户信息呢?所以这里要写一个加载用户信息的函数,因为是从session中读取,所以是id不是int类型,咱们要把它转成int类型哦。

app/models.py : flask-login用户加载函数

1 # ...
2 from app import login
3
4 # ...
5
6 @login.user_loader
7 def load_user(id):
8     return User.query.get(int(id))

还记得视图模块中对登录处理过的方法吗?现在已经学习了这么多,把以前写的完善修改一下吧。

app/routes.py : 视图模块登录方法

 1 # ...
 2 from flask_login import current_user, login_user
 3 from app.models import User
 4
 5 # ...
 6
 7 @app.route(‘/login‘,methods=[‘GET‘,‘POST‘])
 8 def login():
 9     #判断当前用户是否验证,如果通过的话返回首页
10     if current_user.is_authenticated:
11         return redirect(url_for(‘index‘))
12
13     form = LoginForm()
14     #对表格数据进行验证
15     if form.validate_on_submit():
16         #根据表格里的数据进行查询,如果查询到数据返回User对象,否则返回None
17         user = User.query.filter_by(username=form.username.data).first()
18         #判断用户不存在或者密码不正确
19         if user is None or not user.check_password(form.password.data):
20             #如果用户不存在或者密码不正确就会闪现这条信息
21             flash(‘无效的用户名或密码‘)
22             #然后重定向到登录页面
23             return redirect(url_for(‘login‘))
24         #这是一个非常方便的方法,当用户名和密码都正确时来解决记住用户是否记住登录状态的问题
25         login_user(user,remember=form.remember_me.data)
26         return redirect(url_for(‘index‘))
27     return render_template(‘login.html‘,title=‘登录‘,form=form)

登录问题解决了,那么就要解决登出问题了。这个非常简单,直接调用一个方法即可。

app/routes.py : 解决登出问题

1 # ...
2 from flask_login import logout_user
3
4 # ...
5
6 @app.route(‘/logout‘)
7 def logout():
8     logout_user()
9     return redirect(url_for(‘index‘))

好的,现在又新增了一个登出的方法,那么模板也要相应的增加一个登出的地方喽。

app/templates/base.html : 添加登出



1    <div>博客 :
2            <a href="{{ url_for(‘index‘) }}">首页</a>
3            <a href="{{ url_for(‘login‘) }}">登录</a>
4            <a href="{{ url_for(‘logout‘) }}">退出</a>
5        </div>

在你浏览过的大部分网站中,有一部分功能是要你登录后才能使用的,那么在flask中怎么实现这个登录才能使用的功能呢?

app/_ _ init _ _.py : 增加登录限制

1 # ...
2 # 在login = LoginManager(app)后面加上即可
3 login.login_view = ‘login‘

app/routes.py : 继续在视图模块中修改,导入装饰器

1 from flask_login import login_required
2
3 @app.route(‘/‘)
4 @app.route(‘/index‘)
5 #这样,必须登录后才能访问首页了,会自动跳转至登录页
6 @login_required
7 def index():
8     # ...

现在如果你访问首页http:// localhost:5000/ ,你就会发现会自动跳转至登录页,而且地址栏变成http:// localhost:5000/login?next=%2F,但是我想登录后想重定向原本要去的网址,怎么解决?肯定和next这个参数有关系,所以我们要对视图模块的登录函数进行修改。

 1 # ...
 2 from flask import request
 3 from werkzeug.urls import url_parse
 4
 5 #...
 6
 7 @app.route(‘/login‘,methods=[‘GET‘,‘POST‘])
 8 def login():
 9     # ...
10
11         if form.validate_on_submit():
12         user = User.query.filter_by(username=form.username.data).first()
13         if user is None or not user.check_password(form.password.data):
14
15             flash(‘无效的用户名或密码‘)
16
17             return redirect(url_for(‘login‘))
18         login_user(user,remember=form.remember_me.data)
19         #此时的next_page记录的是跳转至登录页面是的地址
20         next_page = request.args.get(‘next‘)
21         #如果next_page记录的地址不存在那么就返回首页
22         if not next_page or url_parse(next_page).netloc != ‘‘:
23             next_page = url_for(‘index‘)
24         #综上,登录后要么重定向至跳转前的页面,要么跳转至首页
25         return redirect(next_page)
26     #...

后端管理的代码都写的差不多了,那就改一改前端的页面吧。

app/templates/index.html : 显示当前用户的用户名和他的内容

 1 {% extends ‘base.html‘ %}
 2
 3         {% block content %}
 4
 5             <h1>你好呀, {{ current_user.username }} !</h1>
 6
 7         {% for post in posts %}
 8             <div><p>{{ post.author.username }} 说:<b>{{ post.body }}</b></p></div>
 9         {% endfor %}
10
11         {% endblock %}

额,下面咱们就要测试一下了,但是测试之前把首页的登录限制和指定的user去掉去掉

1 @app.route(‘/‘)
2 @app.route(‘/index‘)
3 def index():
4     # ...
5     return render_template(‘index.html‘,title=‘我的‘,user=user,posts=posts)

先写入一条测试用例:

 1 (venv) [email protected]:~/flask_tutorial/flask$ flask shell
 2 Python 3.6.4 (default, May  3 2018, 19:35:55)
 3 [GCC 5.4.0 20160609] on linux
 4 App: app [production]
 5 Instance: /home/duke/flask_tutorial/flask/instance
 6 >>> from app import db
 7 >>> from app.models import User,Post
 8 >>> u = User(username=‘duke‘,email=‘[email protected]‘)
 9 >>> u.set_password(‘123456‘)
10 >>> db.session.add(u)
11 >>> db.session.commit()

好的,访问试一试吧!

登录后的界面!

退出后的界面!

登录写好了,也自己能往里面写数据了,但是不方便啊,一点点敲命令进去,反人类啊,不行不行。所以来写一个注册的方法吧!

首先要在表单模块修改喽。

app/forms.py : 添加注册表格

 1 # ...
 2 from wtforms.validators import ValidationError,Email,EqualTo
 3 from app.models import User
 4
 5 # ...
 6
 7 class RegistrationForm(FlaskForm):
 8     username = StringField(‘用户名‘, validators=[DataRequired()])
 9     email = StringField(‘邮箱‘, validators=[DataRequired(), Email()])
10     password = PasswordField(‘密码‘, validators=[DataRequired()])
11     password2 = PasswordField(
12         ‘重复密码‘, validators=[DataRequired(), EqualTo(‘password‘)])
13     submit = SubmitField(‘注册‘)
14     #校验用户名是否重复
15     def validate_username(self, username):
16         user = User.query.filter_by(username=username.data).first()
17         if user is not None:
18             raise ValidationError(‘用户名重复了,请您重新换一个呗!‘)
19     #校验邮箱是否重复
20     def validate_email(self, email):
21         user = User.query.filter_by(email=email.data).first()
22         if user is not None:
23             raise ValidationError(‘邮箱重复了,请您重新换一个呗!‘)

注册表格处理都写好了,那没页面怎么能行?

app/templates/register.html : 写注册界面



 1 {% extends "base.html" %}
 2
 3 {% block content %}
 4     <h1>注册</h1>
 5     <form action="" method="post">
 6         {{ form.hidden_tag() }}
 7         <p>
 8             {{ form.username.label }}<br>
 9             {{ form.username(size=32) }}<br>
10             {% for error in form.username.errors %}
11             <span style="color: red;">[{{ error }}]</span>
12             {% endfor %}
13         </p>
14         <p>
15             {{ form.email.label }}<br>
16             {{ form.email(size=64) }}<br>
17             {% for error in form.email.errors %}
18             <span style="color: red;">[{{ error }}]</span>
19             {% endfor %}
20         </p>
21         <p>
22             {{ form.password.label }}<br>
23             {{ form.password(size=32) }}<br>
24             {% for error in form.password.errors %}
25             <span style="color: red;">[{{ error }}]</span>
26             {% endfor %}
27         </p>
28         <p>
29             {{ form.password2.label }}<br>
30             {{ form.password2(size=32) }}<br>
31             {% for error in form.password2.errors %}
32             <span style="color: red;">[{{ error }}]</span>
33             {% endfor %}
34         </p>
35         <p>{{ form.submit() }}</p>
36     </form>
37 {% endblock %}

注册页面写好了,那登录界面得给它一个链接才行,所以到登录面添加个超链接吧。

app/templates/login.html : 添加一个注册的链接。

1 <h1>登 录</h1>
2 <p>还没注册? <a href="{{ url_for(‘register‘) }}">点击一下就可以注册哦!</a></p>

现在什么都准备好了,就差视图模块进行一个总结啦,进入视图模块,添加方法吧!

 1 # ...
 2 from app import db
 3 from app.forms import RegistrationForm
 4
 5 # ...
 6
 7 @app.route(‘/register‘, methods=[‘GET‘, ‘POST‘])
 8 def register():
 9     # 判断当前用户是否验证,如果通过的话返回首页
10     if current_user.is_authenticated:
11         return redirect(url_for(‘index‘))
12     form = RegistrationForm()
13     if form.validate_on_submit():
14         user = User(username=form.username.data, email=form.email.data)
15         user.set_password(form.password.data)
16         db.session.add(user)
17         db.session.commit()
18         flash(‘恭喜你成为我们网站的新用户!‘)
19         return redirect(url_for(‘login‘))
20     return render_template(‘register.html‘, title=‘注册‘, form=form)

注册页面哦 !

原文地址:https://www.cnblogs.com/heymonkey/p/11721350.html

时间: 2024-10-06 13:38:24

flask——简单博客示例教程(四)的相关文章

flask——简单博客示例教程(二)

原文:https://blog.csdn.net/u014793102/article/category/9285123 Flask从入门到做出一个博客的大型教程(二) 在开始之前,先来看下项目的整体结构. 1 flask 2 ├── app 3 │ ├── __init__.py 4 │ ├── routes.py 5 │ └── templates 6 │ ├── base.html 7 │ └── index.html 8 ├── myblog.py 3 表单 前面已经讲了一个简单的hel

flask——简单博客示例教程(一)

原文:https://blog.csdn.net/u014793102/article/category/9285123 Flask从入门到做出一个博客的大型教程(一) 本项目全部在虚拟环境中运行,因此请参照前面的文章,链接为https://blog.csdn.net/u014793102/article/details/80302975 建立虚拟环境后,再接着完成本教程的学习. 0 开始之前 网上看了很多教程,都不是很满意,因此自己写一个大型教程,从入门到做出一个比较完整的博客.此次教程不是直

flask——简单博客示例教程(三)

原文:https://blog.csdn.net/u014793102/article/category/9285123 Flask从入门到做出一个博客的大型教程(三) 在开始之前,先来看下项目的整体结构. 1 flask 2 ├── app 3 │ ├── forms.py 4 │ ├── __init__.py 5 │ ├── routes.py 6 │ └── templates 7 │ ├── base.html 8 │ ├── index.html 9 │ └── login.html

项目实战(连载):基于Angular2+Mongodb+Node技术实现的多用户博客系统教程(4)

本章主要讲什么(一句话)? <项目实战:基于Angular2+Mongodb+Node技术实现的多用户博客系统教程(4)> -- 基于Node的Express项目环境框架搭建 一.前言 从本节开始,我们将正式[多用户博客系统]的项目开发工作.首先我们先从后台Node部分开始做起,一步步带领大家完成整个博客系统的开发. 本篇将主要帮助大家把Node环境下的Express框架搭建起来,后继后台将会在这个框架上进行扩展与业务逻辑开发. 二.项目环境 Node.js: v 6.x Express: v

java基于MVC的简单博客系统

原文:java基于MVC的简单博客系统 源代码下载地址:http://www.zuidaima.com/share/1550463595760640.htm 采用技术:jsp+servlie+javaBean+mysql+ajax

Word2016编辑博客发布至博客园教程

用word2016编辑博客发布至博客园教程 博客园的编辑器不够灵活,且官方推荐的windows live writer不再更新,不知什么原因windows10安装不了,markdown的语法不太熟悉,所以用word编辑博客既方便又快捷. 点击文件à共享à发布至博客 在弹出对话中点击立即注册à在"选择博客提供商中选中其他"à点击下一步 在弹出注册框中设置如下: 再点击图片选项,在弹出框中选择"我的博客提供商 测试 博客效果 原文地址:https://www.cnblogs.co

Django 系列博客(十四)

Django 系列博客(十四) 前言 本篇博客介绍在 html 中使用 ajax 与后台进行数据交互. 什么是 ajax ajax(Asynchronous Javascript And XML)翻译成中文就是''异步 JavaScript 和 XML''.即使用 JavaScript 语言与服务器进行异步交互,传输的数据为 XML(现在更多地使用 json). 同步交互:客户端发出一个请求后,需要等待服务器响应结束,才能发出第二个请求: 异步交互:客户端发出一个请求后,无需等待服务器响应结束,

从0开始使用python flask编写博客网站(1)

在学完flask教程时候,总是会遇到难以自己写项目的问题.在第一次看狗书的时候,作者从单文件马上就到了多文件的项目组织,当时也是仔细看,慢慢打代码才渐渐的明白了flask的项目组织方法,当明白了又感觉很简单..使用中多思考多打代码才能日有所得,愿你我共同成长. 1. 编写项目骨架 一个博客网站需要什么呢? 首页展示博客文章的概览 单页文章展示 后台管理 管理员登录 增加文章 修改文章 删除文章 错误页面 这就是一个最简单的博客需要的东西了.那么我分为三个路由负责三个大的功能.再加上静态文件,模板

【阿里云产品公测】ACE安装WordPress博客图文教程

阿里云ace搭建wordpress图文教程 C?ib_K* 按照大大说的,wordpress确实能够轻松创建,只有几步. \0l>q ,    do*}syQ`O   ml0.$z   我想说,小白的世界技术大大还是不了解.想当初我了解一下怎么使用svn就研究了快一星期,天天下载软件,卸载软件,查看教程. 更别说前两天终于稍稍懂了一点的git(知道怎么上传文件了.)更是在年初bae支持git代码的时候研究,可是一直不入其门,拖拖踏踏就是大半年的时间. 555,不说了,说多了都是泪. uwf 5!