1.工程搭建:

(1) 安装flask: pip3 install flask

python flask设置端口 和应用名称 flask 修改端口_html

python flask设置端口 和应用名称 flask 修改端口_flask_02

python flask设置端口 和应用名称 flask 修改端口_flask_03

(2)命令行:

(1)终端运行:flask run 

(2)绑定IP地址和端口:Flask run -h 127.0.0.1 -p 8083 修改端口号



  • (3)启动项目: pyhthon app.py
  •   (4)  设置真实项目:FLASK_APP = "RealProject"
  • (5)生产环境:set FLASK_ENV=production
  • (6)开发模式:set FLASK_ENV=development 

注意:虽然 flask 命令可以方便地启动一个本地开发服务器,但是每次应用代码 修改之后都需要手动重启服务器。这样不是很方便, Flask 可以做得更好。如果你打开 调试模式,那么服务器会在修改应用代码之后自动重启,并且当应用出错时还会提供一个 有用的调试器。在命令行中,如果需要打开所有开发功能(包括调试模式),那么要在运行服务器之前导出 FLASK_ENV 环境变量并把其设置为 development:

2. flask框架的路由:

terminal中输入显示所有的路由:flask routes

(1)  路由定义

from flask import Flask

app = Flask(__name__)

"""
路由设置的注解路径: /index
"""
@app.route('/index',methods=['POST','GET'])
def hello_world():

    return 'Hello World!'

"""
路由的路径不能相同,每个函数对应不同的路由;不同的功能;
"""
@app.route('/return')
def return_content():
    return '你好!'
"""
启动本地服务:
"""
if __name__ == '__main__':
    '设置ip 和端口号'
    app.run(debug=True,host='127.0.0.1',port=8083)

python flask设置端口 和应用名称 flask 修改端口_flask_04

 

python flask设置端口 和应用名称 flask 修改端口_学习_05

(2)路由中传递参数:

除了默认字符串变量部分之外,还可以使用以下转换器构建规则:

转换器

描述

string

(缺省值) 接受任何不包含斜杠的文本

int

接受正整数

float

接受正浮点数

path

类似 string ,但可以包含斜杠

uuid

接受 UUID 字符串

#在路由中传递参数
@app.route('/get_name/<name>',methods=['POST','GET'])
def get_params(name):
    return '你好!' + name

python flask设置端口 和应用名称 flask 修改端口_html_06

(3)request 对象的使用:

1)HTTP请求方法:

GET

以未加密的形式将数据发送到服务器,最常见的方法。

HEAD

和GET方法相同,但没有响应体。

POST

用于将HTML表单数据发送到服务器,POST方法接收的数据不由服务器缓存。

PUT

用上传的内容替换目标资源的所有当前表示。

DELETE

删除由URL给出的目标资源的所有当前表示。

2)参数格式:

data(请求的数据,类型为string)、

form(表单的数据)、

args(记录请求中的查询参数?号后面的参数)

headers

method(get\post)

cookies

url

files:文件类型;上传图片)

(4)响应对象:response:

1)返回模板:render_template() :返回一个模板文件

python flask设置端口 和应用名称 flask 修改端口_flask_07

2)重定向redirect:  跳转到其他的路由

python flask设置端口 和应用名称 flask 修改端口_数据_08

3)返回json数据: ( json.load() :读json 文件)

 json.dumps() :写json文件;

 jsonify() :返回为json,同时设置响应头;

4)Cookie使用: 存储在客户端,显示用户的访问记录

一般使用response对象.set_cookie() 来设置cookie

python flask设置端口 和应用名称 flask 修改端口_学习_09

 得到cookie: request.Cookies.get("XXX") 得到cookie

python flask设置端口 和应用名称 flask 修改端口_flask_10

5)Session使用:保存前端提交的状态的数据;存放在浏览器服务器上;

1)设置session:

python flask设置端口 和应用名称 flask 修改端口_数据_11

2.得到session:session.get() :

python flask设置端口 和应用名称 flask 修改端口_flask_12

3删除session:

①删除单条session值,可以采用session.pop('name')方法;
②清空整个session内容,则采用session.clear()方法;

6)abort函数的使用:异常处理函数;

  • 使用类似于python中的raise函数,可以在需要退出请求的地方抛出错误,并结束该请求;
  • 我们可以使用app.erroehandler装饰器来进行异常的捕获与自定义:
from flask import Flask,render_template,request,abort

app = Flask(__name__)

@app.route("/",methods=['GET','POST'])
def index():
    if request.method == 'GET':
        return render_template('index.html')
    elif request.method == 'POST':
        name = request.form.get('name')
        password = request.form.get('password')
        if name == 'zhangsan' and password == '123456':
            return 'login sucess'
        else:
            # abort的用法类似于python中的raise,在网页中主动抛出错误
            abort(404)
            return None



# 自定义错误处理方法,将404这个error与Python函数绑定
# 当需要抛出404error时,将会访问下面的代码
@app.errorhandler(404)
def handle_404_error(err):
    # return "发生了错误,错误情况是:%s"%err
    # 自定义一个界面
    return render_template('404.html')

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

7)url_for实现反转:

url_for是实现url反转的工具,即视图函数→url;
静态文件引入:url_for('static', filename='文件路径')

(5)请求钩子:

中间件(中间件对所有的view都起作用:):是一个类,然后定义pre-process、after-process方法;

请求处理的过程:pro-process----view -----after-process------>(return response)

请求钩子的类别:

  1. before_request:在每一次请求之前调用;
  2. before_first_request:与before_request的区别是,只在第一次请求之前调用;只调用一次
  3. after_request每一次请求之后都会调用;
  4. teardown_request每一次请求之后都会调用;

请求钩子执行顺序:

before-first-request-----before-request----after-request-------teardown-request(接近结尾处理)

3. flask框架的视图:

(1) add_url_rule的初登场

欲实现url与视图函数的绑定,除了使用路由装饰器@app.route,我们还可以通过add_url_rule(rule,endpoint=None,view_func=None)方法

rule:设置的url

endpoint:给url设置的名称

view_func:指定视图函数的名称

(2) 视图函数和类视图:

类视图的引入

之前我们所定义的视图都是通过函数来实现的,所以称之为视图函数,但其实视图还可以由类来实现,即类视图

标准类视图:

定义时需要继承flask的views.View这一基类;
每个类视图内必须包含一个dispatch_request方法,每当类视图接收到请求时都会执行该方法,返回值的设定和视图函数相同;
区别:

视图函数可以通过@app.route和app.add_url_rule来进行注册(映射到url),但类视图只能通过app.add_url_rule来注册,注册时view_func不能直接使用类名,需要调用基类中的as_view方法来为自己取一个“视图函数名”

from flask import Flask,render_template,views

app = Flask(__name__)

# 定义父视图类继承基类View
class Ads(views.View):
    def __init__(self):
        super(Ads, self).__init__()
        # 实例属性
        self.context={
            'ads':'这是对联广告!'
        }

# 定义子视图类继承父类并实现工程
class Index(Ads):
    def dispatch_request(self):
        # 字典传参方式==不定长的关键字传参
        return render_template('class_mould/index.html',**self.context)
class Login(Ads):
    def dispatch_request(self):
        # 字典传参方式==不定长的关键字传参
        return render_template('class_mould/login.html',**self.context)
class Register(Ads):
    def dispatch_request(self):
        # 字典传参方式==不定长的关键字传参
        return render_template('class_mould/register.html',**self.context)

# 注册我们创建的类视图,as_view给类视图起名
app.add_url_rule(rule='/',endpoint='index',view_func=Index.as_view('index'))
app.add_url_rule(rule='/login/',endpoint='login',view_func=Login.as_view('login'))
app.add_url_rule(rule='/register/',endpoint='register',view_func=Register.as_view('register'))

if __name__=='__main__':
    print(app.view_functions)
    app.run(debug=True)

(3) 蓝图的使用:
一个蓝图就是一个模块;视为一种容器对象;有自己的模板文件、静态文件等;

蓝图使用方式:创建蓝图和注册蓝图。

python flask设置端口 和应用名称 flask 修改端口_学习_13

 蓝图内部的静态文件: static_folder:静态文件夹

python flask设置端口 和应用名称 flask 修改端口_html_14

 4. jinja2模板引擎:

(1) 模板的使用:

  • 后端传数据:Flask通过render_template来实现模板的渲染,要使用这个方法,我们需要导入from flask import rander_template,模板中注释需放在{# #}中
  • 模板的第一个参数为指定的模板文件名称,如自定义的html文件,第二个或者更多参数为可选项,用于向模板中传递变量。
  • 如果有多个变量需要传递,我们可以不需要一个一个进行传参,直接使用**locals()替代我们在当前视图函数中定义的所有变量:
from flask import Flask,render_template

app = Flask(__name__)

# 给前端模板传参
@app.route("/")
def index():
    data = {
        'name':'张三',
        'age':18,
        'mylist':[1,2,3,4,5,6,7]
    }
    # 以键值对的形式传参给模板index2.html
    # 左边是形参:data);
    # 右边是我们给这个变量传的值(实参:字典data);
    return render_template('index2.html',data=data)

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

前端接受数据:

前端html模板内需要在双括号{{ }}中使用该变量:
如果想给该变量添加属性便于CSS修改格式,我们可以在变量后添加括号,并在括号内定义class、id等属性

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
hello world
<br>
<!-- 对传入变量的使用并显示:在双括号内,和python中用法类似 -->
{{ data }}
<br>
{{ data['name'] }}
<br>
{{ data.name }}
<br>
mylist:{{ data.mylist }}
<br>
mylist[1]:{{ data.mylist[1] }}
<br>
count:{{ data.mylist[1]+data.mylist[2] }}
</body>
</html>

(2)模板中的控制语句:

  • jinja2模板引擎中也可使用if和for控制语句,但是语句需要放置在{% %}中;
  • if条件判断语句必须包含结束标签{% endif %},其他部分与python中类似,可以与比较运算符> >= < <= == !=结合使用,或与逻辑运算符and,or,not,()结合使用;
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
{% if name==1 %}
	<h1>恭喜你抽中了一等奖!</h1>
{% if name==2 %}
	<h1>恭喜你抽中了二等奖!</h1>
{% else %}
	<h1>恭喜你抽中了三等奖!</h1>
{% endif %}
</body>
</html>
  • for循环控制语句在模板内的用法也和python中类似,遍历的对象可以是字典、元组、列表等,但需要注意的是在模板中无法使用continue和break来对循环进行控制;
{% for 目标 in 对象 %}
	<p>目标</p>
{% endfor %}

(3)过滤器的使用与自定义:

  • 可以在前端模板内{{ 内容 | 过滤器 }}的" | "后使用;
  • 可以使用add_template_filter(函数方法名,'过滤器名')来自定义过滤器;
# 自定义过滤器
def list_step(li):
    # 返回列表,步长为2
    return li[::2]

# 注册模板过滤器(filter)
# 参数1为该过滤器调用的函数,参数2为在前端中调用该过滤器使用的名称
app.add_template_filter(list_step,'li2')
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!-- 过滤器的使用 -->
<!-- 全大写 -->
{{ 'hello_world' | upper }}
<br>
<!-- 单词首字母大写 -->
{{ 'hello world' | title }}
<br>
<!-- 替换左边的内容为右边的内容 -->
{{ 'hello_world' | replace('hello','hi') }}
<br>
<!-- 调用自定义的过滤器 -->
mylist列表:{{ data.mylist | li2 }}
</body>
</html>

(4) include的使用:

  • include用于在一个模板的指定位置导入另一个模板的内容,区别于宏的调用,include更像从另一个模板“复制+粘贴”;
  • include同样在{% %}中使用,采用语句{% include 模块名 %},相当于复制。

(5) 加载静态文件

静态文件一般是我们在开发过程中用到的图片文件、css文件和js文件,在Flask工程中通常包含一个static文件目录,当需要调用静态文件是将会默认在该目录下进行查询,固不需要使用相对路径;
通常我们会在static文件目录下定义名为css、image和js的文件夹分别存储这些静态文件;
加载静态文件通常配合url_for函数使用(需要在双括号内调用),将模板标签的src、herf属性通过url_for(静态文件名称)设置为反转url要比使用相对路径更好

<head>
	<!-- 导入js文件 -->
	<script type="text/javascript" src="{{url_for('static',filename='js/jquery-3.5.1/jquery-3.5.1.js')}}"></script>
	<!-- 导入css文件 -->
	<link rel="stylesheet" href="{{url_for('static',filename='css/car.css')}}">
</head>
<body>
	<!-- 导入图片 -->
	<img alt="" src="{{ url_for('static',filename='image/car.jpg') }}"/>
</body>

(6)extends继承模板

  • 在include中,我们对于当前模板需要插入的代码块,可以在其他模板中定义,然后用include导入进来,外部模块是当前模块的补充,引入新的子模块
  • 而在extends中,我们当前的模板则是待装载的代码块,需要我们继承一个框架来搭载这些代码块,这时候就需要extend来导入框架(基类)模块了;在继承父类的模板基础上,然后生成自己的模板。
  • 通常使用{% block xxx %} xxxx {% endblock %}来充当占位符。

5. flask数据交互:

(1) 使用flask传统的处理表单:

1)传统的前端通用表单,需要前后端共同完成操作,前端需要使用form标签来定义表单,而后端则需要使用request.form来获取post请求中的表单数据:

# 判断请求方式
if request.method == 'POST':
	# 获取表单中name为username的文本域提交的数据
	name = request.form.get('username')
	# 获取表单中name为password的文本域提交的数据
	password = request.form.get('password')
	return name+" "+password

2)使用第三方组件:flask-wtf 和wtforms 来实现后端独立完成的表单操作;

  • wtforms安装:pip install wtforms
  • flask-wtf安装:pip install Flask-WTFpip install flask-wtf

wtforms依照功能类别来说wtforms分别由以下几个类别:

  1. Forms: 主要用于表单验证、字段定义、HTML生成,并把各种验证流程聚集在一起进行验证。
  2. Fields: 包含各种类型的字段,主要负责渲染(生成HTML文本域)和数据转换。
  3. Validator:主要用于验证用户输入的数据的合法性。比如Length验证器可以用于验证输入数据的长度。
  4. Widgets:html插件,允许使用者在字段中通过该字典自定义html小部件。
  5. Meta:用于使用者自定义wtforms功能(配置),例如csrf功能开启。
  6. Extensions:丰富的扩展库,可以与其他框架结合使用,例如django。

(2) flash 闪现的使用:

  • 导入:from flask import flash
  • 后端的使用:flash("message"),message为消息内容;
  • 前端通过遍历get_flashed_messages()获取flash消息内容;

(3) Flask实现文件上传(后面补充)

  • 对于单文件的上传,主要用到flask_wtf.file库下的上传字段类:FileField,以及检验组件:FileRequired和 FileAllowed

6. flask访问数据库:

(1) Flask-SQLAlchemy数据库:

安装 :

pip3 install Flask-SQLAlchemy

SQLAlchemy是一个基于Python实现的ORM (Object Relational Mapping,对象关系映射)框架。该框架建立在DB API (数据库应用程序接口系统) 之上,使用关系对象映射进行数据库操作。简言之便是将类和对象转换成SQL,然后使用数据API (接口) 执行SQL 并获取执行结果。
它的核心思想于在于将关系数据库表中的记录映射成为对象,以对象的形式展现,程序员可以把对数据库的操作转化为对对象的操作。

1)Flask-SQLALchemy的ORM框架便可以实现将操作数据库转变为操作对象,一个book表被抽象成了一个Book类,一个表中的id、tiltle、publishing_office、isbn、storage_time字段被抽象成一个类的五个属性,而该表的一条数据记录就抽象成该类的一个实例化对象,不用再写烦琐的底层SQL语句了。

(2) 初始化数据库配置:

USERNAME = 'root' #设置登录账号
PASSWORD = '123456' #设置登录密码
HOST = '127.0.0.1' #设置主机地址
PORT = '3306' #设置端口号
DATABASE ='flaskdb' #设置访问的数据库

# 创建URI(统一资源标志符)
'''
SQLALCHEMY_DATABASE_URI的固定格式为:
'{数据库管理系统名}://{登录名}:{密码}@{IP地址}:{端口号}/{数据库名}?charset={编码格式}'
'''
DB_URI = 'mysql://{}:{}@{}:{}/{}?charset=utf8'.format(USERNAME,PASSWORD,HOST,PORT,DATABASE)

# 设置数据库的连接URI
SQLALCHEMY_DATABASE_URI = DB_URI
# 设置动态追踪修改,如未设置只会提示警告
SQLALCHEMY_TRACK_MODIFICATIONS = False
# 设置查询时会显示原始SQL语句
SQLALCHEMY_ECHO = True
  • 上述配置文件设置完后,在flask程序文件下导入该文件,再用app.config.from_object方法导入到flask对象内即可;

(3) 表模型的定义与数据库映射

SQLAlchemy允许我们依据数据库的表结构来构建数据模型,即用python类的方式定义一个表模型,再通过调用create_all()方法,就可以将我们定义的所有表模型全部映射为数据库下的表;
但要注意的是每次运行create_all()这行代码时都会将所有表创建一次,导致重复创建表的问题,可以在前面添加一行drop_all()代码来删除已经创建的表;
创建表名:在用类的方式定义表模型时,使用__tablename__='<表名>'来将字符串对象设为表名,

创建列名:使用<列名>=db.Column()来将Column类的实例对象设为表的字段;我们为字段(列)指定的数据类型和约束条件,作为Column实例化时的参数;

SQLAlchemy创建表了,并可以尝试着进行插入记录的操作SQLAlchemy.session.add()

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
import flask学习.config
from datetime import * # datatime库下的datatime类重名了

app = Flask(__name__)
app.config.from_object(flask学习.config)

# 初始化一个SQLAlchemy对象(该步要在导入config后执行)
# 实例化的同时将与数据库相关的配置读入
db = SQLAlchemy(app)
# 初始化app对象中与数据库相关的配置的设置,防止数据库信息泄露
db.init_app(app)

# 创建表模型类对象
class Book(db.Model):
    __tablename__='book'
    id = db.Column(db.Integer, primary_key = True,autoincrement = True)	#定义id字段
    title = db.Column(db.String(50),nullable = False)	#定义title字段
    publishing_office = db.Column(db.String(100),nullable = False)	#定义出版社字段
    isbn = db.Column(db.String(100),nullable = False) #定义isbn号字段
    storage_time = db.Column(db.DateTime, default = datetime.now) # 入库时间字段

if __name__ == '__main__':
    # 删除数据库下的所有上述定义的表,防止重复创建
    db.drop_all()
    # 将上述定义的所有表对象映射为数据库下的表单(创建表)
    db.create_all()

    # 向表中插入记录:实例化-插入-提交
    book1 = Book(id='001',title='人工智能导论',publishing_office ='高等教育出版社',isbn='9787040479843')
    db.session.add(book1)
    db.session.commit()

(4)数据的增、删、改、查操作

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
import flask学习.config
from datetime import * # datatime库下的datatime类重名了

app = Flask(__name__)
app.config.from_object(flask学习.config)

# 初始化一个SQLAlchemy对象(该步要在导入config后执行)
# 实例化的同时将与数据库相关的配置读入
db = SQLAlchemy(app)
# 初始化app对象中与数据库相关的配置的设置,防止数据库连接泄露
db.init_app(app)

# 创建表模型类对象
class Book(db.Model):
    __tablename__='book'
    id = db.Column(db.Integer, primary_key = True,autoincrement = True)	# 定义id字段
    title = db.Column(db.String(50),nullable = False)	                # 定义title字段
    publishing_office = db.Column(db.String(100),nullable = False)	    # 定义出版社字段
    price = db.Column(db.String(30), nullable=False)                    # 定义price号字段
    isbn = db.Column(db.String(50),nullable = False)                    # 定义isbn号字段
    storage_time = db.Column(db.DateTime, default = datetime.now)       # 入库时间字段

# 删除数据库下的所有上述定义的表,防止重复创建
db.drop_all()
# 将上述定义的所有表对象映射为数据库下的表单(创建表)
db.create_all()

# 添加数据的路由
@app.route('/add')
def add_record():
    book1 = Book(title='Python基础教程(第3版)', publishing_office ='人民邮电出版社', price = '68.30 ', isbn = '9787115474889')
    book2= Book(title='Python游戏编程快速上手第4版',publishing_office = '人民邮电出版社', price = '54.50', isbn = '9787115466419')
    book3 = Book(title='JSP+Servlet+Tomcat应用开发从零开始学',publishing_office = '清华大学出版社', price = '68.30', isbn = '9787302384496')

    db.session.add(book1)
    db.session.add(book2)
    db.session.add(book3)
    # 需要提交事务给数据库
    db.session.commit()
    return 'add success!'

# 查找数据的路由
@app.route('/query')
def query_record():
    # 查找id=1的第一个对象
    result = Book.query.filter(Book.id == '1').first()
    print(result.title)
    # 查找publishing_office=人民邮电出版社的全体对象
    result_list = Book.query.filter(Book.publishing_office == '人民邮电出版社').all()
    for books in result_list:
        print(books.title)
    return 'query success!'

# 修改数据的路由
@app.route('/edit')
def edit_record():
    # 查找id=1的第一个对象
    book1 = Book.query.filter(Book.id == '1').first()
    book1.price = 168
    # 需要提交事务给数据库
    db.session.commit()
    return 'edit success!'

# 删除数据的路由
@app.route('/delete')
def delete_record():
    # 查找id=9的第一个对象
    book2 = Book.query.filter(Book.id == '9').first()
    db.session.delete(book2)
    # 需要提交事务给数据库
    db.session.commit()
    return 'delete success!'

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

1)数据的添加

  • 确保数据库已经建立好后,直接使用db.session.add(<实例化对象>)的方法就可以把依据某一个表类实例化的数据对象插入到对应表中;
  • 这一步操作需要进行事务提交db.session.commit()

2)数据的查找

数据的查找需要通过query.filter(<限制条件>)方法来实现,query继承自db.Model,query.filter返回的是查找到的所有满足限制条件的数据对象组成的列表,当没有限制条件时则返回表中所有记录对应的数据对象组成的列表;
可以使用first()来获取查找到的第一个数据对象,也可以用all()来获取查找到的全部数据对象(一个列表);

3)数据的修改

  • 数据的修改操作是基于数据的查找操作实现的,先通过查找记录获取到对应的数据对象,再对该对象的某一个字段进行修改即可;
  • 这一步操作需要进行事务提交db.session.commit()

4)数据删除:

  • 数据的删除和数据的修改一样,也是基于数据的查找实现的,先通过查找记录获取到对应的数据对象,再调用db.session.delete(<数据对象>)方法即可删除该数据对象与表中的记录;
  • 这一步操作需要进行事务提交db.session.commit()

(5)表模型的关联关系构建

数据库实体型(表)间有3种关联关系:一对一一对多多对多

在SQLAlchemy中,为了在表模型间创建上述的三种关联关系,

同样要在一个表模型中通过db.ForeignKey('表模型类.属性')的方式添加外键,绑定另一个表模型的主属性(primary_key);添加外键后,

还需要使用<字段名1> = db.relationship('<多方表名>',backref=db.backref('<字段名2>')[,secondary=<Table对象名>,uselist=False])的方法来正式构建关系。
 

(6) init_app作用:初始化数据库,但必须要提前传入flask对象。

只要在实例化SQLAlchemy对象的过程中,如果参数app不为空(判断是否传入了flask对象,参数app默认值为None),那么就会调用init_app方法来初始化flask对象中数据库部分的相关配置。这时如果我们提前为flask对象导入了配置文件,init_app就无法覆写我们自定义的配置内容,也就相当于“没有起作用”。