(L159951)Flask2001

课程内容

1. 开发环境
1.1 系统介绍

​ [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UvmLbV43-1590763077268)(C:\Users\ADMINI~1\AppData\Local\Temp\1587992841459.png)]

windows, macOS,linux是当今主流三大操作系统,普通用户一般是选择windows或macOS, linux主要是占据服务器领域市场。
操作系统给人的感觉是:
	(1)windows经济适用,档次较低;2)macOS高端大气上档次;3)Linux是极客专用,一个黑乎乎的窗口,各种花花绿绿的指令在闪烁,对着键盘噼里啪啦一通乱敲,就能窃取各种机密。
    在程序员群体中,操作系统有以下的鄙视链:macOS-->linux-->windows。 不过作为一个程序员,你很有必要学会linux,如果你的程序最终是跑在线上的Linux服务器上,那么你就更应该从现在开始投入linux的怀抱中,早日从windows脱坑。至于macOS,在命令行上与linux绝大部分相同,都是类unix的操作系统。简单地说,macOS是一个比windows界面更加美观,同时又兼备linux强大命令行的操作系统. 要说macOS的缺点,那就是贵...

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V8xCNgTq-1590763077272)(C:\Users\ADMINI~1\AppData\Local\Temp\1587992857153.png)]

windows与linux的设计理念有根本性的区别:

windows:用户不知道自己想要什么,也不明白自己在做什么,更不打算为自己的行为负责。

       因为windows将所有操作都隐藏起来,只给用户提供封装好的功能,用户只能在操作系统限制的范围内操作,如果是普通用户,会觉得很windows很舒服,因为不需要思考。只需要按照指示去操作。但对于开发人员而言,这种设计理念是无法接受的,一旦要做出一些超越封装好的功能之外的事情,就会出现各种难以意料的情况,而且很多情况下,这些问题是无解的。或者只能用极其蹩脚扭曲的方式去勉强处理,然后瑟瑟发抖地期待着程序能正常运行。因为一旦程序崩溃,你也会为之崩溃。在windows下作开发,那种体验就好比在陪伴一个任性的女朋友,虽然长得清秀靓丽,但喜怒无常,她开心时,彼此相安无事,她不开心时,就直接哭闹,你问她:怎么了?她也不说原因,只是一直哭。你只能试着用各种方式去哄她开心,即使这次能哄好她,并不意味着下次同样的方法能奏效。这样的相处方式,很累。不是她不好,而是彼此不适合。即使终日相伴,却依然对其一无所知。
linux:用户知道自己想要什么,也明白自己在做什么,并且会为自己的行为负责。

        linux将所有操作权都交给了用户,她相信用户是理性的聪明的,忠实地执行用户的指令,向用户暴露所有的细节。用户在拥有自主权的同时也拥有了破坏力,因此普通用户根本无法驾驭,可能一个指令就把操作系统弄崩溃了。对于开发者而言,linux的开放与自由给了我们无限的可能性,我们能看到程序是如何运行的,运行报错也会有友好的提示。根据报错指引往往能将问题解决。与之相处,好比与一个成熟的女性相处,历经风雨,已经不再关注浮夸的外表,而是关注内在的涵养。刚接触时,可能会觉得她高冷,慢慢地,会发现她很善解人意,心情不好时她会跟你说是什么原因造成的,彼此商量如何解决这个问题,而不是无来由地崩溃。与之相处,会感到很舒服,彼此坦诚,无需套路,你在想什么,我都知道。我在念什么,你也明白。

总结:我选择linux的原因在于自由、舒服,简言之:爽!

1.2 环境安装
  1. centos7安装python3(https://www.cnblogs.com/felixwang2/p/9934460.html)
  2. centos7安装虚拟环境(https://www.centos.bz/2018/05/centos-7-4-安装python3及虚拟环境/)
  3. centos7安装mysql (https://blog.csdn.net/WYA1993/article/details/88890883)
  4. centos7安装redis (https://www.cnblogs.com/zuidongfeng/p/8032505.html)
  5. pycharm连接云服务器(https://blog.csdn.net/lin_danny/article/details/82185023)
2. BS/CS
2.1 概念:
CS = Client - Server = 客戶端 - 服务器。
例子: QQ,迅雷,快播,暴風影音,各种网络游戏等等。

BS = Browser - Server = 浏览器 - 服务器。 
例子:所有的网站都是BS结构。( 知乎 / 果壳 / 微博 / 等等等等等等 )
2.2 区别:
1、开发维护成本
	cs开发维护成本高于bs。因为采用cs结构时,对于不同的客户端要开发不同的程序,而且软件安装调试和升级都需要在所有客户机上进行。
	bs只需要将服务器上的软件版本升级,然后从新登录就可以了。
2、客户端负载
	cs客户端负载大。cs客户端不仅负责和用户的交互,收集用户信息,而且还需要通过网络向服务器发出请求。
	bs把事务处理逻辑部分交给了服务器,客户端只是负责显示。
3、安全性
	cs安全性高。cs适用于专人使用的系统,可以通过严格的管理派发软件。
	bs使用人数多,不固定,安全性低。
4、作用范围
	Client/Server是建立在局域网的基础上的。Browser/Server是建立在广域网的基础上的。
3. MVC/MTV

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cBo6XoPy-1590763077273)(C:\Users\ADMINI~1\AppData\Local\Temp\1587992872930.png)]

3.1 MVC概念
MVC开始是存在于桌面程序中的,M是指业务模型 model,V是指用户界面 view,C则是控制器 controler,使用MVC的目的是将M和V的实现代码分离,从而使同一个程序可以使用不同的表现形式。比如一批统计数据可以分别用柱状图、饼图来表示。C存在的目的则是确保M和V的同步,一旦M改变,V应该同步更新
3.2 分层介绍
  • Model(模型) -----封装数据的交互操作 CRUD
  • View(视图) -----是用来将数据呈现给用户的 页面
  • Controller(控制器) ------用来协调Model和View的关系,并对数据进行操作,筛选
3.3 MTV

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WkoUxV5x-1590763077275)(C:\Users\lijingAction\Desktop\NZ-2001\day01\doc\media\MTV.png)]

MTV
	也叫做MVT,本质上就是MVC的变种
	
	Model(模型)     -----同MVC中Model
	Template(模板)  -----同MVC中View
	Views(视图函数)-----同MVC中Controller
4. Flask框架
4.1 介绍
Flask是一个轻量级的可定制框架,使用Python语言编写,较其他同类型框架更为灵活、轻便、安全且容易上手。它可以很好地结合MVC模式进行开发,开发人员分工合作,小型团队在短时间内就可以完成功能丰富的中小型网站或Web服务的实现。另外,Flask还有很强的定制性,用户可以根据自己的需求来添加相应的功能,在保持核心功能简单的同时实现功能的丰富与扩展,其强大的插件库可以让用户实现个性化的网站定制,开发出功能强大的网站。
Python最出名的框架要数Django,此外还有Flask、Tornado等框架。虽然Flask不是最出名的框架,但是Flask应该算是最灵活的框架之一,这也是Flask受到广大开发者喜爱的原因。
4.1.1 django和flask对比
重量级框架 django
	为了方便业务程序的开发,提供了丰富的工具及其组件
轻量级框架 flask
	只提供web核心功能,自由灵活,高度定制,Flask也被称为 “microframework” ,因为它使用简单的核心,用 extension 增加其他功能
4.2 官方文档
http://flask.pocoo.org/docs/0.12/      英文
http://docs.jinkan.org/docs/flask/     中文
4.3 flask流行的主要原因
 1 有非常齐全的官方文档,上手非常方便
 2 有非常好的扩展机制和第三方扩展环境,工作中常见的软件都会有对应的扩展,动手实现扩展
 也很容易
 3 社区活跃度非常高    flask的热度已经超过django好几百了
 4 微型框架的形式给了开发者更大的选择空间
5.Flask基本使用
5.1 虚拟环境的创建
1.创建flask的虚拟环境
	mkvirtualenv --python=/usr/bin/python3 flask200x  
2.查看虚拟环境
	pip freeze
	pip list
3.虚拟环境迁移
	pip freeze > requirements.txt
		迁出
	pip install -r requirements.txt
		迁入
5.2 Flask项目的创建
1.安装
	国外源  pip install flask
	国内源  pip install flask -i https://pypi.douban.com/simple
2.创建项目
	代码结构
		from flask import Flask
         app = Flask(__name__)

        @app.route("/")
        def index():
            return "Hello"
        app.run()
3.启动服务器  python  文件名字.py
	默认端口号  5000  只允许本机连接
5.3 启动服务器参数修改
run方法中添加参数
	在启动的时候可以添加参数  在run()中
	debug
		是否开启调试模式,开启后修改过python代码自动重启
		如果修改的是html/js/css 那么不会自动重启
	host
		主机,默认是127.0.0.1 指定为0.0.0.0代表本机ip
	port
		指定服务器端口号
	threaded
		是否开启多线程
6. flask-script-(命令行参数)
	1.安装
		pip install flask-script
		作用
			启动命令行参数
	2.初始化
		修改  文件.py为manager.py
		manager = Manager(app=app)
		修改 文件.run()为manager.run()
	3.运行
		python manager.py runserver -p xxx -h xxxx -d -r
          参数
          - p  端口 port
          - h  主机  host
          - d  调试模式  debug
          - r  重启(重新加载) reload(restart)
7. 视图函数返回值
1)index返回字符串
		@app.route('/index/')
         def index():
            return 'index'2)模板first.html
		@app.route('/first/')
         def hello():
            return render_template("test.html")
      静态文件css
           注意
           <link rel="stylesheet" href="/static/css/hello.css">
6. Flask基础结构
App
	templates
		模板
	static
		静态资源
	views
    	视图函数
	models
    	模型
	坑点
		执行过程中manager.py和其他的文件的路径问题
	第二个坑--封装__init__文件--
7. flask-blueprint-(蓝图)
蓝图
	1. 宏伟蓝图(宏观规划)
	2. 蓝图也是一种规划,主要用来规划urls(路由)
	3. 蓝图基本使用
  	- 安装
     - pip install flask-blueprint
     - 在视图文件中  初始化蓝图   blue = Blueprint('first',__name__)      
       注意导包 from flask import Blueprint
     - 在manager中   调用蓝图进行路由注册  app.register_blueprint(blueprint=blue)
#ext

1 如果上传文件夹的时候 该文件夹中没有文件  那么就不允许上传

2 蓝图  就是帮助我们来规划路由  就是帮助我们找路径
  使用步骤:(1)pip install flask-blueprint
           (2)在视图函数中 创建蓝图对象
               blue = Blueprint('蓝图的名字',__name__)
            (3)在manager中注册蓝图
               app.register_blueprint(blueprint=blue)
            (4)将app.route修改为blue.route()

3 App是个python的文件夹  里面有static  templates  views  init文件
  与App同级的有一个manager的文件

  结论:(1)App和manager是通过init建立关联的
       (2)路由是写在views里的  路径的问题是通过蓝图来解决
8. Flask路由参数
8.1 概念
路由中带参数的请求,从客户端或者浏览器发过来的请求带参数。
基本使用:
 @blue.route('/getstudents/<id>/')
          def getstudents(id):
              return '学生%s'+id
8.2 基础语法
基础语法
	<converter:var_name>
	书写的converter可以省略,默认类型就是string
converter
	(1)string
         接收的时候也是str, 匹配到 / 的时候是匹配结束
         @blue.route('/getperson/<string:name>/')
         def getperson(name):
              print(name)
              print(type(name))
              return name
	(2)path
          接收的时候也是str/ 只会当作字符串中的一个字符处理
          @blue.route('/getperson1/<path:name>/')
          def getperson1(name):
              print(name)
              print(type(name))
              return name
	(3int
           @blue.route('/makemoney/<int:money>/')
           def makemoney(money):
              print(type(money))
              return '1'4float
           @blue.route('/makemoneyfloat/<float:money>/')
           def makemoney(money):
              print(type(money))
              return '1'5)uuid(uuid 类型,一种格式)
         @blue.route(('/getuu/'))
         def getuu():
              uu = uuid.uuid4()
              print(uu)
              return str(uu)
          ------------------------------------
         @blue.route('/getuuid/<uuid:uuid>/')
         def getuuid(uuid):
              print(uuid)
              print(type(uuid))
              return '2'6any(已提供选项的任意一个 而不能写参数外的内容  注意的是/)
		 @blue.route('/getany/<any(a,b):p>/')
          def getany(p):
              return '1'
9.postman
请求方式
	postman
		模拟请求工具
			方法参数中添加methods=['GET','POST']
	1. 默认支持GET,HEAD,OPTIONS
	2. 如果想支持某一请求方式,需要自己手动指定
	3. 在route方法中,使用methods=["GET","POST","PUT","DELETE"]
10.反向解析
1)概念:
		获取请求资源路径
(2)语法格式:
		url_for(蓝图的名字.方法名字)3)使用:
         @blue.route("/hehe/", methods=["GET","POST","PUT"])
          def hehe():
              return "呵呵哒"

          @blue.route("/gethehe/")
          def get_hehe():
              p = url_for("first.hehe")
          return p

11.request
1)request是一个内置对象
	内置对象:不需要创建就可以直接使用的对象
(2)属性
	1.method      (请求方法)            **
	2.base_url    (主机+端口号+资源路径)	
	3.host_url    (只有主机和端口号的url)	
	4.url         (主机+端口号+资源路径+参数)       **
	5.remote_addr (请求的客户端地址)     **
	6.request.args.get('name')
      args  **
           - args
           - get请求参数的包装,args是一个ImmutableMultiDict对象,类字典结构对象
           - 数据存储也是key-value
           - 外层是大列表,列表中的元素是元组,元组中左边是key,右边是value
           - ImmutableMultiDict([('age', '18'), ('age', '19'), ('name', 'zs')])
           
           注意: 一般情况下  get请求方式都是在浏览器的地址栏上显示
                 eg:http://www.baiduc.com/s?name=zs&age=18
                 获取get请求方式的参数的方式:request.args.get('name')
          
     7.request.form.get('name')
       form   **
           - form
           - 存储结构和args一致
           - 默认是接收post参数
           - 还可以接收 PUT,PATCH参数
           注意:eg:
                    <form action='xxx' method='post'>
                        <input type='text' name='name'>
                     获取post请求方式的参数的方式
	 8.files       (文件上传)	  **
	 9.headers	   (请求头)
	 10.path       (路由中的路径)	 **
	 11.cookies    (请求中的cookie)
	 12.session	   (与request类似  也是一个内置对象  可以直接打印 print(session))
12 Response
	(1)返回字符串
		如果只有字符串,就是返回内容,数据
		还有第二个返回,放的是状态码
		@blue.route('/response/')
        def get_response():
               return '德玛西亚',404
	(2)render_template
		渲染模板
		将模板变成字符串
		@blue.route('/rendertemplate/')
         def render_temp():
              resp = render_template('Response.html')
              print(resp)
              print(type(resp))
              return rese,500
	(3)make_response
		Response对象
		返回内容
		状态码
		@blue.route('/makeresponse/')
		def  make_resp():
              resp = make_response('<h2>xxxxxxxx</h2>',502)
              print(resp)
              print(type(resp))
              return rese
	(4)redirect
		重定向
		@blue.route('/redirect/')
        def  make_redir():
             return redirect('/makeresponse/')
		反向解析 url_for
		@blue.route('/redirect/')
		def  make_redir():
       		return redirect(url_for('first.make_resp'))
	(5)Response()
		@blue.route('/testresponse4/')
        def testresponse4():
            res = Response('呵呵')
            print(type(res))
            return res
13.异常
abort
	直接抛出 显示错误状态码  终止程序运行
	abort(404)
	eg:
		@blue.route('/makeabort/')
         def make_abort():
              abort(404)
              return '天还行'
捕获
	@blue.errorhandler()
		- 异常捕获
		- 可以根据状态或 Exception进行捕获
		- 函数中要包含一个参数,参数用来接收异常信息
	eg:
	@blue.errorhandler(502)
    def handler502(exception):
        return '不能让你看到状态码'
14.会话技术
1.请求过程Request开始,到Response结束
2.连接都是短连接
3.延长交互的生命周期
4.将关键数据记录下来
5.Cookie是保存在浏览器端/客户端的状态管理技术
6.Session是服务器端的状态管理技术
(1)cookie
Cookie
	1.客户端会话技术
	2.所有数据存储在客户端
	3.以key-value进行数据存储层
	4.服务器不做任何存储
	5.特性
		(1)支持过期时间
			max_age  毫秒
			expries  具体日期
		(2)根据域名进行cookie存储
		(3)不能跨网站(域名)
		(4)不能跨浏览器
		(5)自动携带本网站的所有cookie
	6.cookie是服务器操作客户端的数据
	7.通过Response进行操作
cookie登陆使用
	设置cookie     response.set_cookie('username',username)
		
	获取cookie     username = request.cookies.get('username','游客')
		
	删除cookie     response.delete_cookie('username')
		
(2)session
Session
	1.服务端会话技术
	2.所有数据存储在服务器中
	3.默认存在服务器的内存中
		- django默认做了数据持久化(存在了数据库中)
	4.存储结构也是key-value形势,键值对
	【注】单纯的使用session是会报错的,需要使用在__init__方法中配置app.config['SECRET_KEY']=110
session登陆使用
	设置    session['username'] = username
	获取    session.get('username')
	删除
		   resp.delete_cookie('session')
		   session.pop('username')
(3)cookie和session总结
1)cookie: 客户端浏览器的缓存;session: 服务端服务器的缓存
(2)cookie不是很安全,别人可以分析存放在本地的cookie并进行cookie欺骗,考虑到安全应当使用session
(3)session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能,考虑到减轻服务器性能方面,应当使用cookie
可以考虑将登陆信息等重要信息存放为session,其他信息如果需要保留,可以放在cookie中
(4)session持久化问题

持久化简介

1.django中对session做了持久化,存储在数据库中
2.flask中没有对默认session进行任何处理
    - flask-session 可以实现session的数据持久化
    - 可以持久化到各种位置,更推荐使用redis
    - 缓存在磁盘上的时候,管理磁盘文件使用lru, 最近最少使用原则

持久化实现方案

	1.pip install flask-session
			在国内源安装
			pip install flask-session -i https://pypi.douban.com/simple/
	2.初始化Session对象 
			(1)持久化的位置
				配置init中app.config['SESSION_TYPE'] = 'redis'2)初始化
				创建session的对象有2种方式 分别是以下两种
				1 Session(app=app)
				2 se = Session()   se.init_app(app = app)3)安装redis   
				pip install redis
				设置了默认开机启动,如果没有设置,那么需要将redis服务开启
				
			 (4)需要配置SECRET_KEY='110'
			 	注意:flask把session的key存储在客户端的cookie中,通过这个key可以从flask的内存中获取					 用户的session信息,出于安全性考虑,使用secret_key进行加密处理。所以需要先设置secret_key的值。
			 	
			(5)其他配置--视情况而定
				app.config['SESSION_KEY_PREFIX']='flask'
		
     特殊说明:
            查看redis内容
                    redis-cli
                    keys *
                    get key
            session生存时间31天	
                ttl session
                    flask的session的生存时间是31天,django的session生存时间是14
15.Template

简介:

1)MVC中的View,MTV中的Template
	(2)主要用来做数据展示的
	(3)模板处理过程分为2个阶段
            1 加载
            2 渲染
    (4)jinja2模板引擎
            1.本质上是html
            2.支持特定的模板语法
            3.flask作者开发的   一个现代化设计和友好的python模板语言  模仿的django的模板引擎
            4.优点
                    速度快,被广泛使用
                    HTML设计和后端Python分离
                    减少Python复杂度
                    非常灵活,快速和安全
                    提供了控制,继承等高级功能

模板语法

1、基本语法

模板语言动态生成的html
		{{ var }}  变量的接收
			从views传递过来的数据
			前面定义出来的数据

2、结构标签

1)block
        首次出现挖坑操作
        第二次出现填坑操作
        第N次出现,填坑操作,会覆盖前面填的坑
        不想被覆盖,需要添加 {{ super() }}2)extends
	    继承
(3)include
		包含,将一个指定的模板包含进来

3、宏定义(macro)

1)无参
		{% macro say()%}
    			你饿了吗???
		{% endmacro %}2)有参
		{% macro createUser(name,age)%}
   				欢迎{{ name }} 心理没点数吗 你都{{ age }}大了
		{% endmacro %}3)外文件中的宏定义调用需要导入也可以include
		{% macro getUser(name)%}
    			欢迎光临红浪漫{{ name }},拖鞋手牌拿好,楼上2楼左转,男宾一位
		{% endmacro %}
		
		{% from ‘html文件’ import yyy %}
		{{ getUser('action') }}

4、循环控制

for
		for .. in 
			loop  循环信息
				  索引  index
				  第一个   first
				  最后一个last
if
		if 
		else
		elif

5、过滤器

语法格式:{{ var|xxx|yyy|zzz }}
没有数量限制
		lower
		upper
		trim
		reverse
		striptags   渲染之前将值中的标签去掉
		safe        标签生效
		eg:
			{% for c in config %}
                    <li>{{ loop.index0 }}:{{ loop.index}}:{{ c|lower|reverse }}</li>
    		{% endfor %}
16.models

简介

1.数据交互的封装
2.Flask默认并没有提供任何数据库操作的API
	Flask中可以自己的选择数据,用原生语句实现功能
		原生SQL缺点:1)代码利用率低,条件复杂代码语句越过长,有很多相似语句
              (2)一些SQL是在业务逻辑中拼出来的,修改需要了解业务逻辑
              直接写SQL容易忽视SQL问题
	也可以选择ORM
		SQLAlchemy
		MongoEngine
		将对象的操作转换为原生SQL
		优点
			 (1)易用性,可以有效减少重复SQL
              (2)性能损耗少
              (3)设计灵活,可以轻松实现复杂查询
              (4)移植性好
3.Flask中并没有提供默认ORM
	ORM 对象关系映射
	通过操作对象,实现对数据的操作

sqlalchemy

flask-sqlalchemy
     使用步骤:1.pip install flask-sqlalchemy
              2.创建SQLALCHEMY对象
                                   ①:db=SQLAlchemy(app=app)
                                   ②:db=SQLAlchemy()  上面这句话一般会放到models中  因为需要db来调                                       用属性 db.init_app(app=app)
              3.config中配置  SQLALCHEMY_DATABASE_URI
                                    数据库 + 驱动 :// 用户:密码@ 主机:端口/数据库
                                    dialect+driver://username:password@host:port/database
                                    eg:mysql+pymysql://root:1234@localhost:3306/flask1905
              4.执行
                    views中db.create_all()
                    
              注意:有坑
                            (1)primary-key
                                添加主键
                            (2)SQLALCHEMY_TRACK_MODIFICATIONS
                                	app.config[‘SQLALCHEMY_TRACK_MODIFICATIONS’]=False        
                                   
#ext

flask-sqlalchemy的基本使用
1 pip install flask-sqlalchemy
2 在models中创建sqlalchemy的对象  db = SQLAlchemy()
3 在init中对db对象进行初始化       db.init_app(app=app)
  注意:必须要在初始化之前添加SQLALCHEMY_DATABASE_URI和
                          SQLALCHEMY_TRACK_MODIFICATIONS=False的两个赋值
4 在init中对SQLALCHEMY_DATABASE_URI进行赋值
5 在init中对警告进行赋值  SQLALCHEMY_TRACK_MODIFICATIONS=False
6 在models中创建模型 注意模型必须继承db.model
                       模型必须有主键
                       模型中的字符串类型必须指定长度

flask-sqlalchemy的错误
1.如果执行create_all的时候  那么报错ModuleNotFoundError: No module named 'pymysql'
那么证明你的虚拟环境中 没有pymysql的安装
2.(in table 'user', column 'name'): VARCHAR requires a length on dialect mysql
  在flask中的字符串数据类型的字段 必须指定长度
  eg:name = db.Column(db.String(20))


flask-migrate  模型迁移
    模型迁移  就是不需要执行create_all 或者 drop_all等方法 就可以直接操作模型的创建
    以及删除

    使用步骤:
        1 安装 pip install flask-migrate
        2 创建以及初始化
            在init中 migrate = Migrate()
                    migrate.init_app(app=app,db=db)  db就是sqlalchemy的对象
        3 在manager中添加   manager.add_command('db',MigrateCommand)
          因为我们可以使用命令行来操作这个执行 所以要添加到manager上

        4 (1)python manager.py db init    --->生成migrations的文件夹
          (2)python manager.py db migrate --->生成迁移文件  操作了那个模型就生成
          哪个模型的迁移文件
          (3)python manager.py db upgrade --->升级  执行迁移文件

          以上三步就能将模型迁移到数据库 生成表
          (4)python manager.py db downgrade ---》降级
使用:
	(1)定义模型
			继承Sqlalchemy对象中的model
			eg:
				class User(db.Model):
                        id = db.Column(db.Integer,primary_key=True,autoincrement=True)l
                        name = db.Column(db.String(32))
                        age = db.Column(db.Integer)
     (2)创建
			db.create_all()
	 (3)删除
			db.drop_all()
	 (4)修改表名
			__tablename__ = "Worker"
      (5)数据操作
            添加
                db.session.add(对象)
                db.session.commit()
            查询
                模型.query.all()
17.ORM
简介
对象关系映射(Object Relational Mapping,简称ORM。ORM是通过使用描述对象和数据库之间映射,将程序中的对象自动持久化到关系数据库中。让我们从O/R开始。字母O起源于"对象"(Object),而R则来自于"关系"(Relational)。几乎所有的程序里面,都存在对象和关系数据库。在业务逻辑层和用户界面层中,我们是面向对象的。当对象信息发生变化的时候,我们需要把对象的信息保存在关系数据库中。 
当你开发一个应用程序的时候(不使用O/R Mapping),你可能会写不少数据访问层的代码,用来从数据库保存,删除,读取对象信息,等等。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Wg4JsVHQ-1590763077277)(C:\Users\ADMINI~1\AppData\Local\Temp\1587991248938.png)]

简单说,ORM 就是通过实例对象的语法,完成关系型数据库的操作的技术,是"对象-关系映射"(Object/Relational Mapping) 的缩写。

18.flask-migrate(模型迁移)
使用步骤
        (1)安装
            	pip install flask-migrate
        (2)初始化
                1.创建migrate对象
                  需要将app 和 db初始化 
                       migrate = Migrate()
                       migrate.init_app(app=app, db=db)
                2.懒加载初始化
                  结合flask-script使用
                  在manage上添加command (MigrateCommand)
                       manager.add_command("db", MigrateCommand)3)python manager.py db xxx
                1.init     生成migrations文件夹
                2.migrate  生成迁移文件
                           不能生成有2种情况
                                (1)模型定义完成从未调用
                                (2)数据库已经有模型记录
                3.upgrade  升级  执行迁移文件
                4.downgrade 降级
          扩展:
                创建用户文件
                    python manager.py db migrate  --message ‘创建用户’
19.DML
# ext

 DDL  数据定义语言  操作表的  对表操作的语言         data  ding  language
        create  drop  alter
  DML  数据操作语言  操作记录的 对表的记录操作的语言   data   make  language
        insert  delete  update
  DQL  数据查询语言                                data   query language
        select
  TCL  事务控制语言
        rollback
        commit

 如果想重新迁移文件
    那么报错的话 必须要 删除迁移文件  删除迁移记录  删除对应的表
    flask的迁移和django的迁移的修改都是一致的
    需要对迁移文件  迁移记录  表  都删除

    注意 flask的迁移记录在alembic_version里面
        django的迁移记录在django_migrations里面
19.1 增 删 改
1.增
	创建对象
		(1)添加一个对象
                  db.session.add()
                         eg:
                         @blue.route("/addperson/")
                          def add_person():
                              p = Person()
                              p.p_name = "小明"
                              p.p_age = 15
                              db.session.add(p)
                              db.session.commit()
                              return "添加成功"2)添加多个对象
                  db.session.add_all()
                          eg:
                          @blue.route("/addpersons/")
                          def app_persons():
                              persons = []
                              for i in range(5):
                                  p = Person()
                                  p.p_name = "猴子请来的救兵%d" % random.randrange(100)
                                  p.p_age = random.randrange(70)
                                  persons.append(p)
                              db.session.add_all(persons)
                              db.session.commit()
                              return "添加成功"
2.删除 建立在查询之上
@blue.route('/deletePerson/')
def deletePerson():
    person = Person.query.get(1)
    print(type(person))

    db.session.delete(person)
    db.session.commit()

    return '删除成功'
3.# 修改 所有flask的修改都建立在查询之上
@blue.route('/updatePerson/')
def updatePerson():
    person = Person.query.get(2)
    person.name = '马大嫂'
    person.age = 80

    db.session.add(person)
    db.session.commit()

    return '修改成功'
19.2 查
1.获取单个数据
	(1)get                  返回的是Person对象
            主键值
            获取不到不会抛错
            person = Person.query.get(3)
            db.session.delete(person)
            db.session.commit()2)first                返回的是Person对象
		   person = Person.query.first()3)没有 last()
2.获取结果集
	(1)xxx.query.all         返回值类型 list
			persons = Person.query.all()2)xxx.query.filter_by  
	        #返回值类型 basequery对象 可以被迭代  前面多写(filter_by)后面就少写(=)
			persons = Person.query.filter_by(p_age=15)3)xxx.query.filter    
			#返回值类型 basequery对象 可以被迭代  前面少写(filter)后面就少写(==)
			persons = Person.query.filter(Person.p_age < 18)
			persons = Person.query.filter(Person.p_age.__le__(15))
			persons = Person.query.filter(Person.p_name.startswith("小"))
			persons = Person.query.filter(Person.p_name.endswith("1"))
			persons = Person.query.filter(Person.p_name.contains("1"))
			persons = Person.query.filter(Person.p_age.in_([15, 11]))
3.数据筛选
		
	(1)order_by     #返回值类型 basequery对象 可以被迭代
		# 按照年龄排序 升序
			persons = Person.query.order_by("p_age")
		# 按照年龄排序 降序
			persons = Person.query.order_by(db.desc(Person.age))
			persons = Person.query.order_by(Person.age.desc())2)limit         #返回值类型 basequery对象 可以被迭代
		# 获取前5个数据
			persons = Person.query.limit(5)3)offset        #返回值类型 basequery对象 可以被迭代
		# 跳过前5个数据
			persons = Person.query.offset(5)
		#跳过前5个数据,取5个数据
			persons = Person.query.limit(5).offset(5)
			persons = Person.query.offset(5).limit(5)
		# 先跳过前5个数据,然后按age降序排列,order_by必须写在query后面
			persons = Person.query.order_by(Person.age.desc()).offset(5)4)offset和limit不区分顺序,offset先生效
			persons = Person.query.order_by("-id").limit(5).offset(5)
			persons = Person.query.order_by("-id").limit(5)
		 	persons = Person.query.order_by("-id").offset(17).limit(5)5)order_by 需要先调用执行  是query调用的  不是 basequery调用
		 	persons = Person.query.order_by("-id").offset(17).limit(5)
# 分页器方法:
	属性:
	# paginate里面有2个参数  page per_page
    # paginate方法的返回值类型是pagination对象
    # per_page:每页的条数,默认为20条
    # pages:总页数
    # total:总条数
    # prev_num 上一页的页码
    # has_prev 是否有上一页
    # has_next 是否有下一页
    # next_num 下一页页码
	# items: 当前页的数据
    iter_pages     (用于迭代页码 是一个方法)
    方法:
    	iter_pages(): 返回一个迭代器,在分页导航条上显示的页码列表,显示不完全的时候返回None
        prev: 上一页的分页对象
        next: 下一页的分页对象
4.pagination
	(1)简介:分页器
              需要想要的页码
              每一页显示多少数据
	(2)原生:
		 	 persons = Person.query.offset((page_num - 1) * page_per).limit(page_per)3)封装:
          	 参数(page,page_per,False(是否抛异常)
         	 persons = Person.query.paginate(page_num, page_per, False).items
5.逻辑运算
	(1)与   and_(条件 1, 条件 2) 两个条件是并且的关系 需要同时满足
			#basequery对象

		    and_     filter(and_(条件))
			huochelist = kaihuoche.query.filter(and_(kaihuoche.id == 1,kaihuoche.name == 'lc'))2)或   or_(条件 1,条件 2...) 条件之间是或者的关系 有几个成立返回几个,如果一个满足则返回一个
			#basequery对象
			or_          filter(or_(条件))
			huochelist = kaihuoche.query.filter(or_(kaihuoche.id == 1,kaihuoche.name =='lc'))3)非   #basequery对象
			not_         filter(not_(条件))  注意条件只能有一个
			huochelist = kaihuoche.query.filter(not_(kaihuoche.id == 1))4in   #basequery对象
		    huochelist = kaihuoche.query.filter(kaihuoche.id.in_([1,2,4]))5# 不要id==1 不要name=='双儿'  可以用 and_(not_)  也可用 not_(or_)
    	persons = Person.query.filter(and_(not_(Person.id==1),(not_(Person.name=='双儿'))))

20.数据定义
1)字段类型
                Integer
                String
                Date
                Boolean
	(2)约束
		primary_key   (主键)   			
		autoincrement (主键自增长)     			
		unique        (唯一) 			
		default       (默认)   			
		index         (索引)    			
		not null     (非空)			
		ForeignKey    (外键)                       
                        用来约束级联数据
                        db.Column( db.Integer, db.ForeignKey(xxx.id) )
                        使用relationship实现级联数据获取
                            声明级联数据
                            backref="表名"
                            lazy=True
21.模型关系
5.1 一对多
1)模型定义
	# flask中模型迁移之后, 普通字段默认可以为null
	# django中模型迁移之后,普通字段默认可以为not null
	# 外键中 ForeignKey中的值是  主表模型的小写.id
          class Parent(db.Model):
              id=db.Column(db.Integer,primary_key=True,autoincrement=True)
              name=db.Column(db.String(30),unique=True)
              children=db.relationship("Child",backref="parent",lazy=True)
              def __init__(self):
                  name=self.name

          class Child(db.Model):
              id = db.Column(db.Integer, primary_key=True)
              name = db.Column(db.String(30), unique=True)
              parent_id = db.Column(db.Integer, db.ForeignKey('parent.id'))
              def __init__(self):
                  name = self.name
	 boyFriend_list = db.relationship('BoyFriends',backref='girl',lazy=True)2)参数介绍:
 		 1.relationship函数   在表结构中没有字段,但是可以调用
                    sqlalchemy对关系之间提供的一种便利的调用方式,关联不同的表;
          2.BoyFriends 参数 : 子表的名字
          3.backref参数 :  'girl' 主表名字的小写
                    对关系提供反向引用的声明,Boy,之后可以在boy.girl来获取这个地址的girl;
          3.lazy参数
                    (1'select'(默认值)
                        SQLAlchemy 会在使用一个标准 select 语句时一次性加载数据;
                    (2'joined'
                        让 SQLAlchemy 当父级使用 JOIN 语句是,在相同的查询中加载关系;
                    (3'subquery'
                        类似 'joined' ,但是 SQLAlchemy 会使用子查询;
                    (4'dynamic':
                        SQLAlchemy 会返回一个查询对象,在加载这些条目时才进行加载数据,大批量数据查询处理时推荐使用。
          4.ForeignKey参数
                    代表一种关联字段,将两张表进行关联的方式,表示一个person的外键,设定上必须要能在父表中找到对应的id
3)模型的应用
            添加
                eg:@blue.route('/add/')
                    def add():
                       # 添加主表
                        p = Parent()
                        p.name = '张三'
                        
                         # 添加从表(外键为null情况时添加到从表的外键字段为空)
                         # flask中模型迁移之后, 普通字段默认可以为null
                         # 如果调用了relationship用法,则自动在从表添加对应的外键
                        c = Child()
                        c.name = '张四'
                        c1 = Child()
                        c1.name = '王五'
                        p.children = [c,c1]

                        db.session.add(p)
                        db.session.commit()

                        return 'add success'
            查
                  eg:
                  主查从 --》 Parent--》Child
                  # 没有使用relationship的方法
                  @blue.route('/getChild/')
                  def getChild():
                      clist = Child.query.filter(Parent.id == 1)
                      for c in clist:
                          print(c.name)
                      return 'welcome to red remonce'
                      
                  # 使用relationship的方法
                  #models.py
                  boyFriend_list = db.relationship('BoyFriends')
                  #views.py
                  boys = Girl.query.filter(Girl.name == name)[0].boyFriend_list
                      
                  从查主
                  # 在没有添加backref的情况下
                  @blue.route('/getParent/')
                  def getParent():
                      p = Parent.query.filter(Child.id == 2)
                      print(type(p))
                      print(p[0].name)
                      return '开洗'
                    
                  # 添加了backref的情况下
                  #models.py
                  boyFriend_list = db.relationship('BoyFriends',backref='girl')
                  
                  name = request.args.get('name')
    			 girl = BoyFriends.query.filter(BoyFriends.name==name)[0].girl
                  
                  print(girl.name)   
5.2 一对一
   一对一需要设置relationship中的uselist=Flase,其他数据库操作一样。
5.3 多对多
1)模型定义
          class User(db.Model):
              id = db.Column(db.Integer,primary_key=True,autoincrement=True)
              name = db.Column(db.String(32))
              age = db.Column(db.Integer,default=18)

          class Movie(db.Model):
              id = db.Column(db.Integer,primary_key=True,autoincrement=True)
              name = db.Column(db.String(32))

          class Collection(db.Model):
              id = db.Column(db.Integer,primary_key=True,autoincrement=True)
              u_id = db.Column(db.Integer,db.ForeignKey(User.id))
              m_id = db.Column(db.Integer,db.ForeignKey(Movie.id))
2)应用场景
          电影添加
              @blue.route('/getcollection/')
              def getcollection():
                    u_id = int(request.args.get('u_id'))
                    m_id = int(request.args.get('m_id'))
                    # 链式调用
                   # 看collection中这个用户且有没有买过这个电影
                    collections = Collection.query.filter(Collection.u_id==user.id).filter(Collection.m_id==movie.id)

                    if collections.count() > 0:
                        collection = collections.first()
                        collection.num = collection.num + 1

                    else:
                        collection = Collection()
                        collection.u_id = user.id
                        collection.m_id = movie.id

                    db.session.add(collection)
                    db.session.commit()

                    return '添加成功'
22.flask-bootstrap
插件安装
	pip install  flask-bootstrap
ext中初始化
	Bootstrap(app=app)
	
bootstrap案例--bootstrap模板   {% extends ‘bootstrap/base.html’%}
23.flask-debugtoolbar
辅助调试插件
安装
	pip install flask-debugtoolbar
初始化  ext 
     app.debug = True (最新版本需要添加)
	debugtoolbar = DebugToolBarExtension()
	debugtoolbar.init_app(app=app)
24.缓存flask-cache
# 存的flask和werkzuge的版本问题
    # cache
    # 1.由于flask更新了 werkzeug页也跟着更新  但是flask-cache没有更新
    # 所以版本兼容性就出现了问题
    # 此时的flask-cache兼容什么版本的werkzeug呢? 0.16.1
    # 解决方案:将werkzeug删除 然后安装0.16.1版本
    # 先卸载pip uninstall werkzeug
    # pip install werkzeug==0.16.1

    # 2  No module named 'flask.ext'
    # 解决方案 进入到flask-cache的库 然后点击jinja2ext.py
    # 将from flask.ext.cache import make_template_fragment_key
    # 修改为from flask_cache import make_template_fragment_key
    
    # 服务器端也需要更改
1 缓存目的:
          缓存优化加载,减少数据库的IO操作
2 实现方案
          (1)数据库
          (2)文件
          (3)内存
          (4)内存中的数据库 Redis
3 实现流程
          (1)从路由函数进入程序
          (2)路由函数到视图函数
          (3)视图函数去缓存中查找
          (4)缓存中找到,直接进行数据返回
          (5)如果没找到,去数据库中查找
          (6)查找到之后,添加到缓存中
          (7)返回到页面上
4 使用
          (1)安装 flask-cache
				pip install flask-cache
		 (2)初始化
                 指定使用的缓存方案
                      cache = Cache(config={'CACHE_TYPE':默认是simple})
                      cache.init_app(app=app)3)使用
        		# 生效效果,距第一次访问的30秒内,都不要睡眠5秒
              在路由的下面添加@cache.cached(timeout=30)
              要配置config
                  TYPE
                  还可以配置各种缓存的配置信息
                      cache=Cache(config={'CACHE_KEY_PREFIX':'python'})4)用法
                  ①:装饰器
                      @cache.cached(timeout=xxx)
                  ②:原生
              # cache.get(key)获取, cache.set(key value)设置的意思
           			
缓存使用例子:

import time
# 缓存  (方法全部缓存)
#     装饰器缓存
@blue.route('/testCache/')
@cache.cached(timeout=30)
def testCache():
    time.sleep(5)
    return '测试缓存'


#     基本缓存 邮件发送  手机验证
@blue.route('/testCache1/')
def testCache1():
    # 如果你是第一次访问 那么显示欢迎客观,
    # 如果是第二次访问,显示小爬虫快走开

    # cache.get(key)获取, cache.set(key value)设置的意思

    # 从缓存汇总获取key值为ip的数据
    value = cache.get('ip2')

    if value:
        return '小爬虫快走开'
    else:
        # 如果没有拿到这个value的时候  就在缓存中设置一下
        # 等一下次访问就可以拿到了

        ip = request.remote_addr
        cache.set('ip2',ip,timeout=10)
        return '欢迎客官'
25.钩子
# 如果将4个方法中公用的逻辑封装方法 那么也不是很好  因为耦合度同样很高
# 我们这种治标不治本  只不过看似代码减少
# 解决方案:在执行视图函数之前 就执行某个方法
# eg:如果我们能够在执行add delete update find视图函数之前就执行某个方法
# 而且这些方法还不会再add delete update find中体现
# 那么耦合度是降到了最低

# blue.before_request就是在执行视图函数之前执行的方法
# 钩子的用法体现了一种思想   面向切面编程  也叫做面向方面编程 ==》AOP
# 嫁接  仙人掌嫁接仙人球
# 仙人掌 纵向的生长   嫁接 横向
# 代码都是一行一行的从上到下的执行 面对对象开发都是纵向开发
# 钩子这种方式实现了横向的开发 eg:在执行add之前执行了conn
# 我们把这种方式叫做面向切面编程 aop


# 如果我们定义了@blue.before_request 那么是再执行视图函数
# 之前就执行了某个方法

@blue.before_request
eg:
	  @blue.before_request
      def aop():
         print('i am aop simida')

      @blue.route('/add/')
      def add():
          print('i am add')
          return 'add'

      @blue.route('/delete/')
      def delete():
          print('i am delete')
          return 'delete'
26.四大内置对象
四大内置对象(不需要创建就可以使用的对象)
	(1)request
			 请求的所有信息
	(2)session
			 服务端会话技术的接口
	(3)config
              当前项目的配置信息
              模板中可以直接使用
                  config
              在python代码中
                  current_app.config
                  当前运行的app
                  使用记得是在初始化完成之后
                  用在函数中
              eg:
                  for c in current_app.config:
                      print(c)
	(4)g
			# ip变量如何能在testg中使用
			# g的属性 g.ip 必须要在使用的那个视图函数之前使用
              global  全局
              可以帮助开发者实现跨函数传递数据
              eg:
                  @blue.route('/g/')
              def g():
                  g.ip = request.remote_addr
                  return 'ok'

              @blue.route('/testg1/')
              def testg1():
                  print(g.ip)
                  return 'ok1'
27.路径
	BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
	init中app = Flask(__name__,static_folder=static_folder)
		 static_folder=os.path.join(settings.BASE_DIR,'static')
28.前后端分离
整合网络和软件的一种架构模式
理解
	Representtational
		表现层
	State Transfer
		状态转换
	表现层状态转换
		资源(Resource)
	每一个URI代表一类资源
		对整个数据的操作
		增删改查
RESTful中更推荐使用HTTP的请求谓词(动词)来作为动作标识
	GET
	POST
	PUT
	DELETE
	PATCH
推荐使用json数据传输
29.前后端分离-原生实现
概念:就是判断不同的请求方式,实现请求方法
高内聚,低耦合
	高内聚
	相同的数据操作封装在一起
	低耦合
MVC 没有模板--前后端分离
get
		坑---类型
		eg:
		@blue.route("/users/<int:id>/", methods=["GET", "POST", "PUT", "DELETE", "PATCH"])
        def users(id):
            if request.method == "GET":
                page = int(request.args.get("page", default=1))
                per_page = int(request.args.get("per_page", default=3))

                users = User.query.paginate(page=page, per_page=per_page, error_out=False).items
                users_dict = []
                for user in users:
                    users_dict.append(user.to_dict())

                data = {
                    "message": "ok",
                    "status": "200",
                    "data": users_dict
                }

                return jsonify(data)
post
		eg:
            elif request.method == "POST":
                  # 更新或创建
                  username = request.form.get("username")
                  password = request.form.get("password")

                  data = {
                      "message": "ok",
                      "status": "422"
                  }
				# data类型是dict
                  if not username or not password:
                      data["message"] = "参数不正确"
                      return jsonify(data), 422
                      
				# jsonify类型是Response
                  user = User()
                  user.u_name = username
                  user.u_password = generate_password(password=password)

                  try:

                      db.session.add(user)
                      db.session.commit()
                      data["status"] = "201"
                  except Exception as e:
                      data["status"] = "901"
                      data["message"] = str(e)
                      return jsonify(data), 422

                  return jsonify(data), 201
put #修改的是全部数据
		eg:
			elif request.method == "PUT":
                      username = request.form.get("username")
                      password = request.form.get("password")
                      user = User.query.get(id)

                      user.u_name = username
                      user.u_password = generate_password(password)

                      db.session.add(user)
                      db.session.commit()

                      data = {
                          "message": "update success",
                      }

                      return jsonify(data), 201
delete
		eg:
		    elif request.method == "DELETE":
                    user = User.query.get(id)

                    data = {
                        "message": "delete success"
                    }

                    if user:
                        db.session.delete(user)
                        db.session.commit()
                        return jsonify(data), 204
                    else:
                        data["message"] = "指定数据不存在"
                        return jsonify(data)

	patch # 修改的是 部分数据
			eg:
			   elif request.method == "PATCH":
                        password = request.form.get("password")
                        user = User.query.get(id)
                        user.u_password = generate_password(password)

                        data = {
                            "messgage": "update success"
                        }

                        db.session.add(user)
                        db.session.commit()

                        return jsonify(data), 201
md5
	    eg:
	    def generate_password(password):
              hash = hashlib.md5()
              hash.update(password.encode("utf-8"))
              return hash.hexdigest()
30.flask-restful

使用

使用
	安装 pip install flask-restful
	初始化 
		urls---在init中调用init_urls
			api = Api()
			api.add_resource(Hello, "/hello/")
				Hello是一个类的名字  hello是路由
			def init_urls(app):
    		api.init_app(app=app)
    
	apis--基本用法
		继承自Resource
			class Hello(Resource):
		实现请求方法对应函数
			def get(self):
        		return {"msg": "ok"}

            def post(self):
                return {"msg": "create success"}

定制输入输出

# 结构化输出的例子
from flask_restful import Resource, marshal_with, fields

# 结构化输出  返回的内容由结构来固定
# 解决序列化问题

r1_field={
    'msg':fields.String,
    'status':fields.Integer,
    'code': fields.Integer,
    'message':fields.String(default='aaaa')
}

class CatResource(Resource):

    #marshal_with 结构化输出 以指定的结果来当做返回值
    # (1)结果方法返回的数据在结构化中没有定义  那么会被过滤
    #(2)如果预定义结构中的数据比方法的返回值多 那么会给定一个默认值
    # 如果是整形 那么返回0 ; 如果是字符串 那么返回的是null
    # (3) 如果预定义结构和方法的返回值一致 那么就正常返回
    @marshal_with(r1_field)
    def get(self):
        data = {
            'msg': 'test ok',
            'status' : 200,
            'xxx':'qqqq'
        }
        return data
# flask_restful序列化对象的例子
from flask_restful import Resource, marshal_with, fields

from App.models import Cat

r2_field = {
    'id':fields.Integer,
    'name':fields.String,
}

r1_field = {
    'msg':fields.String,
    'status': fields.Integer,
    'cat':fields.Nested(r2_field)
}

class Cat1Resource(Resource):

    @marshal_with(r1_field)
    def get(self):

        # 序列化难度大
        cat = Cat.query.first()
        data = {
            'msg':'ok',
            'status':200,
            'cat':cat
        }
        return data
# flask-restful 返回列表形式 basequery  的例子
from flask_restful import Resource, fields, marshal_with
from flask_restful.fields import Nested

from App.models import Cat


r2_field = {
    'id':fields.Integer,
    'name':fields.String,
}

r1_field = {
    'msg':fields.String,
    'status':fields.Integer,
    #如果查询的是所有  返回的是List  那么可以使用Nested
    # 如果返回值是basequery那么就会给默认值,不会给数据,此时就必须用list嵌套nested
    # 'cat_list':fields.Nested(r2_field)

    'cat_list':fields.List(fields.Nested(r2_field))
}

class Cat2Resource(Resource):
    @marshal_with(r1_field)
    def get(self):

        # 对象形式
        cat_list = Cat.query.all()

        # basequery形式
        cat_list = Cat.query.filter(Cat.name=='tom')

        data = {
            'msg': 'cat2 ok',
            'status': 200,
            'cat_list':cat_list
        }
        return data
定制输入输出
	输出
		fields中的类型约束
			String
			Integer
			Nested
			List
				Nested
		@marshal_with的基本使用
			类型括号中还允许添加约束
				attribute
					指定连接对应名字
						attribute=名字
				default
					设置默认值
						default=404
		marshal_with特性
			        - 默认返回的数据如果在预定义结构中不存在,数据会被自动过滤
        	         - 如果返回的数据在预定义的结构中存在,数据会正常返回
                      - 如果返回的数据比预定义结构中的字段少,预定义的字段会呈现一个默认值
			        如果类型是Integer  那么默认值是  0
                     如果类型是String  那么默认值是null
                @marshal_with返回一个类对象
                @marshal_with返回一个列表
	输入
		使用了parser=reqparse.RequestParser()
		parser.add_argument("c_name", type=str)
        parser.add_argument("id", type=int, required=True, help="id 是必须的")
		parse = parser.parse_args()
		cat_name = parse.get("c_name")
        id = parse.get("id")
         print(id)
		在对象中添加字段
			对字段添加约束
			default
			required
				必须的参数
			help
				id是必须的
			action
				action=append
					c_name=tom&c_name=zs
		继承
			copy
			可以对已有字段进行删除和更新
			继承解析
    - 在整个项目中,通用字段可以创建一个基parser
    - 复用已有的部分参数转换数据结构
			parse_c parser.copy()   parse_c.remove_argument('')
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值