使用BootStrap
Bootstrap: 是一个基于 HTML/CSS/JavaScript 的前端框架, 兼容大部分的 jQuery 插件, 它简洁灵活, 提供了大量内置的样式接口,使得 Web 开发更加简单快捷.
- 下载
到官网下载https://getbootstrap.com/,会有三个下载源,第一个(bootstrap)是简易压缩版的,第二个(source code)是源文件,第三个是sass本版的。第一个就足够用
将下载的解药到static文件下。
继承
这里用于一个基础模板用于继承:base.html
<html><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,, initial-scale=1"><!-- Will be replace the page title --><title>{% block title %}Home{% endblock %}</title><link rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap.min.css') }}"></head><body><div class="container"><div class="jumbotron"><!-- Replace the route function to URL: `/` --><h1><a href="{{ url_for('home')}} ">Claymore's Blog</a></h1><p>Welcome to the blog!</p></div>{% block body %}body_content{% endblock %}</div><script src="{{ url_for('static', filename='js/jquery.min.js') }}"></script><script src="{{ url_for('static', filename='js/bootstrap.min.js') }}"></script></body></html>
其他文件继承上面的文件则 代码块里 :extends “base.html”
在主程序中:
|
使用蓝图创建控制器(controller)
mvc中,最后一块是控制器,我们在main.py中已经了解了试图函数的基本用法,我们需要更强大更复杂的方式来将视图函数组织成更机密的整体。
请求构建和销毁,和全局变量
请求中会访问全局变量,所有函数都会访问到它。
Flask中装饰器函数@app.before_request
会在每个请求被创建的时候之前执行它所装饰的函数。@app.teardown_request
会在每个请求结束的时候执行。
全局变量g(为每个特点请求临时存储特定数据,并且是线程安全的。)
自定义错误页面
如果向用户显示浏览器默认的错误页面,会显得特别突兀,而且没有让用户返回主页。
Flask的abort()返回错误页面时,可以用errorhandler装饰器来显示你自己定义的模板。
|
app.errorhandle可以接收一个或者多个http状态码。
使用类描述视图
如果很多视图处理函数都会用到一些通用的功能,我们把他总结成几个函数比较好,这时用类来体现,享受继承的好处。
View类是flask代替视图函数注册路由的另一种实现方式。
dispatch_request函数是一个普通函数,返回了一个HTML字符串。
app.add-url_rule()跟app.route()作用类似,同样是把一个路由返回到一个函数上。
第一个参数定义了绑定的路由,
view_func变量定义了用来处理路由的函数,as_view会把类转成一个试图函数,所以这里第一个参数定义了转成试图函数的名字,使得url_for()之类的函数能够通过这个名字找到,后面的其他参数会直接传递给该试图类的__int__()
方法。
非get方式:
跟普通的函数一样,在使用view类试图的时候,除GET为的其他http请求需要被显式的声明才能使用。
方法视图
处理多种HTTP请求时,会写大量的判断语句:
我们用MethonView(方法视图)来解决。他把每种http请求写成一个同名的类方法。
app.add-url_rule()跟app.route()作用类似,同样是把一个路由返回到一个函数上。
第一个参数定义了绑定的路由.
View_func变量地冠以了处理路由的函数。
蓝图
在Flask中,蓝图(blueprint)是一种用来扩展自已有Flask应用结构的方式。
把共有的东西统一起来,让结构更紧密。
前两个参数是固定的,其他参数规定蓝图去什么位置找文件,如上,对应的页面会渲染templates/blog/home.html.
url_prefix选项会自动把URL前缀添加在这个蓝图所有的路由之前。所以渲染上面的模板实际路径是:127.0.0.1:5000/hh/
使用url_for:
在蓝本中使用url_for()函数和原来在程序中使用不一样,蓝本中的全部端点上加入一个命名空间。
其实这个命名空间就是蓝图的名字(如上blogblue),所以home(函数名)的端点名是bolgblue,其url使用url_for('bolgblue.home')
可以省略蓝本名:url_for('.index')
注册:
最后的if __name__='__main__':
语句之前注册蓝图:app.register_blueprint(blueprint)
要在末尾导入,因为其他文件也要导入蓝本,这样可以避免循环导入依赖。
工厂模式生成应用对象
工厂模式:就是通过某一个接口函数或对象来创建另一个对象,而这个接口函数也称之为工厂函数。 工厂模式使一个类的实例化延迟到其子类。也就是说工厂模式可以推迟到在程序运行的时候才动态决定要创建哪个类的实例,而不是在编译时就必须知道要实例化哪个类。
eg:
|
在主函数main.py中:
|
这时,app.config.from_object(object_name)变为了一个变量,我们在manage.py中将变量传入:
|
目录结构
需求文件
一个txt文件,写了各个扩展的版本pip freeze>requirements.txt
创建一个新的和上面版本一样的虚拟环境:pip install -r requirements.txt
Bcrypt密文存储账户信息
使用明文的方式存储账户数据是一个非常严重的安全隐患,要保护用户的密码,就要使用 哈希算法的单向加密方法。
哈希算法:对于相同的数据,哈希算法总是会生成相同的结果。
单向加密:就是信息在加密之后,其原始信息是不可能通过密文反向计算出来的。
所以,为了账户信息的安全,在数据库中存储的密码应该是被哈希过的哈希值。但是需要注意,哈希算法的种类很多,其中大多是是不安全的,可以被黑客 暴力破解。
暴力破解:通过遍历各种数据的哈希值,来找到匹配的哈希值,从而获取你的密码权限。
所以这里我们使用 Bcrypt 哈希算法,这是一种被刻意设计成抵消且缓慢的哈希计算方式,从而极大的加长了暴力破解的时间和成本,以此来保证安全性。
安装:
pip install Flask-Bcrypt
extensions.py
|
在main.py(__init__
py):导入bcrypt,然后。bcrypt,init_app(app)
数据模型models.py中,对要加密的模型:
|
set_password(self, password)
:在设定密码的时候,将明文密码转换成为 Bcrypt 类型的哈希值。check_password(self, password)
:检验输入的密码的哈希值,与存储在数据库中的哈希值是否一致。
reCAPTCHA实现验证码
reCAPTCHA 的使用起来并不复杂,在注册一个 Google 用户名后,进入到 reCAPTCHA 官网 并输入你的 blog 名(随意填写)和域名(只支持域名和子域名,现在我们暂时使用 localhost,等部署到线上之后也需要将新的域名填入),就会得到一个 Public Key,就可以把它用在你的 reCAPTCHA 插件上了,同时 reCAPTCHA 也支持多个站点。
|
添加验证码控件:
|
页面实现:register.html,去掉继承和括号,以为这里会影响到我的博客。
|
在模板 register 中需要按照 reCAPTCHA 官档给出的方法将 和
应用到该模板中, 验证码才会生效.
Flask Login保护登陆安全
我们每个页面都需要对用户的身份进行认证。在这样的应用场景下, 保存用户的登录状态的功能就显得非常重要了. 为了实现这一功能:
- 第一种方法, 用得最多的技术就是 session 和 cookie,我们会把用户登录的信息存放在客户端的 cookie 里,这样,我们每个页面都从这个 cookie 里获得用户是否已经登录的信息,从而达到记录状态,验证用户的目的.
- 第二种方法, 我们这里会使用 Flask-Login 扩展是提供支撑.
NOTE: 两种方法是不能够共存的.
安装:
pip install flask-login
初始化对象:
extensions.py
|
设置loginManager对象的参数
extensions.py
|
NOTE 1: login_view 指定了登录页面的视图函数
NOTE 2: session_protection 能够更好的防止恶意用户篡改 cookies, 当发现 cookies 被篡改时, 该用户的 session 对象会被立即删除, 导致强制重新登录.
NOTE 3: login_message 指定了提供用户登录的文案
NOTE 4: login_category 指定了登录信息的类别为 info
NOTE 5: 我们需要定义一个 LoginManager.user_loader
回调函数,它的作用是在用户登录并调用 login_user()
的时候, 根据 user_id 找到对应的 user, 如果没有找到,返回None, 此时的 user_id 将会自动从 session 中移除, 若能找到 user ,则 user_id 会被继续保存.
修改用户的数据模型:
|
构建RESTful Flaks API
Rest是人们对通信所做的约束,
- 客户端和服务端关心的业务是完全分离的
- 服务端是无状态的,处理请求所需要的信息都u要求储存在客户端、
- 所有资源必须有同意接口的形式
等,当一个系统满足了所有这些约束,可以被认为它是一个RESTful系统。最常见的形式是由http和json构建的。每种资源都有自己url来定位。
http请求方法 | url | 操作 |
---|---|---|
get | http://host/resource | 返回该资源所有的条目 |
get | http://host/resource/1 | 返回id为1的资源 |
post | http://host/resource | 通过post的表单内容创建一个新的资源 |
put | http://host/resource/1 | 修改id为1的已存在的资源 |
delete | http://host/resource/1 | 删除id为1的资源 |
URI: protocol://hostname[:port]/path
定义了某一类资源
URL: protocol://hostname[:port]/path/[;parameters][?query]#fragment
定义了某一个具体的资源单位
为什么要构建restful api
对于一个 blog application 而言, 其实完全可以不用到 restful api 也能满足日常所需. 加入 restful api 的唯一目标就是加强该项目的可扩展性, 为后期所要实现的诸如: 博客迁移/数据备份/功能扩展 提供统一且可靠的接口.