当前位置:   article > 正文

python后端:Flask框架学习笔记_flask后端

flask后端
笔记来自视频教程:2分钟了解flask_哔哩哔哩_bilibili
一、第一个flask程序
  1. from flask import Flask #导入必要的包
  2. app=Flask(__name__) #创建Flask对象
  3. @app.route('/') #前端在根目录下的路由+视图函数p
  4. def p():
  5. return 'he'
  6. app.run() #运行该Flask对象 app

这是我们做flask项目时候的具体流程,我们不用担心看不太懂,只要了解大概的模式就好

我们从浏览器进入http://127.0.0.1:5000/

就可以看到打印出来的he了(后端向前端返回的数据)

  1. from flask import Flask #导入必要的包
  2. app=Flask(__name__) #创建Flask对象
  3. @app.route('/') #前端在根目录下的路由+视图函数p
  4. def p():
  5. return 'he'
  6. @app.route('/user/') #前端在根目录下的user下的路由+视图函数p
  7. def user():
  8. return 'user'
  9. app.run()

在根目录下访问 http://127.0.0.1:5000/user/会打印出

来user

二、run启动参数详解
  1. from flask import Flask #导入必要的包
  2. app=Flask(__name__) #创建Flask对象
  3. @app.route('/') #前端在根目录下的路由+视图函数p
  4. def p():
  5. return 'he'
  6. app.run(debug=True,port=5001,host='0.0.0.0')
  7. #run()启动可以添加参数
  8. #debug是开调试模式,修改python代码自动重新运行,我们只要刷新浏览器
  9. #port指定端号,默认5000
  10. #host主机,默认是127.0.0.1,指定位0.0.0.0代表本机所有ip都可以访问网站
三、模板渲染

我们可以看到。网页上的字体有各种颜色和字型,这就要用到渲染技巧:

如我们在函数返回时return '<b>Flask</b>'那么出来的Flask就会加粗,所有之处HTML的渲染方式,但是我们一般不这么做,我们一般把所有的渲染语句放到templates文件之中

  1. from flask import Flask, render_template # 导入必要的包
  2. app=Flask(__name__) #创建Flask对象
  3. @app.route('/') #前端在根目录下的路由+视图函数
  4. def user():
  5. return render_template('index.html') #使用templates目录下的index.html模板
  6. app.run()
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. </head>
  7. <body>
  8. <h2>index</h2>
  9. </body>
  10. </html>

这样程序更加系统,而static文件中会存放一些静态信息.css,如字体颜色等

四、项目拆分

合理的项目拆分可以让我们更好的把握项目结构,方便编码,如果要做一个大型的项目,项目拆分是必不可少的

首先,我们像这样在项目目录下建立这样几个文件,然后把templates和static放入App文件中

在app.py文件中,我们之前讲过会写这个

对于一个大项目,我们会写很多route和视图函数,这样全部放在app中很繁杂,那么怎么做呢?

我们像这样拆分文件,让App变成一个包,init用于把项目初始化,models是模型和数据库相关操作,views中存放所有的route和视图函数

但是view文件中,我们需要app创建,app.py文件中,我们也需要app的创建,如果导两次包那么就创建了两个app对象,这不就不对了吗?所以我们要引入一个新概念,叫做蓝图blueprint

        1.蓝图用来规划urls(路由route)

        2.我们在views.py中初始化蓝图

                blue = Blueprint('user',__name__)

            然后再init文件中调用蓝图进行路由注册

                 app.register_blueprint(blueprint=blue)     

init.py文件:   

  1. #初始化文件,创建flask应用
  2. from flask import Flask
  3. from .views import * #init里导入了view,那么view就不要再导入init了避免重复导入
  4. def create_app():#用函数进行封装,导包时候只会声明这个函数
  5. app=Flask(__name__)#新建了一个Flask对象
  6. app.register_blueprint(blueprint=blue)#让app和我们再view文件中的blue联系起来
  7. return app

views.py文件:

  1. from flask import Blueprint
  2. from .models import * #目前不用,但是一定会用的
  3. blue=Blueprint('user',__name__)#可以有多个blue,作为模板提供给app注册
  4. blue2=Blueprint('product',__name__)
  5. @blue.route('/')
  6. def index():
  7. return 'hello'
  8. @blue2.route('/goods')
  9. def goods():
  10. return 'goods'

app.py文件:

  1. from App import create_app
  2. app=create_app()
  3. if __name__=='__main__':
  4. app.run(debug=True)

是不是一下子就清晰很多了?

五、路由参数解析
  1. from flask import Flask
  2. app=Flask(__name__)
  3. @app.route('/string/<string:name>') #尖括号里面写类型:变量名
  4. def get_string(name):
  5. return name
  6. # app.run()
  7. # string 接受任何不包含斜杠的文本
  8. # int 接受正整数
  9. # float 接受正浮点数
  10. # path 接受包含斜杠的文本
  11. # uuid 只接受uuid字符串,唯一码,一种生成规则
  12. # any 可以同时指定多个路径,进行限定
  13. @app.route('/any/<any(apple,banana,orange):fruit>')#只能传入三个里面的一个
  14. def get_any(fruit):
  15. return str(fruit)
  16. #请求方法,默认支持GET,HEAD,OPTIONS,如果要支持,需要自己指定
  17. @app.route('/methods',methods=['GET,POST,HEAD,PUT,DELETE'])
  18. def l():
  19. return 1
  20. app.run()
六、Request请求

请求和响应:

request:请求

response:响应

http一次前后端交互:先请求,后响应

服务器在接受到客户端的请求后,会自动创建request对象,他的重要参数如下:

url:完整请求地址

base_url:去掉GET参数的URL

host_url:只有主机和端口号的URL

path:路由中的路径

method:请求方法  GET/POST

remote_addr:请求的客户端地址

args:GET请求参数

form:POST请求参数

files:文件上传

headers:请求头

cookies:请求中的cookie(用于特别标识是具体哪个用户发送的请求)

  1. @blue.route('/request',methods=['GET','POST'])
  2. def get_request():
  3. pass
  4. print(request) #打印出了:<Request 'http://127.0.0.1:5000/request' [GET]> 就是网址+请求方式
  5. print(request.method)#只打印请求方式
  6. #GET请求
  7. print(request.args)#打印请求附带的参数 如'http://127.0.0.1:5000/request/?name=lisi&age=33' ?后面是参数那么就会打印 ImmutableMultiDict([('name','lisi'),('age','33')])这是一个类字典对象,它可以出现重复的key
  8. print(request.args['name'])#单独把name参数打印出来
  9. print(request.args.get('name'))#单独把name参数打印出来的另一种写法
  10. print(request.args.getlist('name'))#单独把name参数打印出来,如果有多个name参数就全部打印
  11. #POST请求
  12. print(request.form)#返回post的参数字典 如'http://127.0.0.11:5000/request',data={'name':'lucy','age':33}
  13. print(request.form.get('name'))#单独把name参数打印出来
  14. #cookie
  15. print(request.cookies)#把附带的cookie参数打印出来
  16. print(request.path)#打印到/reuest/
  17. print(request.url)#打印所有,包括附带参数
  18. print(request.base_url)#去参数
  19. print(request.host_url)#只到根目录
  20. print(request.remote_addr)#127.0.0.1,客户端的ip
  21. print(request.file)#打印文件内容,还是那个类字典,需要有文件上传
  22. print(request.header)#请求头
  23. return 'request ok!'
七、Response:响应

从服务端(前端)向客户端发送的响应

  1. @blue.route('/respose/')
  2. def get_response():
  3. pass
  4. #响应的几种方式
  5. #1.返回字符串(并不常用)
  6. #return 'response ok!'
  7. #2.模板渲染
  8. #return render_template('index.html')使用template文件中的index.html渲染方式
  9. #3.返回json数据(前后端分离)
  10. data={'name':'李四','age':'44'}
  11. #return data 一般返回json数据 可以用字典实现
  12. #或者序列化 jsonify(): 字典->字符串
  13. #return jsonify(data)
  14. #自定义Response对象
  15. html=render_template('index.html')
  16. res=make_response(html,200)#使用自定义的html文件
  17. #return res

八、Redirect:重定向

就是你访问我,我不返回,我把你的请求跳转到别的页面去,使得项目呈现多层的结构

  1. @blue.route('/redirect')
  2. def make_redirect():
  3. pass
  4. #重定向的几种方式
  5. #return redirect('https://www.qq.com') 这样你在返回这个页面的时候会直接跳转到qq页面去
  6. #return redirect('/response/')#如果本地页面,那么不要网址,直接写路由就可以
  7. ret=url_for('user.goods')#这里写蓝图名.视图函数名可以转到对应页面 这就是反向解析,我先通过视图函数找到蓝图,再跳转到对应页面去
  8. #return redirect(ret)
九、会话技术
1.cookie

首先我们明确http协议的特点:

1.先请求,后响应

2.响应后会断开链接

3.一次请求就结束了

用图表示:

如图所示:每个用户是一个浏览器(前端)访问服务器后会生成一个cookie,可以是用户名等等可以唯一标识的字符串,这样在下一次访问服务器时,就会让服务器找到你是哪个用户,返回对应的数据

具体处理流程如下:

  1. from flask import Blueprint, request, make_response, render_template, redirect, url_for
  2. import requests
  3. blue=Blueprint('user',__name__)#可以有多个blue,作为模板提供给app注册
  4. blue2=Blueprint('product',__name__)
  5. @blue.route('/')
  6. def index():
  7. return 'hello'
  8. @blue.route('/home')
  9. def home():
  10. # 4.获取cookie
  11. username=request.cookies.get('user')#这就是字典的意义,通过键找到值
  12. return render_template('home.html',username=username)
  13. @blue.route('/login',methods=['GET','POST'])
  14. def login():
  15. # GET:访问登录页面
  16. if request.method=='GET':
  17. return render_template('login.html')
  18. # POST:实现登录功能(按下提交按钮就是一个POST请求)
  19. elif request.method=='POST':
  20. pass
  21. #1.获取前端提交过来的数据
  22. username=request.form.get('username')
  23. password=request.form.get('password')
  24. #2.模拟登录:用户名密码验证
  25. if username=='lisi'and password=='123':
  26. response=redirect('home')#成功登录,重定向转到home页面
  27. #3.设置cookie,实现如果登录成功识别出是哪个用户
  28. response.set_cookie('user',username)#这个函数和字典一样,需要前key后值,这里把username作为特定识别的cookie
  29. #默认浏览器关闭则cookie失效
  30. #过期时间:max_age 单位秒
  31. # response.set_cookie('user',username,max_age=3600*24*7)持续7天
  32. # response.set_cookie('user',username,expires=datetime。datetime(2024,11.11))规定时间
  33. return response
  34. else:
  35. return '用户名或密码错误!'
  36. #注销
  37. @blue.route('/logout')
  38. def logout():
  39. response=redirect('/home')
  40. response.delete_cookie('user')#把需要删除的cookie写进去
  41. return response

以上是一个登录页面的实现,其中:

home.html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>首页</title>
  6. </head>
  7. <body>
  8. <h2>首页</h2>
  9. <hr>
  10. <a href="/login">登录</a>
  11. </body>
  12. </html>

login.html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>登录</title>
  6. </head>
  7. <body>
  8. <h2>登录</h2>
  9. <hr>
  10. <form action=""method="post">
  11. <!-- 前半段是空的表示默认为login当前界面-->
  12. <!-- <form action="{{url_for('user.login')}}"></form>反向解析也可以-->
  13. <!-- <form action="/login"></form>直接写也可以-->
  14. <p>
  15. 用户名:<input type="text"name="username">
  16. </p>
  17. <p>
  18. 密码:<input type="password"name="password">
  19. </p>
  20. <p>
  21. <button>提交</button>
  22. </p>
  23. </form>
  24. </body>
  25. </html>

实现了用户输入用户名密码,后端判断是否正确并给予cookie,返回特定用户数据

2.session

session是服务器端会话技术,依赖于cookie

特点:

1.服务器端的会话技术

2.所有数据存储在服务器中

3.默认存储在内存中

4.存储结构也是key-value形式,键值对

5.session是离不开cookie的

flask中的session是全局对象(之前的request也是全局对象)

常用操作:

        设置session

                session['key']='value'

        获取session

                session.get(key,default=None)根据键获取会话的值

        删除session

                session.pop(key)删除一个

                session.clear()删除所有

书接上回,我们设置session:

  1. from flask import Blueprint, request, make_response, render_template, redirect, url_for, session
  2. import requests
  3. blue=Blueprint('user',__name__)#可以有多个blue,作为模板提供给app注册
  4. blue2=Blueprint('product',__name__)
  5. @blue.route('/')
  6. def index():
  7. return 'hello'
  8. @blue.route('/home')
  9. def home():
  10. # 4.获取cookie
  11. username=request.cookies.get('user')#这就是字典的意义,通过键找到值
  12. #获取session
  13. username=session.get('user')
  14. return render_template('home.html',username=username)
  15. @blue.route('/login',methods=['GET','POST'])
  16. def login():
  17. # GET:访问登录页面
  18. if request.method=='GET':
  19. return render_template('login.html')
  20. # POST:实现登录功能(按下提交按钮就是一个POST请求)
  21. elif request.method=='POST':
  22. pass
  23. #1.获取前端提交过来的数据
  24. username=request.form.get('username')
  25. password=request.form.get('password')
  26. #2.模拟登录:用户名密码验证
  27. if username=='lisi'and password=='123':
  28. response=redirect('home')#成功登录,重定向转到home页面
  29. #3.设置cookie,实现如果登录成功识别出是哪个用户
  30. response.set_cookie('user',username)#这个函数和字典一样,需要前key后值,这里把username作为特定识别的cookie
  31. #默认浏览器关闭则cookie失效
  32. #过期时间:max_age 单位秒
  33. # response.set_cookie('user',username,max_age=3600*24*7)持续7天
  34. # response.set_cookie('user',username,expires=datetime。datetime(2024,11.11))规定时间
  35. #设置session
  36. session['user']=username
  37. return response
  38. else:
  39. return '用户名或密码错误!'
  40. #注销
  41. @blue.route('/logout')
  42. def logout():
  43. response=redirect('/home')
  44. response.delete_cookie('user')#把需要删除的cookie写进去
  45. session.pop('user')
  46. return response

在设置session时,一定要先在创建app时(在init.py文件)设置一个secret key(唯一)否则会报错,它的作用是通过这个secret key加密我们session的value值

  1. #初始化文件,创建flask应用
  2. from flask import Flask
  3. from .views import *
  4. def create_app():#用函数进行封装,导包时候只会声明这个函数
  5. app=Flask(__name__)#新建了一个Flask对象
  6. print(app.config)
  7. """
  8. <Config {'DEBUG': False, 'SECRET_KEY': None, }这里我们要设置一个secret key
  9. """
  10. app.config['SECRET_KEY']='abc123'#随便写,只要是唯一的
  11. app.register_blueprint(blueprint=blue)#让app和我们再view文件中的blue联系起来
  12. return app

然后我们打开网站在输入用户名密码后点击检查看看我们的session:

发现我们的value已经被加密,并且没有报错

但是session也是有过期时间的,怎么设置它是永久的呢?

只需要在设置session那一步下面加上

  1. #设置session
  2. session['user']=username
  3. session.permanent=True

session和cookie的区别:

cookie:

1.在浏览器存储

2.安全性较低

3.可以减轻服务器压力

session:

1.在服务器端存储

2.安全性较高

3.对服务器要求较高

4.依赖cookie

十、模板Template

模板就是呈现给用户的界面

在MVT中作为T的角色,V和T是多对多的关系

模板处理分为两个部分

1.静态HTML

2.动态插入代码块

flask主用的HTML模板语言为Jinja2

模板语法

模板语法主要分为两种
        变量
        标签


模板中的变量 {{ var }}
        视图传递给模板的数据
        前面定义出来的数据
        变量不存在,默认忽略


模板中的标签 {% tag %}
        控制逻辑
        使用外部表达式
        创建变量
        宏定义

结构标签

block 块操作
        父模板挖坑,子模板填坑
        {% block xxx %}
        {% endblock %}


extends 继承
        {% extends 'xxx' %}

        继承后保留块中的内容
        {{ super() }}


include
        包含,将其他html包含进来
        {% include 'xxx' %}

marco 【了解】
        宏定义,可以在模板中定义函数,在其它地方调用
        {% macro hello(name) %}
                {{ name }}
        {% endmacro %}

宏定义可导入
        {% from 'xxx' import xxx %}

循环

for循环
        {% for item in cols %}
                AA
        {% else %}
                BB
        {% endfor %}


可以使用和Python一样的for...else
也可以获取循环信息 loop
loop.first: 判断是否是第一个元素
loop.last: 判断是否是最后一个元素
loop.index: 1开始的下标
loop.index0: 0开始的下标
loop.revindex: 反向下标,不包括0
loop.revindex0: 反向下标,包括0

过滤器(扩展)

语法
        {{ 变量|过滤器|过滤器... }}
capitalize
lower
upper
title
trim
reverse
striptags 渲染之前,将值中标签去掉


safe
default(1)
last
first
length
sum
sort

具体参照链接:Jinja2模板语言最基础入门_jinja2模板语法-CSDN博客

十一、模型Model

它用于对数据库进行操作

Flask模型

Flask默认并没有提供任何数据库操作的API
我们可以选择任何适合自己项目的数据库来使用
Flask中可以自己的选择用原生语句实现功能,也可以选择ORM(SQLAlchemy,MongoEngine)

原生SQL缺点
代码利用率低,条件复杂代码语句越⻓,有很多相似语句
一些SQL是在业务逻辑中拼出来的,修改需要了解业务逻辑

直接写SQL容易忽视SQL问题

ORM

Flask通过Model操作数据库,不管你数据库的类型是MySql或者Sqlite特,Flask自动帮你生成相应数据库类型的SQL语句,所以不需要关注SQL语句和类型,对数据的操作Flask帮我们自动完成。只要会写Model就可以了。

Flask使用对象关系映射(Object Relational Mapping,简称ORM)框架去操控数据库。

ORM(Object Relational Mapping)对象关系映射,是一种程序技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换。

将对对象的操作转换为原生SQL
优点
易用性,可以有效减少重复SQL
性能损耗少
设计灵活,可以轻松实现复杂查询
移植性好

下面是代码讲解:

我们之前在views里是没有写import model的,但是一旦我们用到了model,就要在views中加上

from .models import *

1.首先我们要先配置数据库:在init.py文件中配置·sqlite数据库

  1. def create_app():#用函数进行封装,导包时候只会声明这个函数
  2. app=Flask(__name__)#新建了一个Flask对象
  3. #注册蓝图
  4. app.register_blueprint(blueprint=blue)#让app和我们再view文件中的blue联系起来
  5. #配置数据库(连接数据库)
  6. db_url='sqlite://sqlite3.db'
  7. app.config['SQLALCHEMY_DATABASE_URI']=db_url
  8. return app
'
运行

现在还不会自动生成数据库

我们还要在App下新建一个包,作为我们之后要用很多插件要用的包取名为exts.py

  1. #exts:插件管理
  2. #扩展的第三方插件
  3. #1.导入第三方插件
  4. from flask_sqlalchemy import SQLAlchemy
  5. from flask_migrate import Migrate
  6. #2.初始化
  7. db=SQLAlchemy()#ORM
  8. migrate=Migrate()#创建数据迁移对象
  9. #3.和app对象绑定

第三步犯了难,app对象在init.py里,怎么绑定?为了不循环引用

app.py->_init_.py->view->model  之后还会再model里导入->exts,所以exts里最好不要导入init从而引入app了,而且每多一个插件,init.py就要修改,因此

  1. #3.和app对象绑定
  2. def init_exts(app):
  3. db.init_app(app)
  4. migrate.init_app(app=app,db=db)#两个参数必须填,用于对应数据库和app
'
运行

使用函数的形式,然后在init中

  1. #初始化文件,创建flask应用
  2. from flask import Flask
  3. from .views import *
  4. from .exts import init_exts
  5. def create_app():#用函数进行封装,导包时候只会声明这个函数
  6. app=Flask(__name__)#新建了一个Flask对象
  7. #注册蓝图
  8. app.register_blueprint(blueprint=blue)#让app和我们再view文件中的blue联系起来
  9. #配置数据库(连接数据库)
  10. db_url='sqlite://sqlite3.db'
  11. app.config['SQLALCHEMY_DATABASE_URI']=db_url
  12. #和插件绑定
  13. init_exts(app=app)
  14. return app

只用改exts就可以啦

如此配置工作完成,下面写model

  1. #model:模型,数据库
  2. from .exts import db #导入db数据库对象
  3. #模型 数据库
  4. #类 表
  5. #类属性 表字段
  6. #一个对象 表的一行
  7. #模型model:一个类
  8. #必须继承db.Model,它才是一个模型,不然就只是一个class
  9. class User(db.Model):
  10. #表名
  11. __tablename__='tb_user'
  12. #定义表字段
  13. id=db.Column(db.Integer,primary_key=True,autoincrement=True)
  14. name=db.Column(db.String(30),unique=True,index=True)
  15. age=db.Column(db.Boolean,default=True)
  16. #autoincrement自动递增
  17. #index普通索引

之后进行数据迁移

数据迁移命令:
在cmd或Terminal先进入项目目录(app.py所在目录):
然后输入命令:
flask db init 创建迁移文件夹migrates, 只调用一次
flask db migrate 生成迁移文件  会自动找到model中自动生成的类(继承了db)
flask db upgrade 执行迁移文件中的升级   把数据库中的表创建了
flask db downgrade 执行迁移文件中的降级  把之前的upgrade撤销 回到上一个版本

如果想改变表结构(改动了model.py)就要重新做迁移  也就是做2 3步命令行操作

1.表的增操作:
  1. #增:添加数据
  2. @blue.route('/useradd')
  3. def user_add():
  4. # #添加一条数据:
  5. # u=User()
  6. # u.name='kun'
  7. # u.age=1
  8. # u.id=0
  9. # db.session.add(u)#将u对象添加到session中
  10. # db.session.commit()#同步到数据库中
  11. #同时添加多条数据:
  12. users=[]
  13. for i in range(10,30):
  14. u=User()
  15. u.name='男的'+str(i)
  16. u.age=i
  17. users.append(u)
  18. try:
  19. db.session.add_all(users)
  20. db.session.commit()#自带事务提交
  21. except Exception as e:
  22. db.session.rollback()#回滚撤销操作
  23. db.session.flush()#清空缓存
  24. return 'fail'+str(e)
  25. return 'success'
2.表的删操作:
  1. #删:减少数据
  2. @blue.route('/userdelete')
  3. def user_delete():
  4. u=User.query.first()#查询第一条数据
  5. db.session.delete(u)
  6. db.session.commit()
  7. return 'sucess'
3.表的改操作:
  1. @blue.route('userupdate')
  2. def user_update():
  3. u = User.query.first() # 查询第一条数据
  4. u.age=1000#拿到直接改
  5. db.session.commit()
  6. return 'sucess'
4.表的查操作:

查操作就比较麻烦了,需要记的东西有很多:

查询数据
        过滤器
                filter() 把过滤器添加到原查询上,返回一个新查询得到一个查询集=where,可以list强转,可以.filter.filter无限循环
                filter_by() 把等值过滤器添加到原查询上,返回一个新查询
                limit() 使用指定的值限制原查询返回的结果数量,返回一个新查询
                offset() 偏移原查询返回的结果,返回一个新查询
                order_by() 根据指定条件对原查询结果进行排序,返回一个新查询
                group_by() 根据指定条件对原查询结果进行分组,返回一个新查询

常用查询
           all() 以列表形式返回查询的所有结果,返回列表
           first() 返回查询的第一个结果,如果没有结果,则返回 None
           first_or_404() 返回查询的第一个结果,如果没有结果,则终止请求,返回 404 错误响应
           get() 返回指定主键对应的行,如果没有对应的行,则返回 None
           get_or_404() 返回指定主键对应的行,如果没找到指定的主键,则终止请求,返回 404 错            误响应
           count() 返回查询结果的数量
           paginate() 返回一个 Paginate 对象,它包含指定范围内的结果

查询属性:

        contains
        startswith
        endswith
        in_
        __gt__
        __ge__
        __lt__
        __le__

逻辑运算

        与 and_
        filter(and_(条件),条件...)
        或 or_
        filter(or_(条件),条件...)
        非 not_
        filter(not_(条件),条件...)

查询:

  1. persons = Person.query.all() # 获取所有
  2. persons = Person.query.filter(Person.age>22)
  3. # filter功能比filter_by强大
  4. persons = Person.query.filter(Person.age==22) # filter(类.属性==值)
  5. persons = Person.query.filter_by(age=22) # filter_by(属性=值)
  6. persons = Person.query.filter(Person.age.__lt__(22)) # <
  7. persons = Person.query.filter(Person.age.__le__(22)) # <=
  8. persons = Person.query.filter(Person.age.__gt__(22)) # >
  9. persons = Person.query.filter(Person.age.__ge__(22)) # >=
  10. persons = Person.query.filter(Person.age.startswith('宝')) # 开头匹配
  11. persons = Person.query.filter(Person.age.endswith('宝')) # 结尾匹配
  12. persons = Person.query.filter(Person.age.contains('宝')) # 包含
  13. persons = Person.query.filter(Person.age.in_([11,12,22])) # in_
  14. persons = Person.query.filter(Person.age>=20, Person.age<30) # and_
  15. persons = Person.query.filter(and_(Person.age>=20, Person.age<30)) # and_
  16. persons = Person.query.filter(or_(Person.age>=30, Person.age<20)) # or_
  17. persons = Person.query.filter(not_(Person.age<30)) # not_

排序:

  1. persons = Person.query.order_by('age') # 升序
  2. persons = Person.query.order_by(desc('age')) # 降序

分页:

  1. perrsons = Person.query.limit(5) # 取前5个
  2. persons = Person.query.offset(5) #跳过前5个
  3. # 获取⻚码page和每⻚数量num
  4. page = int(request.args.get('page'))
  5. per_page = int(request.args.get('per_page'))
  6. # 手动做分⻚
  7. persons = Person.query.offset((page-1) * per_page).limit(per_page)
  8. # 使用paginate做分⻚
  9. persons = Person.query.paginate(page=page, per_page=per_page,
  10. error_out=False).items
  11. paginate对象的属性:
  12. items:返回当前⻚的内容列表
  13. has_next:是否还有下一⻚
  14. has_prev:是否还有上一⻚
  15. next(error_out=False):返回下一⻚的Pagination对象
  16. prev(error_out=False):返回上一⻚的Pagination对象
  17. page:当前⻚的⻚码(从1开始)
  18. pages:总⻚数
  19. per_page:每⻚显示的数量
  20. prev_num:上一⻚⻚码数
  21. next_num:下一⻚⻚码数
  22. total:查询返回的记录总数
5.多表操作:

1.一对多

  1. #model.py文件:
  2. from .exts import db #导入db数据库对象
  3. #多表关系
  4. #一对多
  5. #班级:学生=1:N
  6. #班级表
  7. class Grade(db.Model):
  8. __tablename__='grade'
  9. id=db.Column(db.Integer,primary_key=True,autoincrement=True)
  10. name=db.Column(db.String(30),unique=True)
  11. #建立关联
  12. #第一个参:是关联的表名
  13. #第二个参:是反向引用的名称,grade对象 让student去反过来得到grade对象的名称:student.grade
  14. #为什么这么做?因为我们只给grade的id创建外键,student只能拿到Grade.id,不能拿到name的值,但是反向查找可以找到所有值
  15. #第三个参:懒加载 事先不给你加关联,等到你真正要用这个关联时再关联
  16. students=db.relationship('student',backref='grade',lazy=True)
  17. #这里的students不是字段,就是一个类属性
  18. #学生表
  19. class student(db.Model):
  20. __tablename__='student'
  21. id=db.Column(db.Integer,primary_key=True,autoincrement=True)
  22. name=db.Column(db.String(30),unique=True)
  23. age=db.Column(db.Integer)
  24. #外键 和Grade表中的id关联
  25. gradeid=db.Column(db.Integer,db.ForeignKey(Grade.id))

  1. #view.py文件
  2. import random
  3. from flask import Blueprint
  4. from .models import *
  5. blue=Blueprint('user',__name__)
  6. blue2=Blueprint('product',__name__)
  7. @blue.route('/')
  8. def index():
  9. return 'hello'
  10. @blue.route('/addgrade')
  11. def addgrade():
  12. #先添加班级
  13. grades=[]
  14. for i in range(10):
  15. grade=Grade()
  16. grade.name=f'class{i}'
  17. grades.append(grade)
  18. try:
  19. db.session.add_all(grades)
  20. db.session.commit()
  21. except Exception as e:
  22. print(e)
  23. db.session.rollback()
  24. db.session.flush()
  25. return 'OK'
  26. @blue.route('/addstudent')
  27. def addstu():
  28. #添加学生
  29. students=[]
  30. for i in range(10,20):
  31. stu=student()
  32. stu.name=f'student{i}'
  33. stu.age=i
  34. stu.gradeid=random.randint(0,10)
  35. students.append(stu)
  36. try:
  37. db.session.add_all(students)
  38. db.session.commit()
  39. except Exception as e:
  40. print(e)
  41. db.session.rollback()
  42. db.session.flush()
  43. return 'OK'
  44. @blue.route('/updatestu')
  45. def upgradestu():
  46. stu=student.query.first()
  47. stu.age=100
  48. db.session.commit()
  49. return 'OK'
  50. @blue.route('/deletestu')
  51. def deletestu():
  52. stu=student.query.first()
  53. db.session.delete(stu)
  54. db.session.commit()
  55. return 'ok'
  56. @blue.route('/searchstu')
  57. def serchstu():
  58. stu=student.query.get(2)
  59. print(stu.name)
  60. print(stu.age)
  61. print(stu.grade.name)
  62. return 'OK'

2.多对多

如图所示:用户表和电影表就是多对多的关系

  1. #用户收藏电影,一个用户可以收藏多部电影, 一部电影可以被不同的用户收藏, 是一个多对多关系.
  2. # 中间表(不是类)
  3. collects = db.Table('collects',
  4. # user_id为表字段名称, user.id为外键表的id
  5. db.Column('user_id', db.Integer, db.ForeignKey('user.id'), primary_key=True),
  6. db.Column('movie_id', db.Integer, db.ForeignKey('movie.id'), primary_key=True)
  7. )
  8. class Movie(db.Model):
  9. id = db.Column(db.Integer, primary_key=True, autoincrement=True)
  10. name = db.Column(db.String(200))
  11. class User(db.Model):
  12. id = db.Column(db.Integer, primary_key=True, autoincrement=True)
  13. name = db.Column(db.String(16))
  14. age = db.Column(db.Integer, default=1)
  15. # 多对多 关联的学生表格的模型, 中间表的名称, 反向查找
  16. movies = db.relationship('Movie', backref='users',
  17. secondary=collects, lazy='dynamic')

lazy属性:
懒加载,可以延迟在使用关联属性的时候才建立关联
lazy='dynamic': 会返回一个query对象(查询集),可以继续使用其他查询方法,如all().
lazy='select': 首次访问到属性的时候,就会全部加载该属性的数据. 我已经查完了,不能进行其他操作了
lazy='joined': 在对关联的两个表进行join操作,从而获取到所有相关的对象

  1. #查:
  2. # 查询用户收藏的所有电影
  3. user = User.query.get(id)
  4. movies = user.movies
  5. # 查询电影被哪些用户收藏
  6. movie = Movie.query.get(id)
  7. users = movie.users
  8. #删:
  9. # 中间表的数据会被级联删除
  10. movie = Movie.query.get(id)
  11. db.session.delete(movie)
  12. db.session.commit()
  13. #增:
  14. # 用户收藏电影
  15. user = User.query.get(id)
  16. movie = Movie.query.get(id)
  17. user.movies.append(movie)
  18. db.session.commit()
十二、flask插件 

之前已经有提到过了,像之前的flask-migrate等都是flask插件内容,特征是都带有flask-标志

下面学习几种其他插件

插件的使用非常简单,先安装,然后在exts.py文件中初始化

安装
pip install flask-caching

初始化
from flask_cache import Cache
cache = Cache(config={
'CACHE_TYPE': 'simple',
})
cache.init_app(app=app)

使用
在视图函数上添加缓存
@blue.route('/')
@cache.cached(timeout=30)  
def home():

##什么意思呢? 其实就是,如果我要访问一个数据,每天访问很多次,都是这个数据访问时##间又特别长,那么我们就加上这个cache,使得第一次加载的时候满,之后每一次加载直##接读缓存,节省时间,timeout=30是缓存的有效时间
print('加载数据')
return 'home'

十二、钩子

什么是钩子(中间件Middleware)
钩子或叫钩子函数, 是指在执行函数和目标函数之间挂载的函数, 框架开发者给调用方提供一个point-挂载点, 是一种AOP切面编程思想

他相当于一个拦截,在访问与视图函数之间加了一个函数进行检查,如看看是不是有个爬虫或者一直访问服务器或植入木马病毒等等

常用的钩子函数
before_first_request:

处理第一次请求之前执行(你第一次来访问我,我执行函数,第二次就不了)


before_request:

(用的最多)在每次请求之前执行. 通常使用这个钩子函数预处理一些变量, 实现反爬等.

每一次请求都会执行这个函数


after_request:注册一个函数,如果没有未处理的异常抛出,在每次请求之后运行.

teardown_appcontext: 当APP上下文被移除之后执行的函数,可以进行数据库的提交或者回滚

AOP反爬策略

  1. # 利用缓存反爬,相同ip地址1秒内不允许重复访问
  2. key = request.remote_addr + "before"
  3. value = cache.get(key)
  4. if value:
  5. return '小伙子,别爬了'
  6. else:
  7. cache.set(key, 'aa', timeout=1)
  8. # 反爬,防止非浏览器访问
  9. ua = request.user_agent # 用户代理
  10. if not ua:
  11. return "hello"
  12. # abort(400) # 可以抛出错误给用户
十三、Flask内置对象&配置templates,static

g:
global全局对象
g对象是专⻔用来保存用户的数据的
g对象在一次请求中的所有的代码的地方,都是可以使用的突破变量存储位置限制, 为数据传递添加了新的方式, 比如我们在before_request产生一个数据在后面需要使用,可以保存在g对象中,在其他视图函数中就可以使用这个数据

他和在函数外面定义的对象不一样,他时间只有一次请求的时间,每一个请求都带有一个g对象
request:
请求对象, 可以获取客户端提交过来的所有请求信息
session:
会话技术,服务端会话技术的接口
current_app:
app的配置信息, app对象获取, current_app使用获取当前app需要注意,一定要在程序初始化完成之后

如果想要修改templates模板目录或static静态目录,可以自己配置
在settings.py文件中添加BASE_DIR:

  1. import os
  2. BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
'
运行

在__init__.py文件中添加static路径和templates路径:

  1. static_path = os.path.join(settings.BASE_DIR, 'static')
  2. template_path = os.path.join(settings.BASE_DIR, 'templates')
  3. app = Flask(__name__, static_folder=static_path, template_folder=template_path)

在views.py文件中访问模板:

  1. @blue.route('/hello/')
  2. def hello():
  3. return render_template('hello.html')

在模板中使用静态资源:

<link rel="stylesheet" href="{{ url_for('static', filename='css/hello.css') }}">
十四、前后端分离

前后端不分离:

        render_template('index.html',users=users)

只要使用了这种方法就是前后端不分离,通过本地的模板渲染

前后端分离:

        后端返回json字符串:jsonify()    序列化方法

        前端使用ajax来请求数据:ajax

 HTTP请求方式:

        GET:用来获得数据

        POST:用来提交数据

        PUT:用来修改数据

        DELETE:用来删除数据

十五、RESTful类视图

他的作用主要用在前后端分离的项目中,视图views.py可以完全删除了,我们将用类视图和urls.py来代替他的功能:

用到的插件:flask-restful-0.3.10

项目拆分如下:

在init文件中引入api:

  1. from flask_sqlalchemy import SQLAlchemy
  2. from flask_migrate import Migrate
  3. from flask_restful import Api
  4. from .urls import * #这里不导入的话url文件注册代码不会执行
  5. db=SQLAlchemy()
  6. migrate=Migrate()
  7. api=Api()
  8. def init_exts(app):
  9. db.init_app(app=app)
  10. migrate.init_app(app=app,db=db)
  11. api.init_app(app=app)

在apis.py文件中引入类视图:

  1. from flask_restful import Resource
  2. #类视图:CBV 基于视图的类
  3. #视图函数:FBV 基于视图的函数
  4. class HelloResouce(Resource):
  5. #如果是GET请求自动执行
  6. def get(self):
  7. return 'GET请求'
  8. #如果是POST请求自动执行
  9. def post(self):
  10. return 'POST请求'

在urls.py文件中注册类视图:

  1. #路由文件:专门写路由
  2. from .exts import api
  3. from .apis import *
  4. #路由
  5. api.add_resource(HelloResouce,'/hello')

现在的执行流程就是,类=原来的视图函数

先在apis.py定义类视图,类视图在urls.py中被注册并赋予路由,服务器根据访问类型执行类视图中不同的函数

字段格式化 Flask-RESTful

定义返回给前端的数据格式

具体详细请转向文章:Flask-RESTful的介绍和简单使用-CSDN博客

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/一键难忘520/article/detail/997592
推荐阅读
相关标签
  

闽ICP备14008679号