文章目录
Flask 框架
1.Flask介绍
flask 是一门使用 python 编写的后端框架。
另外一门非常优秀的 Django 框架:
目前是建议是初学者使用 flask 进行开发。
因为 Django 有着一系列复杂的我们并不需要使用的功能。
python环境
如果没有 python 的环境的话,请安装最新的 python 环境即可。
flask安装
pip install Flask
记得把天杀的梯子关了。
开发工具pychram
请到官网下载。(专业版最好
实在要用 vscode 也一样。
2.第一个项目
项目目录
# 从 Flask 这个包中导入 flask 这个类
from flask import Flask
# 使用Flask类创建一个app对象
# __name__ 代表当前的这个模块
# 1.以后出现bug,它可以帮助我们快速定位
# 2.对于寻找模板文件,有一个相对路径
app = Flask(__name__)
# 创建一个路由和视图函数的映射
# 创建的是根路由
# 访问根路由,就会执行hello_world这个函数
@app.route('/')
def hello_world(): # put application's code here
return 'Hello World!'
# 运行代码
if __name__ == '__main__':
app.run()
执行:
pychram 直接点击右上角直接运行;
vscode 可以在终端中输入 flask run
也可以运行。
3.项目配置
debug模式
默认是没有开启的。
如果没有开启 debug 模式的话,你修改完代码后必须将项目停止,然后重启才能够有效果。(我们希望的效果当然是直接保存然后就有效果)
所有一般我们打开 debug 模式。
如何开启:
不仅如此,开启了 debug 模式之后,如果报错了,我们在浏览器上就可以看到报错信息。
此外:也可以在代码中直接修改
if __name__ == '__main__':
app.run(debug=True)
修改host
默认情况下是 localhost:
但是外部是不能访问的。
如果想让在同一个网络下的其他设备可以访问的话,需要修改为0.0.0.0
然后我们就可以使用ip地址进行访问。
如何修改host:
或者也可以使用 --host=你的ipaddress
也行。
效果:
修改端口号
就是修改项目运行的端口号。
还是在刚刚修改host的地址。
4.url与视图
url的组成部分:
协议 + 域名 + 端口号(默认是80 \ 443) + 路由
我们使用 @app.route()
即可定义路由:
@app.route('/')
def hello_world(): # put application's code here
return '你好china'
@app.route('/my')
def my(): # put application's code here
return '这里是李嘉俊'
也可以定义多层。
url携带参数
@app.route('/my/blog/<blog_id>')
def blog_detail(blog_id): # put application's code here
return '您访问的博客是{}'.format(blog_id)
参数携带类型
如果携带类型的话,能够强制转换的话会被强制转换。
可以定义的类型:
默认参数
/book/list
/book/list?page=2
使用 request
from flask import Flask,request
@app.route('/book/list')
def book_detail(): # put application's code here
page = request.args.get('page', default=1, type=int)
return '你获取的是{}'.format(page)
请求类型
post 和 get …
5.模板渲染
模板引擎:Jinja2
虽然 jinja2 是一个单独的库,但是由于 flask 依赖了jinja2,所以不必单独安装。
引入:
from flask import render_template
使用:
@app.route('/template')
def template(): # put application's code here
// 渲染
return render_template('demo.html')
效果:
动态渲染
还是使用 jinja2 的 render_template
:
@app.route('/template/blog/<blog_id>')
def template(blog_id): # put application's code here
return render_template('demo.html', blog_id=blog_id)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Title</title>
</head>
<body>
<a href="www.baidu.com">百度</a>
<div class="header">这里是博客{{ blog_id }}</div>
</body>
</html>
效果:
模板访问对象属性
一样的:
@app.route('/template/blog/<blog_id>')
def template(blog_id): # put application's code here
uesr = User('lijiajun', '[email protected]')
person = {
'username': 'zhangsan',
'email': 'zhangsan的email'
}
return render_template('demo.html', blog_id=blog_id, user=uesr, person=person)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Title</title>
</head>
<body>
<a href="www.baidu.com">百度</a>
<div class="header">这里是博客{{ blog_id }}</div>
<div>{{ user }}</div>
<div>{{ user.username }}</div>
<div>{{ user.email }}</div>
<div>{{ person.username }}</div>
<div>{{ user.email }}</div>
</body>
</html>
结果:
6.jinja2过滤器
使用过滤器
使用管道符号 |
即可。
就是处理从render_template
中传入的一些数据,可以在 template 中使用 jinja2 的过滤器。
比如求传入的长度:
<div>{{ user.email | length }}</div>
有几十个内置的过滤器,查看 jinja2 的文档即可。
自定义过滤器
自定义相关函数,然后增加即可。
# 自定义过滤器
def filter(value):
return value.upper()
# 增加过滤器
app.add_template_filter(filter, 'filter')
<div>{{ user.email | filter }}</div>
效果:
7.jinja2控制语句
if语句
<div>
{% if age > 18 %}可以进入 {% endif %} {% if age < 18 %} 禁止进入{% endif %}
</div>
效果:
for循环
注意没有 break 这样的语句。
<div>
{% for foo in age %}
{% endfor %}
</div>
8.jinja2模板继承
封装组件
就是组件,在这里称为需要复用的模板。
举例:我们新建一个组件:
在别的页面中使用:
{% extends 'component.html' %}
组件传参
demo.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>test</title>
</head>
<body>
<div>
{% extends 'component.html' %} {% block content %} 我是传过来的内容 {%
endblock %} {% block title %} 我是传过来的标题 {% endblock %}
</div>
</body>
</html>
component.html
在其中留空即可。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>这是一个组件</title>
</head>
<body>
这是一个组件 {% block title %}{% endblock %} {% block content %}{% endblock
%}
</body>
</html>
效果:
9.jinja2中加载静态文件
加载图片
<body>
<div>
<img src='{{ url_for("static",filename="image.png") }}' alt="" />
</div>
</body>
结果:
加载css文件
<head>
<meta charset="UTF-8" />
<title>test</title>
<link rel="stylesheet" href='{{ url_for("static",filename="demo.css") }}' />
</head>
效果:
加载js文件
一样的:
<script src='{{ url_for("static",filename="demo.js")}}'></script>
总结
都是使用 {{ url_for('static',filename="demo")}}
就可以了。
10.操作数据库(Mysql)
安装相关包
MySQL-python
:老旧的包,只支持 py2mysqlclient
:对上面这个包的改善,支持了 py3,是目前的驱动包中效率(纯c语言编写)最高的,但安装的时候环境容易出问题pymysql
:纯 py 编写,效率比较低,但是正因为如此,它可以和 python 无缝衔接mysql-connector-python
:纯 py 写的,比上面这个还慢
为了减少出错:可以使用 pymysql
pip install pymysql
我们不会直接使用这个包去操作数据库,因为需要写原生的SQL语句,我们最好使用 orm。
所以我们还需要下一个:
pip install flask-sqlalchemy
sqlalchemy 给我们提供了 orm 的技术,可以让我们像操作普通对象一样去操作数据库。
这个需要额外安装,因为 flask 没有这个依赖。
连接数据库
- 在 app.config 中设置好连接数据库的相关信息
- 然后使用 SQLAlchemy(app)创建一个 db 对象
- SQLAlchemy 会自动读取 app.config 中的连接信息
# 从 Flask 这个包中导入 flask 这个类
from flask import Flask, request, render_template
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import text
app = Flask(__name__)
# 配置文件
HOSTNAME = '127.0.0.1'
PORT = 3306
USERNAME = 'root'
PASSWORD = 'admin123'
DATABASE = 'my_db_01'
print('mysql+pymysql://{}:{}@{}:{}/{}?charset=utf8mb4'.format(USERNAME, PASSWORD,
HOSTNAME, PORT,
DATABASE))
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://{}:{}@{}:{}/{}?charset=utf8mb4'.format(USERNAME, PASSWORD,
HOSTNAME, PORT,
DATABASE)
db = SQLAlchemy(app)
with app.app_context():
with db.engine.connect() as conn:
rs = conn.execute(text("select 1"))
print(rs.fetchone())
结果:
orm模型与表的映射
orm(object relationship mapping) : 对象关系映射,是一种可以利用 python 面向对象的方式来操作关系型数据库的技术。
优点:
- 开发效率高,不需要写 SQL 语句
- 安全性强:对常见的 SQL 问题进行了处理,比如 SQL 注入等等
- 灵活性强:flask-sqlalchemy的orm支持一系列关系型数据库,只需要在连接的时候正确配置即可
写法:
# User orm
class User(db.Model):
# 映射表名
__tablename__ = 'user'
# 配置数据库元素
# id,username,password 的各自的属性(主键,类型,是否可以为空,自增等等)
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
username = db.Column(db.String(100), nullable=False)
password = db.Column(db.String(100), nullable=False)
# 下面的语句实际上就是映射为 insert 语句
user = User(username='法外狂徒张三',password='111111')
# 将你创建的表推到数据库
with app.app_context():
db.create_all()
如果数据库中已经有相关的表的话,也就是说我们不需要在代码中新建表,我们直接读取数据库中的表:
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
my_table = db.Table('my_table',
db.Column('id', db.Integer, primary_key=True),
db.Column('name', db.String(50)),
db.Column('age', db.Integer))
orm与crud操作
create
@app.route('/user/add')
def addUser():
user = User(username='法外狂徒张三', password='111111')
db.session.add(user)
db.session.commit()
return '新建用户成功'
read
@app.route('/user/read')
def readUser():
# get 查找:根据主键查找
user = User.query.get(1)
return '查找用户成功{}{}'.format(user.id, user.username)
@app.route('/user/read')
def readUser():
# 1.get 查找:根据主键查找
# user = User.query.get(1)
# 2.使用 filter_by 查找
users = User.query.filter_by(username='法外狂徒张三')
print('this is users', users[0].username)
return '查找用户成功'
update
@app.route('/user/update')
def updateUser():
user = User.query.filter_by(username='法外狂徒张三').first()
user.username = '法外狂徒李嘉俊'
db.session.commit()
return '修改用户成功'
delete
@app.route('/user/delete')
def deleteUser():
# 查找
user = User.query.filter_by(username='法外狂徒李嘉俊').first()
# 从 db.session 中删除
db.session.delete(user)
# 提交删除
db.session.commit()
return '删除用户成功'
orm外键与表关系
了解一下就行。
关于外键:
- 在实际生产中基本不用
- 因为本质上是一种耦合的体现
- 数据表之间的查询效率不高
- 如果有分布式的情况存在就更无法使用外键
- 代替
- 使用另外一张表代替,就像多对多一样
- 使用外键但不建立外键的约束
orm映射到数据库
我们之前使用这样的方式来将模型映射到数据库:
# 将你创建的表推到数据库
with app.app_context():
db.create_all()
但是如果模型中的字段改变了,就会出现问题。
比如:
原来我们的模型:
# user 模型
class User(db.Model):
# 映射表名 -> 就是数据库中表名
__tablename = 'user'
# 配置数据库元素
# id,username,password 的各自的属性(主键,类型,是否可以为空,自增等等)
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
username = db.Column(db.String(100), nullable=False)
password = db.Column(db.String(100), nullable=False)
我们这时候添加一个 email
:
# user 模型
class User(db.Model):
# 映射表名 -> 就是数据库中表名
__tablename = 'user'
# 配置数据库元素
# id,username,password 的各自的属性(主键,类型,是否可以为空,自增等等)
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
username = db.Column(db.String(100), nullable=False)
password = db.Column(db.String(100), nullable=False)
email = db.Column(db.String(50), nullable=False)
但是数据库中并不会增加 email 字段。
甚至你如果想修改原来的字段的一些信息:
都是会无法修改的。
所以实际开发中我们并不会使用 db.create_all()
。
这时候我们需要一个第三方的包,叫做 flask-migrate
pip install flask-migrate
引入:
from flask_migrate import Migrate
初始化:
migrate = Migrate(app,db)
映射:
-
flask db init 只需要执行一次
-
flask db migrate 识别 orm 模型的改变,生成迁移脚本
注意原来这个 version 中的没有文件
当我们修改过模型之后,可以执行代码,然后:
-
flask db upgrade 运行迁移脚本,同步到数据库中
可以看出,数据库中的字段已经发生了改变,同时生成了一张用于记录 version 的表:
(存储的当前最新的 version)
千万注意,使用这三步走,会重置整个数据库,比如你原来数据库中有除了本项目代码以外的数据模型,会被删除。千万注意!
但是我感觉这种方法也不是很方便,不知道会不会有更简单的方法。
11.蓝图blueprint
学习自https://zhuanlan.zhihu.com/p/357444025
蓝图结构
我们在写项目的时候,肯定是不能够将所有的接口都写在同一个页面中的。
如果接口很少的话,我们甚至只需要使用一个页面,就是 app.py 就可以解决后台的开发,但是实际上的开发往往会比较复杂,这时候我们就需要将代码模块化。
这时候我们就需要使用蓝图。
蓝图技术可以帮助我们实现 flask 应用的模块划分。
blue-print/
├── admin
│ ├── __init__.py
│ └── views.py
├── app.py
└── user
├── __init__.py
└── views.py
接下来请看各个部分的代码:
app.py
from falsk import Flask
app = Flask(__name__)
// 引入
from admin import admin_blue
from user import user_blue
@app.route('/')
def hello():
return 'hello'
app.register_blurprint(admin_blue)
app.register_blurprint(user_blue)
if(__name__ == '__main__'):
app.run(port=5001)
user init 模块
from flask import Blueprint
# 用户部分接口的统一头
user_blue = Blueprint('user',__name__,url.prefix='/user')
from . import views
user views 模块
from user import user_blue
# 用户部分的接口
@user_blue.route('/register')
def register():
return 'register'
@user_blue.route('/login')
def login():
return 'login'
@user_blue.route('/modify_password')
def modify_password():
return 'modify_password'
admin init 模块
from flask import Blueprint
# 用户部分接口的统一头
admin_blue = Blueprint('admin',__name__,url.prefix='/admin')
from . import views
admin views 模块
from admin import admin_blue
# 用户部分的接口
@admin_blue.route('/alluser')
def register():
return 'alluser'
@admin_blue.route('/deluser')
def login():
return 'deluser'
如上,这样的划分的话,就会好很多。
关于代码组织形式
蓝图在组织代码的时候,一共有两种组织形式
- 功能性架构
- 分区式架构
我们上面所展示的就是功能性架构,很明显,我们就是按照功能模块来组织的蓝图,他们共用着相同的静态资源,一起放在 static 中
一个功能性架构的目录示意图:
__init__.py
static/
templates/
home/
control_panel/
admin/
views/
__init__.py
home.py
control_panel.py
admin.py
models.py
关于分区式架构:
适用于子模块有特殊需要的情况下,在创建蓝图对象时,可以指定 static 和 templates ,结构大致如下:
yourapp/
__init__.py
admin/
__init__.py
views.py
static/
templates/
home/
__init__.py
views.py
static/
templates/
control_panel/
__init__.py
views.py
static/
templates/
models.py