Flask是一个Python编写的Web轻量级框架。
它和Django的联系以及区别:django是一个大而全的web框架,它内置许多模块,flask是一个小而精的轻量级框架只包含基本的配置; Django有模板,表单,路由,基本的数据库管理等等内建功能。Flask只是一个内核,默认依赖于2个外部库: Jinja2 模板引擎和 WSGI工具集–Werkzeug , flask的使用特点是基本所有的工具使用都依赖于导入的形式去扩展,flask只保留了web开发的核心功能。
常用扩展包:
Flask-SQLalchemy:操作数据库;
Flask-script:插入脚本;
Flask-migrate:管理迁移数据库;
Flask-Session:Session存储方式指定;
Flask-WTF:表单;
Flask-Mail:邮件;
Flask-Bable:提供国际化和本地化支持,翻译;
Flask-Login:认证用户状态;
Flask-OpenID:认证;
Flask-RESTful:开发REST API的工具;
Flask-Bootstrap:集成前端Twitter Bootstrap框架;
Flask-Moment:本地化日期和时间;
Flask-Admin:简单而可扩展的管理接口的框架
一、虚拟环境
虚拟环境是隔离的Python解释器环境。通过创建虚拟环境,可以拥有一个独立的Python解释器环境,相当于对全局的python解释器环境拷贝一份私有的副本, 这样做的好处是可以为每一个项目创建独立的Python解释器环境,因为不同的项目常常会依赖不同版本的库或Python版本。使用虚拟环境可以保持全局Python解释器环境的干净,避免包和版本的混乱,并且可以方便地区分和记录每个项目的依赖,所谓环境追根溯源也是文件,既然是文件就支持拷贝到各个平台上,所以同时提高了可移植性,以便在新环境下复现依赖环境。
1.创建虚拟环境,virtualenv虚拟开发环境
pip install virtualenv
pip install virtualenvwrapper-win
2.利用安装好的模块创建一个虚拟环境mkvirtualenv first_env
创建的路径C:\*\Local\pypa\virtualenv
3.虚拟环境其他相关命令:切换到指定的虚拟环境:workon workon first_env
退出虚拟环境deactivate
删除指定的虚拟环境rmvirtaulenv first_env
列出所有虚拟环境:lsvirtualenv
进入到虚拟环境所在的目录:cdvirtualenv
在虚拟环境中安装Flask模块pip install flask
4.打开pycharm选择已经存在的虚拟环境C:\*\Envs\first_env\Scripts\python.exe
或直接新建flask项目,选择Virtualenv,配置python解释器后新建,在teminal终端上安装pip install flask
。
二、项目目录详解:
static文件夹 用于存放各种静态文件 css、js、图片等
templates文件夹 用于存放html模板文件
app.py 为主文件 启动项目需要启动该文件
app.py 文件的名字可以自由命名
初始app.py
The flask object implements a WSGI application and acts as the central object.
from flask import Flask
app = Flask(__name__) # __name__参数:Python会根据所处的模块来赋予__name__变量相应的值,此时值为app
@app.route('/') # 用来匹配url,以装饰器实现,装饰器引用的是上面实例化核心类出来的对象。
def hello_world(): # 路由下面跟的函数是视图函数,如果匹配到了路由就会触发视图函数执行,并且return回具体的数据。
return 'Hello World!'
if __name__ == '__main__':
app.run(debug=True) # app.run()实现了flask程序在开发环境下运行起来,并且默认ip和端口是127.0.0.1:5000 host,port参数可以设定
导入Flask的核心类实例化对象app,然后app作为装饰器使用匹配url分发给下面的视图函数,然后执行该页面会触发app调用run()方法运行起来整个项目。此时为b/s型。
DEBUG模式
app参数设置 debug=True
开发阶段对代码进行修改时使用,flask默认部署后再修改代码,刷新页面不起作用。flask代码中如果出现了异常,浏览器中不会提示具体的错误信息,开启debug模式后会把具体的错误信息发送到浏览器上。flask代码如果被修改了,必须要重启项目修改的代码才会有效,开启debug模式后修改代码后只要ctrl+s项目就会自动重新加载,不需要手动加载整个网站。
对这些配置操作手动解耦,创建settings文件
ENV = 'development'
DEBUG = True
此时app文件改为
from flask import Flask, Response
import settings
app = Flask(__name__)
app.config.from_object(settings) # 配置文件解耦
# app.config.from_pyfile('settings') # 或这个
@app.route('/')
def hello_world():
return 'Hello World!' # 底层将其送入Response进行封装
@app.route('/han/')
def hello_world():
return Response('你好啊')
if __name__ == '__main__':
app.run()
运行python app.py
用http://localhost:5000/或http://127.0.0.1:5000/访问,url是统一资源定位符
默认只能是本机访问,如果需要通过本机ip地址访问,则将host改为‘0.0.0.0’查看本机ip:cmd–ipconfig 查找ipv4地址
针对sever端写东西:
b/s:浏览器/服务器 c/s:客户机/服务器
CS = Client - Server = 客户端- 服务器。
例子: QQ,迅雷,快播,暴风影音,各种网络游戏等等。
BS = Browser - Server = 浏览器 - 服务器。
例子:所有的网站都是BS结构。( 知乎 / 果壳 / 微博 / 等等等等等等 )
区别:
1、开发维护成本
cs开发维护成本高于bs。因为采用cs结构时,对于不同的客户端要开发不同的程序,而且软件安装调试和升级都需要在所有客户机上进行。
bs只需要将服务器上的软件版本升级,然后重新登录就可以了。
2、客户端负载
cs客户端负载大。cs客户端不仅负责和用户的交互,收集用户信息,而且还需要通过网络向服务器发出请求。
bs把事务处理逻辑部分交给了服务器,客户端只是负责显示。
3、安全性
cs安全性高。cs适用于专人使用的系统,可以通过严格的管理派发软件。
bs使用人数多,不固定,安全性低。
4、作用范围
Client/Server是建立在局域网的基础上的。Browser/Server是建立在广域网的基础上的。
三、Werkzeug工具包简介
WSGI:Web服务器网关接口(Python Web Server Gateway Interface,缩写为WSGI)是为Python语言定义的Web服务器和Web应用程序或框架之间的一种简单而通用的接口。Werkzeug是一个WSGI工具包,可以作为一个Web框架的底层库,封装了很多 Web 框架的东西,例如 Request,Response 等 。但它不是一个web服务器,也不是一个web框架。
四、url和路由
一个URL由以下几部分组成,URL建立了与Python视图函数的映射关系:
scheme:代表的是访问的协议,一般为http或者https及ftp等。host:主机名,域名。port:端口号。当你访问一个网站的时候,浏览器默认使用80端口,flask:5000。path:路径 /*。query-string:查询字符串
浏览器地址栏输入的东西url–服务器在app中找路由–执行路由匹配的函数–return–response–到客户端的浏览器
Flask程序中使用路由称之为注册路由,使用的是程序实例提供的app.route()装饰器注册路由,而括号内的字符串就是url,注册路由的过程就是完成了 url和python类或函数映射的过程,这样我们以url访问flask就可以找到对应的程序。所有路由搜索规则都是自上而下匹配
1.默认路由@app.route('/')
@app.route('/student_list/')
2.动态路由传参:想根据学生的id找到具体的学生eg:http://127.0.0.1:5000/student_list/8/
@app.route('/student_list//' ) # 路由绑定,无type:则表示为str
# @app.route('/student_list//') # url必须传int
# 如果app.route中有最后的/而url中没有,则浏览器做了一次重定向
def student_list(student_id):
return '学生{}号的信息'.format(student_id) # 此时显示url的学生id
或
def student_list(student_id):
return '学生{}号的信息'.format(student_id) # 此时显示url的学生id
app.add_url_rule('/student_list//' ,view_func=student_list) # 路由绑定
any:
@app.route('///' )
# 第一个为class或student都可以 http://127.0.0.1:5000/class/3/
def item(url_path, id):
if url_path == 'student':
return '学生{}详情'.format(id)
else:
return '班级{}详情'.format(id)
type:
string: 默认的数据类型,接收没有任何斜杠"/"的字符串
int: 整型
float: 浮点型
path:和string类型相似,但是接受斜杠,如:可以接受参数/aa/bb/cc/多条放在一起
uuid: 只接受uuid格式的字符串
五、查询字符串传参
如果浏览器中输入*/s?wd=python&ad=flask
,key=value是查询字符串,多个key=value用&相连,将查询字符串作为参数去请求flask程序,这便是查询字符串传参。http://127.0.0.1:5000/student_name/?name=%27zz%27&age=19
@app.route('/student_name/')
def school_name_list():
name = request.args.get('name')
age = request.args.get('age')
return "学生的姓名为{},年龄为{}".format(name, age)
六、url_for()的使用
路径反向解析,若在视图函数中想使用一个url给前端返回,或者在这个视图函数中返回一个模板文件都会使用到url。url_for()利用视图函数名字一般不会改变的特性,利用视图函数的名字去动态精准的获取url,便于开发使用。
url_for('视图函数名字') # 输出该视图函数url
eg:此时直接访问http://127.0.0.1:5000/,输出/book_list/,网页返回/book_list/
@app.route('/')
def demo1():
print(url_for("book")) # 引用的是视图函数的名字 字符串格式
return url_for("book")
@app.route('/book_list/')
def book():
return 'flask_book'
url_for处理动态的视图函数
如果想获取动态路由,必须以关键字实参的形式为动态的path部分赋值
@app.route('/test/')
def demo2():
student_url = url_for('student', id=5) # id 就是动态path的id 必须赋值
print(student_url) # 输出/student/5/
return student_url
@app.route('/student//' )
def student(id):
return 'student {}'.format(id)
url_for为url添加查询字符串
想在路径后面拼出来查询字符串,以关键字实参的形式放到url_for()里面作为参数,会自动拼成路径
@app.route('/test/')
def test():
school_url = url_for('school', school_level='high', name='college') # 具体要拼接的查询参数 以关键字实参的形式写在url_for里
print(school_url) # /school/?school_level=high&name=college
return school_url
@app.route('/school/')
def school():
return 'school message'
自定义动态路由过滤器
可以通过继承werkzeug.routing 的BaseConverter类从而自定义一个动态路由过滤器的规则
from werkzeug.routing import BaseConverter
class TelephoneConverter(BaseConverter):
regex = '1[3857]\d{9}' # 第二位为3857中的一个,后面在匹配9个数
app.url_map.converters['tel'] = TelephoneConverter # 添加规则
@app.route('/student//' ) # 匹配tel规则
def student_detail(telenum):
return '学生的手机号码是{}'.format(telenum)
七、endpoint参数
写在注册路由的装饰器中的一个参数,学名叫端点,可以理解为函数的别名。如url_for(‘函数名’),现在可以指定endpoint='click'
参数来进行翻转url。如果不指定endpoint,默认以函数名作为端点名。
@app.route('/')
def demo1():
print(url_for("click")) # 引用的是视图函数的名字 字符串格式
return url_for("click")
@app.route('/book_list/',endpoint='click')
def book():
return 'flask_book'
声明变量
{# 声明变量,全局 #}
{% set username='zz' %}
{{ username }}
{# 声明变量,只可在块内使用,局部 #}
{% with num=100 %}
{{ num }}
{% endwith %}
八、蓝图
蓝图的基本使用,flask中可以利用蓝图对程序目录的划分。具体来说可以管理路由划分。如果有很多个视图函数,就应该抽取出来专门的py文件进行管理
此时app.py只是负责启动程序settings负责配置
/app
from apps import create_app
app = create_app() # 程序启动的入口,在apps包里的init文件中
if __name__ == '__main__':
app.run()
/settings
ENV = 'development'
DEBUG = True
base文件是html文件的模板
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% block title %} 用户中心{% endblock %}</title>
<style>
#head {
height: 50px;
background-color: bisque;
}
#head ul {
list-style: none;
height: 50px;
}
#head ul li {
float: left;
width: 100px;
text-align: center;
font-size: 18px;
height: 50px;
line-height: 50px;
}
#middle {
height: 900px;
background-color: azure;
}
#foot {
height: 50px;
line-height: 50px;
background-color: darkseagreen;
}
</style>
{% block mycss %}{% endblock %}
</head>
<body>
<div id="head">
<ul>
<li><a href="">首页</a></li>
<li><a href="">超市</a></li>
<li><a href="">会员</a></li>
</ul>
</div>
<div id="middle">
{% block middle %}
middle
{% endblock %}
</div>
<div id="foot">foot</div>
{% block myjs %}{% endblock %}
</body>
</html>
注册界面
{% extends 'base.html' %}
{% block title %}
用户注册
{% endblock %}
{% block middle %}
<p style="color: red">{{ msg }}p>
{# 加url_prefix参数的 post action #}
{# <form action="/user/register" method="post"> #}
<form action="{{ url_for('user.register') }}" method="post">
<p><input type="text" name="username" placeholder="用户名">p>
<p><input type="password" name="password" placeholder="密码">p>
<p><input type="password" name="repassword" placeholder="确认密码">p>
<p><input type="number" name="phone" placeholder="手机号码">p>
<p><input type="submit" value="用户注册">p>
form>
{% endblock %}
展示界面
{% extends 'base.html' %}
{% block middle %}
<h1>用户信息h1>
<span>当前用户人数是:{{ users |length }} 人span>
<table border="1" cellspacing="0" width="60%">
{% for user in users %}
<tr>
<td>{{ loop.index }}td>
<td>{{ user.username }}td>
<td>{{ user.password }}td>
<td>{{ user.phone }}td>
<td><a href="javascript:;" onclick="del('{{ user.username }}')">删除a>td>
tr>
{% endfor %}
table>
{% endblock %}
{% block myjs %}
<script>
function del(username){
// console.log(username)
// location 地址栏对象
// 发送一条url
// alert('{{ url_for('user.register') }}');
location.href = '{{ url_for('user.del_user') }}'+'?username='+username
}
script>
{% endblock %}
apps目录下的init文件负责创建所需对象
from flask import Flask
import settings
from apps.user.view import user_bp
# 为app设置配置文件,此时使用蓝图分发路径
def create_app():
app = Flask(__name__,template_folder='../templates',static_folder='../static')
# app是一个核心对象,设置模板文件夹以及静态文件夹,路径为apps的上级目录hello_flask的的子目录
app.config.from_object(settings) # 加载配置
# 注册蓝图对象 需要手动注册蓝图,才会建立上url和视图函数的映射关系
app.register_blueprint(user_bp)
# http://127.0.0.1:5000/user/logout 不可访问
# http://127.0.0.1:5000/logout 可访问
# app.register_blueprint(user_bp,url_prefix='/user') # 给url加前缀/user
# http://127.0.0.1:5000/user/logout 可以访问
# http://127.0.0.1:5000/logout 不可访问
# print(app.url_map)
return app
user目录下的view文件负责编写函数以及路径
from flask import Blueprint, request, render_template, redirect, url_for
from apps.user.model import User
# 创建蓝图
user_bp = Blueprint('user', __name__)
# 列表保存的是用户对象
users = []
# 利用蓝图分发路径
@user_bp.route('/')
def user_center():
return render_template('user/show.html', users=users) # 由于模板文件夹为template
@user_bp.route('/register', methods=['GET', 'POST'])
def register():
if request.method == 'POST':
# 获取post提交的数据
username = request.form.get('username')
password = request.form.get('password')
phone = request.form.get('phone')
repassword = request.form.get('repassword')
if password == repassword:
for user in users:
if user.username == username:
return render_template('user/register.html', msg='用户名已存在')
# 创建user对象
user = User(username, password, phone)
# 添加到用户列表
users.append(user)
# 不加参数的
# return redirect('/')
# 加url_prefix参数的
# return redirect('/user/')
# 均可
return redirect(url_for('user.user_center'))
return render_template('user/register.html')
@user_bp.route('/del')
def del_user():
# 获取传递的username
username = request.args.get('username')
# 根据username找到列表中的user对象
for user in users:
if user.username == username:
# 删除user
users.remove(user)
return redirect(url_for('user.user_center'))
else:
return '删除失败'
@user_bp.route('/logout', methods=['GET', 'POST'])
def logout():
return '用户退出'
model文件负责连接数据库等操作
class User:
def __init__(self, username, password, phone=None):
self.username = username
self.password = password
self.phone = phone
def __str__(self):
return self.username