基础概念
-
什么是框架
- 框架是一个为了解决开放性问题而存在的程序结构
-
MTV框架模式
- M:Models,模型层,与数据库打交道 - ORM
- T:Templates,模板层,前端页面
- V:Views,视图层,处理与用户打交道的内容
-
Flask框架
- Flask是一个基于Python,并且依赖于Jinja2模板引擎和Werkzeug WSGI 服务的一个微型框架(Micro Framework)
-
安装Flask:sudo pip3 install flask
-
Flask示例
from flask import Flask app = Flask(__name__) @app.route('/index') def index(): return 'Hello World' if __name__ == "__main__": app.run(debug=True) # 访问地址:http://127.0.0.1:5000/index -
route:路由,路由是为了匹配用户的请求地址以及对应的视图函数
-
带参数的路由 <参数名>
@app.route('/show/<name>/<age>') def show(name, age): print('name:', name) print('age:', age) return '接收数据成功!' # http://127.0.0.1:5000/show/张三/25 -
指定参数类型的路由
@app.route('/calculate/<int:num1>/<int:num2>') def calculate(num1, num2): # 允许直接当成整数去处理 add = num1 + num2 -
多url的路由匹配:多个访问地址最终匹配到同一个视图处理函数
@app.route('/') @app.route('/index') @app.route('/<int:page>') @app.route('/index/<int:page>') def show_page(page=1): return '当前要看的页数为第%d页' % page
模板(Templates)
-
Flask - 模板(Templates)
- 模板是能够呈现给用户看的html+python的网页结构
- 在模板中,允许包含“变量”以及“标签”表示动态内容
- Flask中的模板是依赖于Jinja2的模板引擎
- 默认情况下,Flask会到项目中找到一个 templates 的文件夹,去搜索要用到的模板
# 创建平级的文件夹:templates,在文件夹下创建temp.html # temp.html <body> <h1>hello world</h1> </body> # run.py from flask import Flask, render_template app = Flask(__name__) @app.route('/temp') def temp(): return render_template("temp.html") if __name__ == "__main__": app.run(debug=True) # http://127.0.0.1:5000/temp -
模板中的语法规范(重点)
- 变量
-
什么是变量:在模板中,变量是一种占位符,告诉模板该位置的值是从哪个数据中读取出来的
-
在视图中对变量的处理,渲染模板时,要指定带到模板上的变量们
return render_template('xxx.html',变量1=值1,变量2=值2,... ...) -
在模板中显示变量的值 语法: {{变量名}}
# run.py @app.route('/01-var') def var(): return render_template("01-var.html", name='张三', age=18) # 01-var.html <body> <h1>姓名:{{ name }}</h1> <h1>年龄:{{ age }}</h1> </body> # http://127.0.0.1:5000/01-var # 姓名:张三 # 年龄:18 # 变量过多时用 locals() 表示 # 变量类型有:字符串、数字、小数、列表、元组、字典、类变量、类方法 list = ["保健", "大保健", "按摩"] return render_template('02-var.html', params=locals()) <h1>爱好:{{ params.list }}</h1> <h1>爱好[0]:{{ params.list[0] }}</h1>
- 过滤器
-
允许在变量输出之前改变变量的值
{{变量|过滤器(参数)}} 过滤器名 说明 1.trim 去掉字符串两端的空格 2.default 如果变量为空,则使用default的参数值做显示 3.truncate 如果字符串超出指定长度的话则截取字符串,后面显示...
- 标签
-
每个标签表示的是服务器端一段独立的功能
{% 标签内容 %} {% 结束标签 %} -
常用标签
# if 标签 {% if 条件 %} # 允许写静态或动态的内容 {% endif %} {% if 条件1 %} {% elif 条件2 %} {% else %} {% endif %} # for 标签 {% for 变量 in 可迭代元素%} # 变量是服务器端内容 {% endfor %} # 内部变量 - loop # loop.index 表示当前循环的次数,从1开始记录 # loop.index0 表示当前循环的次数,从0开始记录 # loop.first 是否为第一次循环,值为True,表示是 # loop.last 是否为最后一次循环,值为True,表示是 <table border="1" width="300"> <tr> <th>姓名</th> <th>年龄</th> <th>性别</th> </tr> {% for user in list %} # list 列表中嵌套字典 <tr {% if loop.first %} class="c1" {% elif loop.last %} class="c2" {% else %} class="c3" {% endif %} > <td>{{ user.name }}</td> <td>{{ user.age }}</td> <td>{{ user.gender }}</td> </tr> {% endfor %} </table>
- 静态文件
- 只要不与服务器做动态交互的文件,一律都是静态文件
- 在项目中创建一个static文件夹,存放所有的静态文件
- 所有的静态文件访问必须通过 /static/ 访问
- 模板的继承
- 如果一个模板中的内容大部分与另一个模板一样的时候,则可以使用继承的方式简化模板的开发
- 在父模板中需要定义在子模板中可以被重写的内容
- 在子模板中需要指定继承自哪个父模板,重写父模板中指定的内容
# 父模板 demo.html
{% block 块名 %}
{% endblock %}
# 子模板
{% extends 'demo.html' %}
{% block 块名 %}
{% endblock %}
请求
-
修改配置
1.构建Flask应用是指定配置信息 app = Flask( __name__, template_folder="指定模板文件夹的名称", static_folder="指定静态文件夹的名称", static_url_path="指定访问静态文件的路由" ) 示例: app = Flask( __name__, template_folder="t", static_folder="s", static_url_path="/s" ) 2.启动程序时指定运行配置 app.run( debug=True, host="0.0.0.0", #局域网内都可以访问我的网站 port=5555 ) -
请求 - request
- HTTP协议(Hyper Text Transfer Protocol)
-
规范了数据是如何打包以及数据是如何传递的
-
两大核心内容
1.请求消息 由浏览器带给服务器端的消息 共有3部分组成: 1.请求起始行 GET / HTTP/1.1 1.请求方式 - GET 2.请求的资源路径 - / 3.协议以及版本 - HTTP/1.1 2.请求消息头 消息头都是以 key:value格式存在 每个消息头都是要传递给服务器的信息 3.请求主体 只有 POST , PUT 请求方式才有请求主体 2.响应消息 由服务器端要带给客户端的内容 1.响应起始行 协议/版本 响应状态码 原因短句 1.协议/版本 : HTTP/1.1 2.响应状态码: 200 OK 301 Moved Permanently (永久性重定向) 302 Found (临时性重定向) 304 Not Modified 400 Bad Request (错误请求) 403 Forbidden (禁止访问) 404 Not Found (请求资源不存在) 405 Method Not Allowed (请求方法不被允许) 500 Internal Server Error(服务器内部错误) 502 (网关错误) 2.响应消息头 描述的是服务器端要响应给客户端的内容 以key:value的形式存在的 3.响应主体 服务器端所响应回来的内容
- 请求对象 - request
-
请求对象中会封装着与请求相关的所有的信息
-
语法: from flask import request
-
在视图函数中可以通过 request 去获取对应的请求信息
-
request 中常用成员
1.scheme :获取请求协议 2.method :获取请求方式 - GET / POST 3.args :获取使用get请求方式所提交的数据 4.form :获取使用post请求方式所提交的数据 5.cookies :获取cookies中的数据 6.files :获取上传的文件们 7.path :获取请求的资源路径(没有参数) 8.full_path :获取请求的资源的完整路径(有参数) 9.url :获取完整的请求地址 10.headers :获取请求消息头的信息def request_views(): print('scheme:', request.scheme) print('method:', request.method) print('headers:', request.headers) print('User-Agent:', request.headers['User-Agent']) print('host:', request.headers['host']) # 判断Referer 在 request.headers 中是否存在 if 'Referer' in request.headers: print('Referer:', request.headers['Referer']) url = request.headers.get('Referer', '/') print('返回到:', url) return '获取请求对象成功'
- 获取请求提交的数据
``` 1.get方式 1.get方式的场合 1.表单中method=get <form method="get"> <input type="text" name="xxx"> </form> 2.通过地址栏访问的全部都是get 1.<a href="/xxx?name=xiaoze&age=30"> 2.window.location.href = "/xxx?name=xxx&age=x" 2.获取请求提交的数据 通过 request.args 获取请求的数据 (允许按照字典的方式操作 request.args) 常用手段: 1.request.args['参数名'] 注意:取值之前先做判断 2.request.args.get('参数名','默认值') 3.request.args.getlist('参数名') 场合:能够实现多选的元素 1.checkbox 2.<select> 2.post方式 1.场合 <form method="post"> 2.获取post的请求数据 通过 request.form 获取post的请求数据 (可以按照字典的方式操作 request.form ) request.form['name'] request.form.get('name') request.form.getlist('name') ``` ``` # run.py @app.route('/login', methods=['POST','GET']) def login(): if request.method == 'GET': return render_template('login.html') else: uname = request.form.get('uname') upwd = request.form.get('upwd') return 'uname:%s,upwd:%s'%(uname,upwd) # login.html <body> <form action="/login" method="post"> <p> 用户名称:<input type="text" name="uname"> </p> <p> 用户密码:<input type="password" name="upwd"> </p> <p> <input type="submit" value="提交"> </p> </form> </body> ``` -
文件上传
- 文件必须放在表单中,表单的提交方式必须为post,表单的enctype属性值必须为multipart/form-data
- 服务器端,获取上传的文件,f = request.files['文件框的name值']
- 将文件保存到指定的目录处,f.save('static/+f.filename'),f.filename:能得到原始文件名
# run.py import datetime, os @app.route('/01-file', methods=['POST','GET']) def upfile(): if request.method == 'GET': return render_template('/01-file.html') else: if request.files: f = request.files['file'] ftime = datetime.datetime.now().strftime('%Y%m%d%H%M%S%f') # 获取文件扩展名 ext = f.filename.split('.')[-1] filename = ftime + '.' + ext # 将文件保存在相对路径的static中,不合理(相对路径) # 通过当前文件的地址找到static的地址(绝对路径) basedir = os.path.dirname(__file__) # 当前文件所在文件夹路径 # 拼接文件路径 upload_path = os.path.join(basedir, 'static', filename) f.save(upload_path) return '数据处理成功' # 01-file.html <body> <form action="/01-file" method="post" enctype="multipart/form-data"> <p> <input type="file" name="file"> </p> <p> <input type="submit" value="提交"> </p> </form> </body>
模型 - Models
-
什么是模型
- 根据数据库中表结构而创建的class
- 数据库中的每一张表对应到编程语言中就是一个class
- 表中的每一个列,对应到编程语言中就是class的一个属性
-
模型的框架 - ORM
- Object Relational Mapping 对应关系映射
- 数据表(Table)到编程类(Class)的映射
- 数据类型的映射:数据库中表的字段以及类型 对应到 编程语言中就是类的属性及其数据类型
- 关系映射:将数据库中表与表之间的关系 对应到 编程语言中类与类的关系上
- 优点:封装了数据库中所有的操作,提升效率,省略庞大的数据访问层,即便不用SQL编码也能够完成数据库的CRUD操作(Create/Retrive/Update/Delete)
-
Flask中的ORM框架
- SQLAlchemy框架
- 安装:pip3 install sqlalchemy
- Flask中需要使用flask-sqlalchemy 支持包:pip3 install flask-sqlalchemy
- Flask中配置数据库
- 语法:app.config['SQLALCHEMY_DATABASE_URI']="mysql+pymysql://数据库用户名称:数据库密码@数据库服务器地址:端口号/数据库名"
from flask import Flask from flask_sqlalchemy import SQLAlchemy app = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] = "mysql+pymysql://root:123456@127.0.0.1:3306/flaskDB" - SQLAlchemy框架
-
定义模型类(重点)
- 模型:根据数据库表结构而创建出来的类(模型类,实体类)
# 语法 class MODELNAME(db.Model): __tablename__ = "TABLENAME" # 不写默认表名为小写的类名 COLUMN_NAME = db.Column(db.TYPE,OPTIONS) 1.db.TYPE:映射到列的类型 db.TYPE的常用列类型如下: 类型名 Python类型 说明 Integer int 整数 Float float 浮点数 Numeric decimal.decimal 定点数 String str 字符串 Text str 字符串 Boolean bool 布尔型 Date datetime.date 日期类型 Time datetime.time 时间类型 DateTime datetime.datetime 日期时间类型 2.OPTIONS:指定列选项 选项名 说明 autoincrement 如果设置为True,表示该列为自增长 注:如果列的类型为int并且是主键的话,默认自增长 primary_key 如果设置为True,表示该列为主键 unique 如果设置为True,表示该列值唯一 index 如果设置为True,表示该列加索引 nullable 如果设置为True,表示该列可为空 default 指定该列的默认值# run.py from flask import Flask from flask_sqlalchemy import SQLAlchemy app = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] = "mysql+pymysql://root:123456@127.0.0.1:3306/flaskDB" db = SQLAlchemy(app) class Users(db.Model): __tablename__ = "users" id = db.Column(db.Integer,primary_key=True) username = db.Column(db.String(80), nullable=False, unique=True, index=True) age = db.Column(db.Integer, nullable=True) email = db.Column(db.String(120), unique=True) # 增加一个字段 isActive, 默认值为True isActive = db.Column(db.Boolean, default=True) # 删除所有的表结构 # db.drop_all() # 将所有的实体类生成对应的数据表 db.create_all() -
数据库的迁移
- 将实体类的改动再映射回数据库
- 依赖于第三方库:flask-script, flask-migrate
from flask import Flask from flask_sqlalchemy import SQLAlchemy from flask_script import Manager from flask_migrate import Migrate, MigrateCommand app = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] = "mysql+pymysql://root:123456@127.0.0.1:3306/flaskDB" # 指定启动模式为调试模式 app.config['DEBUG'] = True # 配置自动提交操作回数据库 # 指定增删改操作完成后自动提交 app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True db = SQLAlchemy(app) # 创建Manager实例并指定要管理哪个app manager = Manager(app) # 创建Migrate对象,并指定要关联的app和db migrate = Migrate(app,db) # 为manager增加数据迁移的子命令 manager.add_command('db',MigrateCommand) # manager接管了,不需要了 # db.create_all() # 增删改表操作 class Users(db.Model):... if __name__ == '__main__': # app.run(debug=True) manager.run() # 启动程序:python3 run.py runserver # 命令行启动程序修改地址和端口号:python3 run.py runserver --host 0.0.0.0 --port 5000 # 设置pycharm右键启动:点击“run”下拉选 -> Edit Configurations... -> Parameters:runserver --host 0.0.0.0 --port 5000 实现数据迁移: 1. python3 xxx.py db init 作用:初始化数据库操作 特点:一个项目,只执行一次即可 2. python3 xxx.py db migrate 作用:将编辑好的实体类生成一个中间文件并保存 特点:只要检测到实体有更改,就会生成中间文件 3. python3 xxx.py db upgrade 作用:将中间文件映射回数据库
基于ORM的CRUD
(未完待续...)