flask

flask

Flask 是一个用 Python 编写的轻量级 Web 应用框架,被誉为“微框架”。它由 Armin Ronacher 开发,核心设计理念是简洁、灵活、易扩展。Flask 只提供构建 Web 应用最核心的工具(路由、请求、响应、模板渲染),而数据库、表单验证等功能则通过丰富的扩展库按需集成。这使得它特别适合快速开发小型应用、RESTful API 以及微服务。凭借极低的入门门槛和高度的自定义能力,Flask 已成为 Python 初学者和追求灵活性的开发者的首选 Web 框架之一。

环境

python环境 保证python在3.6以上

flask安装

1
pip3 install flask

基础配置

项目文件结构

  • FlaskDemo (项目文件名)
    • statc(静态文件存储)
    • template(html代码存储)
    • app.py(主程序代码)

基础代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 从flask这个包中导入Flask类
from flask import Flask

# 使用Flask类创建一个app对象
# __name__: 代表app.py这个模块
# 作用1:以后出现bug可以帮助进行快速定位
# 作用2:对于寻找模板文件,有一个相对路径
app = Flask(__name__)

# 创建一个路由和视图函数的映射
@app.route('/')
def hello_world():
return 'hello world'

if __name__ == '__main__':
app.run()

项目配置

1
2
3
4
5
6
7
8
9
#开启debug模式
if __name__ == '__main__':
app.run(debug=True)

#修改host
使得同局域网主机可以访问

#修改端口
当默认端口被占用的时候可以更改

URL与视图(参数传递)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 访问 /second/123 返回 the netcode is 123
# int:netcode 强制netcode为整型
@app.route('/second/<int:netcode>')
def secondcode(netcode):
return 'the netcode is %s' % netcode

# 查询字符串方式传参
@app.route('/book/list')
def book_list():
# arguments:参数
# requset.args:类字典类型
page = request.args.get('page',default=1,type=int)
return f"你获取的是第{page}页的数据"

# http://127.0.0.1:5000/book/list?page=3 返回 你获取的是第3页的数据
# 没有输入page默认返回1

后续有get post请求

模板渲染(jinja2)

1
2
3
4
5
后端
@app.route("/blog/<blog_id>")
def blog_detail(blog_id):
# 返回渲染的blog_detail文件同时将路径中传入的参数blog_id从后端传入前端
return render_template("blog_detail.html",blog_id =blog_id,userName="mk")
1
2
3
4
5
前端
<!-- 通过双花括号引用后端传入的数据 -->
<title>This is my blog</title>
<h1>your blog_id is {{blog_id}}</h1>
<h1>your userName is {{userName}}</h1>

模板访问对象属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
后端
# 通过创建一个类来实例一个对象传参
class User:
def __init__(self,username,email):
self.username = username
self.email = email


@app.route('/')
def hello_world():
# 创建一个user对象
user = User(username="mk310",email = "xxxx@qq.com")
# 返回渲染后的index超文本文件,和创建好的user
return render_template("index.html",user = user)
1
<h1>用户名是{{user.username}},邮箱是{{user.email}}</h1>
1
2
3
4
5
6
同时还可以使用字典来传参
person = {
"username":"mk",
"email":"xxx@qq.com"
}
<div>{{person['username']}}</div>

过滤器的使用

1
2
3
 <!-- 通过管道符号 | 来实现  -->
<h1>用户名{{user.username}}的长度是{{user.username|length}}</h1>
返回用户名mk310的长度是5

常用过滤器【Flask框架】——12 Jinja2模板-过滤器_jinja2 自定义过滤器-CSDN博客

控制语句

1
2
3
4
5
6
7
8
9
10
if语句
{% if age >10 %}
<div>宁的年龄已满18</div>
{% else %}
<div>宁的年龄不满18</div>
{% endif %}

for语句
{% for book in books %}
{% endfor %}

jinja2中没有break语句,循环必须有限

模板继承

子模板从父模板中继承绝大数样式,同时可以通过block语句自定义需要的样式

文件:

  • template
    • father.html
    • child1.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
father.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<!-- 在父模板中定义主要的样式同时留出自定义的空间block title为可定义的名称 -->
<title>{% block title %} {% endblock %}</title>
<h1>父亲模板的文字</h1>
</head>
<body>

</body>
</html>
1
2
3
4
5
6
7
8
9
child1.html

<!--从父模板中继承主要的样式-->
{% extends "father.html" %}

<!--在子模版中自定义标题-->
{% block title %}
子模板的title
{% endblock %}

jinja2中加载静态文件

flask中静态文件默认放在static文件夹中

1
2
同时可以对样式表和js使用同种方式
<img src="{{url_for('static',filename='2.jpg')}}" >

数据库连接

1
2
3
4
5
6
#首先给pip换成豆瓣源
pip config set global.index-url https://pypi.douban.com/simple/

#设置后若返回 https://pypi.douban.com/simple/ 则设置成功
pip config get global.index-url

复习一下数据库

1
2
3
4
5
安装pymysql
pip install pymysql

安装Flask-SQLAlchemy
pip install flask-sqlalchemy

连接数据库:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import text

app = Flask(__name__)

# MySQl所在的主机名
HOSTNAME = "127.0.0.1"
#MySQl监听的端口号
PORT = "3306"
#连接MySQl的用户名是用户自己设置的
USERNAME = "root"
#连接数据库的密码
PASSWORD = "1111"
# 数据库中创建的数据库名称
DATABASE = "database_learn"

app.config['SQLALCHEMY_DATABASE_URI'] = f"mysql+pymysql://{USERNAME}:{PASSWORD}@{HOSTNAME}:{PORT}/{DATABASE}?charset=utf8mb4"

# 在app.config中设置好连接数据库的信息
# 使用SQlAlchemy(app)创建一个对象
# SQlAlchemy会自动读取信息
db = SQLAlchemy(app)

# 测试连接代码 无实际意义
# 获取引擎连接
with app.app_context():
with db.engine.connect() as conn:
# 执行语句
rs = conn.execute(text("select 1"))
# 查看返回值,若为1连接成功
print(rs.fetchone())

ORM模型

对象关系映射(Object Relationship Mapping)python面向对象的方式来操作关系型数据库的技术,一个ORM模型和数据库中的一个表相对应,ORM模型中的每个类属性分别对应表的每个字段.ORM模型的每个实例对象对应表中的每个记录,ORM技术提供了面向对象和SQL交互的桥梁.

优势:

  1. 开发效率高,几乎不用写原生sql语句
  2. 安全性高
  3. 灵活性强,跟换数据库只需小改少量代码

创建表和基本字段

1
2
3
4
5
6
7
8
9
10
11
12
13
# 继承属性
class User(db.Model):
__tabalename__ = "user"
# 定义字段,整型,主键,自增
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)

# user = User(username="张三",password="1111")
# 把表同步到数据库中去
with app.app_context():
db.create_all()

CRUD(Create Read Update Delete)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
Create添加数据
# 在打开网页后数据库中才会添加数据
@app.route("/user/add")
def add_user():
user = User(username="张三",password="1111")
db.session.add(user)
db.session.commit()
# 防止报错 没有可用的response对象 添加返回
return "添加用户成功"

Read查询
@app.route("/user/query")
def query_user():
# 1.get查找 根据主键查找
user = User.query.get(1)
print(f"{user.id}:{user.username}-{user.password}")
# 2.filter_by查找
# users是Query类型 是类数组
users = User.query.filter_by(username="张三")
for user in users:
print(user.username)
# 另外看一下其他查找操作
return("查找成功")
Update该
@app.route("/user/update")
def update_user():
user = User.query.filter_by(username="张三").first()
user.password = "2222"
db.session.commit()
return "数据修改成功"

Delete删除
@app.route("/user/delete")
def delete_user():
user = User.query.get(2)
db.session.delete(user)
db.session.commit()

return "数据删除成功"

表关系

关系型数据库一个强大的功能,就是多个表之间可以建立关系。

通过给Article添加外键,建立和User之间的关系

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Article(db.Model):
__tabalename__ = "user"
# 定义字段,整型,主键,自增
id = db.Column(db.Integer,primary_key=True,autoincrement=True)
title = db.Column(db.String(200),nullable=False)
content = db.Column(db.Text,nullable=False)

# 添加外键 数据类型和被引用表中的数据类型保持一致
author_id = db.Column(db.Integer,db.ForeignKey("user.id"))
# relationship相当于 返回article.author = User.query.get("article.author_id")
author = db.relationship("User")


artical = Article(title="Flask_study",content="flaskxxxxxxxxxx")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class User(db.Model):
__tabalename__ = "user"
# 定义字段,整型,主键,自增
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)
articles = db.relationship("Article",back_populates = "author")

class Article(db.Model):
__tabalename__ = "user"
# 定义字段,整型,主键,自增
id = db.Column(db.Integer,primary_key=True,autoincrement=True)
title = db.Column(db.String(200),nullable=False)
content = db.Column(db.Text,nullable=False)

# 添加外键 数据类型和被引用表中的数据类型保持一致
author_id = db.Column(db.Integer,db.ForeignKey("user.id"))
# relationship相当于 返回article.author = User.query.get("article.author_id")
# back_populates指数据从User表中的author传入
author = db.relationship("User",back_populates = "articles")

此时可以通过这种方法查找到一个人的所有文章
@app.route("/article/query")
def article_query():
user = User.query.get(4)
for article in user.articles:
print(article.title)

数据库的更新

create_all不能识别模型中的变化,只能识别新增模型,弃用

使用migrate更新数据库,首先pip安装之后引入

1
2
3
4
5
6
7
migrate = Migrate(app,db)

# ORM模型映射三步骤
# 1.flask db init:这步只要做一次
# 2.flask db migrate:识别ORM模型变化,生成迁移脚本
# 3.flask db upgrade:将变化同步到数据库中