第5章 章节五
-
01 内容概要
-
02 内容回顾
-
03 面向对象相关补充:metaclass(一)
-
04 面向对象相关补充:metaclass(二)
-
05 WTforms实例化流程分析(一)
-
06 WTforms实例化流程分析(二)
-
07 拓展:相关面试题
-
08 ORM框架概念
-
09 SQLAlchemy框架快速使用
-
10 SQLAlchemy框架组件使用
-
11 SQLAlchemy执行原生SQL
-
12 上述内容总结
-
13 SQLAlchemy创建表结构
-
14 SQLAlchemy实现基本增删改查(一)
-
15 SQLAlchemy实现基本增删改查(二)
-
16 SQLAlchemy小练习
-
17 SQLAlchemy常见操作
-
18 上述内容总结
-
19 homework
第6章 章节六
-
01 内容概要
-
02 内容回顾
-
03 WTforms组件验证流程
-
04 SQLAlchemy操作补充
-
05 homework
第7章 章节七
-
01 内容概要
-
02 内容回顾
-
03 Flask-script组件
-
04 FLask-SQLAlchemy组件应用(一)
-
05 Flask-SQLAlchemy组件应用(二)
-
06 Flask-SQLAlchemy组件应用(三)
-
07 Flask-SQLAlchemy组件应用总结
-
08 SQLAlchemy创建session的两种方式
-
09 Flask-Migrate组件
-
10 Flask自定义拓展
-
11 Flask多app应用
-
12 Flask信号blinker
-
13 Flask信号和before_request的区别
-
14 内容总结和作业
第5章 章节五
01 内容概要
1.1 面向对象相关;
- _mro__;
- metaclass;
1.2 WTforms;
1.3 SQLALchemy(Flask中的一个ORM框架);
1.4 SQLALchemy/flask-sqlalchemy;
1.5 flask其他;
- flask-script;
- flask-migrate;
- 多app应用;
- 离线脚本;
02 内容回顾
2.1 Flask和Django的区别;
1:重量级web框架,功能齐全,提供一站式解决的思路,能让开发者不用在选择应用上花费大量时间;
2:自带ORM(Object-Relational Mapping 对象关联映射)和模板引擎,支持JinJa等非官方模板引擎,灵活度不高;
3:自带ORM使Django和关系型数据库耦合度过高,如果要使用非关系型数据库,需要使用第三方库;
4:自带数据库管理app;
5:成熟、稳定、开发效率高、相对于Flask,Django的整体封闭性比较好,适合做企业级网站的开发;
6:python web框架的先驱,第三方库丰富;
7:上手容易,开发文档详细、完善、资料丰富;
1:轻量级web框架,只有一个内核,默认依赖两个外部库:Jinja2 模板引擎和 Werkzeug WSGI 工具集,自由,灵活,可扩展性强,开发者可以根据需求自己造轮子;
2:适用于做小型网站以及web服务的API,开发大型网站无压力,架构需自行设计;
3:与关系型数据库结合不弱于Django,而与非关系型数据库的结合远远优于Django;
2.2 Flask的上下文管理是如何实现的?
http://www.cnblogs.com/zhaopanpan/articles/9457343.html
问题一:flask和django的区别: 对于django来说,内部组件特别多,自身功能强大,有点大而全,而flask,内置组件很少,但是它的第三方组件很多,扩展性强,有点短小精悍,而它们之间也有相似之处, 因为它们两个框架都没有写sockte,都是基于wsgi协议做的,在此之外,flask框架中的上下文管理较为耀眼。 相同点:它们两个框架都没有写sockte,都是基于wsgi协议做的 请求相关数据传递的方式不同:django:通过传递request参数取值 flask:见问题二 组件不同:django组件多 flask组件少,第三方组件丰富 问题1.1: flask上下文管理: 简单来说,falsk上下文管理可以分为三个阶段: 1、请求进来时,将请求相关的数据放入上下问管理中 2、在视图函数中,要去上下文管理中取值 3、请求响应,要将上下文管理中的数据清除 详细点来说: 1、请求刚进来,将request,session封装在RequestContext类中,app,g封装在AppContext类中,并通过LocalStack将requestcontext和appcontext放入Local类中 2、视图函数中,通过localproxy--->偏函数--->localstack--->local取值 3、请求相应时,先执行save.session()再各自执行pop(),将local中的数据清除 问题1.2 flask第三方组件 flask: -flask-session 默认放入cookie,可以放入redis -flask-redis -flask-migrate -flask-script -blinker 信号 公共: DBUtils 数据库连接池 wtforms 表单验证+生成HTML标签 sqlalchemy 自定义:Auth 参考falsk-login 问题二:Flask中的session是什么时候创建,什么时候销毁的? 当请求进来时,会将requset和session封装为一个RequestContext对象,通过LocalStack将RequestContext放入到Local对象中,因为 请求第一次来session是空值,所以执行open_session,给session(uuid4())赋值,再通过视图函数处理,请求响应时执行save.session,将签名session写入cookie中,再讲Local中的数值pop掉。 问题三:flask中一共有几个LocalStack和Local对象 两个LocalStack,两个Local request、session共同用一个LocalStack和Local g、app共同用一个Localstack和Local 问题四: 为什么把请求放到RequestContext中: 因为request和session都是在视图中操作频繁的数据,也是用户请求需要用的数据,将request和session封装在RequestContext中top,pop一次就可以完成,而单独不封装在一起就会多次操作, ctx = RequestContext(request,session) 问题五:local作用 -保存 请求上下文对象和app上下文对象 -localstack的源码与threading.local(线程处理)作用相似,不同之处是Local是通过greenlet(协程)获取唯一标识,粒度更细 问题六:Localstack作用 2、将local对象中的数据维护成一个栈【ctx,ctx】(先进后出) { “协程或线程的唯一标识”: { stack:[ctx,ctx,ctx,] } } 为什么维护成一个栈? 当是web应用时:不管是单线程还是多线程,栈中只有一个数据 - 服务端单线程: { 111:{stack: [ctx, ]} } - 服务端多线程: { 111:{stack: [ctx, ]} 112:{stack: [ctx, ]} } 离线脚本:可以在栈中放入多个数据 with app01.app_context(): print(current_app) with app02.app_context(): print(current_app) print(current_app) 问题七:什么是g? g 相当于一次请求的全局变量,当请求进来时将g和current_app封装为一个APPContext类,在通过LocalStack将Appcontext放入Local中,取值时通过偏函数,LocalStack、loca l中取值,响应时将local中的g数据删除: 问题八:怎么获取Session/g/current_app/request 通过 、偏函数(lookup_req_object)、Localstack、Local取值 问题九: 技术点: - 反射 (LocalProxy()) - 面向对象,封装:RequestContext - 线程(threading.local) - 笔试:自己写一个类+列表 实现栈。(LocalStack) 问题十:python基本哪些内容比较重要: 1、反射 -CBV -django配置文件 -wtforms中的Form()示例化中 将"_fields中的数据封装到From类中" 2、装饰器 (迭代器,生成器) -flask:路由、装饰器 -认证 -csrf 3、面向对象 -继承、封装、多态(简单描述) -双下划线: __mro__ wtform中 FormMeta中继承类的优先级 __dict__ __new__ ,实例化但是没有给当前对象 wtforms,字段实例化时返回:不是StringField,而是UnboundField rest frawork many=Turn 中的序列化 __call__ flask 请求的入口app.run() 字段生成标签时:字段.__str__ => 字段.__call__ => 插件.__call__ __iter__ 循环对象是,自定义__iter__ wtforms中BaseForm中循环所有字段时定义了__iter__ metaclass - 作用:用于指定当前类使用哪个类来创建 - 场景:在类创建之前定制操作 示例:wtforms中,对字段进行排序。
2.3 Local的作用:
- 用于保存——请求上下文对象和app上下文对象;
- 做到“线程”间的数据隔离;
2.4 LocalStack作用?
- 将Local中保存的数据维护成一个栈(弹夹,后进先出);
2.5 Flask的内置组件;
- 配置
- 路由
- 视图
- 模板
- session
- 蓝图
- 闪现
- 装饰器
- 中间件
2.6 第三方组件;
- flask-session;私有,将原来保存在Cookies中的session数据保存在redis或者memcache中;
- DBUtils;公共,数据库连接池,维护数据库连接;
- WTforms;公共,用于做表单验证,生成html标签;
03 面向对象相关补充:metaclass(一)
3.1 面向对象相关-__mro__;
04 面向对象相关补充:metaclass(二)
4.1 metaclass的相关说明;
#!/usr/bin/python3 # -*- coding:utf-8 -*- # Project: SQLALchemy # Software: PyCharm # Time : 2018-09-21 16:31 # File : 3.metaclass.py # Author : 天晴天朗 # Email : [email protected] # 创建类的两种方式; # 方式一: class Foo(object): CITY = 'BJ' def func(self, x): return x + 1 # 方式二: def func(self, x): return x + 1 # Foo1 = type('Foo1', (object,), {'CITY': 'BJ', 'func': func}) # 另外一种形式: Foo2 = type('Foo', (object,), {'CITY': 'BJ', 'func': lambda self, x: x + 1}) # 2、类由自定义type创建; class Foo3(object, metaclass=type): # 当前类由type类创建; # __metaclass__ = type# Python2的创建方式; CITY = 'BJ' def func(self, x): return x + 1 class MyType(type): def __init__(self, *args, **kwargs): print('创建类之前') super(MyType, self).__init__(*args, **kwargs) print('创建类之后') class Foo4(object, metaclass=MyType): CITY = 'BJ' def func(self, x): return x + 1 print(Foo4) """ 1、类由type创建,metaclass可以指定当前类由哪一个类创建; """ class MyType1(type): def __init__(self, *args, **kwargs): print('创建类之前') super(MyType1, self).__init__(*args, **kwargs) print('创建类之后') class Foo1(object, metaclass=MyType1): CITY = 'BJ' def func(self, x): return x + 1 class Bar(Foo): pass """ 小结: 1、默认类由type实例化创建; 2、某个类指定metaclass = MyType,那么当前类的所有派生类都由于MyType创建; 3、实例化对象: -type.__init__ -type.__call__ -类名.__new__ -类名.__init__ """
05 WTForms实例化流程分析(一)
5.1 WTForms的实例化流程;
# 源码流程 1. 执行type的 __call__ 方法,读取字段到静态字段 cls._unbound_fields 中; meta类读取到cls._wtforms_meta中 2. 执行构造方法 a. 循环cls._unbound_fields中的字段,并执行字段的bind方法,然后将返回值添加到 self._fields[name] 中。 即: _fields = { name: wtforms.fields.core.StringField(), } PS:由于字段中的__new__方法,实例化时:name = simple.StringField(label='用户名'),创建的是UnboundField(cls, *args, **kwargs),当执行完bind之后,才变成执行 wtforms.fields.core.StringField() b. 循环_fields,为对象设置属性 for name, field in iteritems(self._fields): # Set all the fields to attributes so that they obscure the class # attributes with the same names. setattr(self, name, field) c. 执行process,为字段设置默认值:self.process(formdata, obj, data=data, **kwargs) 优先级:obj,data,formdata; 再循环执行每个字段的process方法,为每个字段设置值: for name, field, in iteritems(self._fields): if obj is not None and hasattr(obj, name): field.process(formdata, getattr(obj, name)) elif name in kwargs: field.process(formdata, kwargs[name]) else: field.process(formdata) 执行每个字段的process方法,为字段的data和字段的raw_data赋值 def process(self, formdata, data=unset_value): self.process_errors = [] if data is unset_value: try: data = self.default() except TypeError: data = self.default self.object_data = data try: self.process_data(data) except ValueError as e: self.process_errors.append(e.args[0]) if formdata: try: if self.name in formdata: self.raw_data = formdata.getlist(self.name) else: self.raw_data = [] self.process_formdata(self.raw_data) except ValueError as e: self.process_errors.append(e.args[0]) try: for filter in self.filters: self.data = filter(self.data) except ValueError as e: self.process_errors.append(e.args[0]) d. 页面上执行print(form.name) 时,打印标签 因为执行了: 字段的 __str__ 方法 字符的 __call__ 方法 self.meta.render_field(self, kwargs) def render_field(self, field, render_kw): other_kw = getattr(field, 'render_kw', None) if other_kw is not None: render_kw = dict(other_kw, **render_kw) return field.widget(field, **render_kw) 执行字段的插件对象的 __call__ 方法,返回标签字符串
#!/usr/bin/env python # -*- coding:utf-8 -*- from flask import Flask, render_template, request, redirect from wtforms import Form from wtforms.fields import core from wtforms.fields import html5 from wtforms.fields import simple from wtforms import validators from wtforms import widgets app = Flask(__name__, template_folder='templates') app.debug = True class LoginForm(Form): name = simple.StringField( label='用户名', validators=[ validators.DataRequired(message='用户名不能为空.'), validators.Length(min=6, max=18, message='用户名长度必须大于%(min)d且小于%(max)d') ], widget=widgets.TextInput(), render_kw={'class': 'form-control'} ) pwd = simple.PasswordField( label='密码', validators=[ validators.DataRequired(message='密码不能为空.'), validators.Length(min=8, message='用户名长度必须大于%(min)d'), validators.Regexp(regex="^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[$@$!%*?&])[A-Za-z\d$@$!%*?&]{8,}", message='密码至少8个字符,至少1个大写字母,1个小写字母,1个数字和1个特殊字符') ], widget=widgets.PasswordInput(), render_kw={'class': 'form-control'} ) @app.route('/login', methods=['GET', 'POST']) def login(): if request.method == 'GET': form = LoginForm() return render_template('login.html', form=form) else: form = LoginForm(formdata=request.form) if form.validate(): print('用户提交数据通过格式验证,提交的值为:', form.data) else: print(form.errors) return render_template('login.html', form=form) if __name__ == '__main__': app.run() app.py
06 WTforms实例化流程分析(二)
6.1 WTForms实例化流程分析;
a. 执行form的validate方法,获取钩子方法 def validate(self): extra = {} for name in self._fields: inline = getattr(self.__class__, 'validate_%s' % name, None) if inline is not None: extra[name] = [inline] return super(Form, self).validate(extra) b. 循环每一个字段,执行字段的 validate 方法进行校验(参数传递了钩子函数) def validate(self, extra_validators=None): self._errors = None success = True for name, field in iteritems(self._fields): if extra_validators is not None and name in extra_validators: extra = extra_validators[name] else: extra = tuple() if not field.validate(self, extra): success = False return success c. 每个字段进行验证时候 字段的pre_validate 【预留的扩展】 字段的_run_validation_chain,对正则和字段的钩子函数进行校验 字段的post_validate【预留的扩展】
07 拓展:相关面试题
7.1 Python基础部分哪些比较重要?
- 反射——CBV、Django的配置文件、WTForms;
- 装饰器——Flask路由、认证、CRSF
- 生成器、迭代器
- 面向对象——继承、封装和多态;特殊的功能:双下划线方法(__mro__、__dict__、__new__、__call__、__iter__)以及metaclass;
08 ORM框架概念
8.1 什么是ORM框架?
关系-对象-映射(Object-Object Relational Mapping);
当有了对应关系后,不再需要编写SQL语句,取而代之是操作:类、对象;
8.2 ORM和原生SQL的优缺点?
8.2.1 ORM;
- 快速开发
- 性能差
8.2.2 SQL;
- 性能好
- 开发速度慢
8.2.3 DB First(已经使用原生SQL开发,根据数据库的表生成类);
8.2.4 Code First(ORM是CodeFirst,根据类创建数据表);
- python3 manage.py inspect
8.2.5 ORM是如何实现的?内置解析器实现;通过对象和类转化成字符换;
09 SQLAlchemy框架快速使用
9.1 SQLAlchemy,是一个基于Python实现的ORM框架;
9.2 SQLAlchemy的快速使用;
ORM.py;
#!/usr/bin/python3 # -*- coding:utf-8 -*- # Project: SQLALchemy # Software: PyCharm # Time : 2018-09-22 09:54 # File : 1.ORM.py # Author : 天晴天朗 # Email : [email protected] "" """ SQLAlchemy插入数据操作; """ import models #from sqlalchemy.ext.declarative import declarative_base #from sqlalchemy import Column, Integer, String, ForeignKey, UniqueConstraint, Index from sqlalchemy.orm import sessionmaker, relationship from sqlalchemy import create_engine engine = create_engine("mysql+pymysql://root:Tqtl911!@%*)@mysql.cuixiaozhao.com:3306/flask_session", max_overflow=5) Session = sessionmaker(bind=engine) session = Session() obj1 = models.Users(name="cuixiaozhao", extra="cxz") obj2 = models.Users(name="cuixiaozhao", extra="cxz") session.add(obj1) session.add(obj2) session.commit()
models.py;
#!/usr/bin/python3 # -*- coding:utf-8 -*- # Project: SQLALchemy # Software: PyCharm # Time : 2018-09-22 09:54 # File : models.py # Author : 天晴天朗 # Email : [email protected] "" """ 1、安装pip3 install sqlalchemy ; 2、依赖于pymysql进行数据库连接; 3、并不支持修改表结构,仅支持在数据库修改字段后,再重新在此处修改; """ from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column, Integer, String, UniqueConstraint, Index from sqlalchemy import create_engine Base = declarative_base() # 创建数据表; class Users(Base): __tablename__ = "users" id = Column(Integer, primary_key=True, autoincrement=True) name = Column(String(32)) extra = Column(String(16)) # __table_args = ( # UniqueConstraint('id', 'name', name='uix_id_name'), # Index('ix_id_name', 'name', 'extra') # ) # 数据库连接相关; # engine = create_engine("mysql+pymysql://root:Tqtl911!@%*)@mysql.cuixiaozhao.com/flask_session?charset=utf8") # Base.metadata.create_all(engine) # 删除表; # Base.metadata.drop_all(engine) # 向表中插入数据; def init_db(): # 数据库连接相关; engine = create_engine("mysql+pymysql://root:Tqtl913421411!@%*)@123.321.com:3306/flask_session?charset=utf8") # 创建表; Base.metadata.create_all(engine) def drop_db(): # 数据库连接相关; engine = create_engine("mysql+pymysql://root:Tqtl911!@%*4321432)@123.321.com:3306/flask_session?charset=utf8") # 删除表; Base.metadata.drop_all(engine) if __name__ == '__main__': init_db() # drop_db()
10 SQLAlchemy框架组件使用
10.1 SQLAlchemy框架组件使用;
SQLAlchemy本身无法操作数据库,其必须以来pymsql等第三方插件,Dialect用于和数据API进行交流,根据配置文件的不同调用不同的数据库API,从而实现对数据库的操作,如:
MySQL-Python mysql+mysqldb://: @ [: ]/ pymysql mysql+pymysql:// : @ / [? ] MySQL-Connector mysql+mysqlconnector:// : @ [: ]/ cx_Oracle oracle+cx_oracle://user:pass@host:port/dbname[?key=value&key=value...] 更多详见:http://docs.sqlalchemy.org/en/latest/dialects/index.html
11 SQLAlchemy执行原生SQL
11.1 SQLAlchemy执行原生SQL语句操作;
- 基于SQLAlchemy写原生SQL(优势在于自带数据库连接池);
- 基于SQLAlchemy写ORM;
- DBUtils+pymysql创建连接池;
#!/usr/bin/python3 # -*- coding:utf-8 -*- # Project: SQLALchemy # Software: PyCharm # Time : 2018-09-22 11:05 # File : 3.执行原生SQL.py # Author : 天晴天朗 # Email : [email protected] from sqlalchemy import create_engine engine = create_engine("mysql+pymysql://root:@flask_session123456mysql.cuixiaozhao.com:3306/", max_overflow=5) # 执行SQL cur = engine.execute( "INSERT INTO hosts (host, color_id) VALUES ('1.1.1.22', 3)" ) # 新插入行自增ID cur.lastrowid # 执行SQL cur = engine.execute( "INSERT INTO hosts (host, color_id) VALUES(%s, %s)", [('1.1.1.22', 3), ('1.1.1.221', 3), ] ) # 执行SQL cur = engine.execute( "INSERT INTO hosts (host, color_id) VALUES (%(host)s, %(color_id)s)", host='1.1.1.99', color_id=3 ) # 执行SQL cur = engine.execute('select * from hosts') # 获取第一行数据 cur.fetchone() # 获取第n行数据 cur.fetchmany(3) # 获取所有数据 cur.fetchall()
12 上述内容总结
12.1 基于SQLALchemy实现数据库的增删改查;
12.2 单表操作;
12.3 多表操作;
13 SQLAlchemy创建表结构
13.1 使用SQLAlchemy;
- 安装 pip3 install sqlalchemy pymysql
14 SQLAlchemy实现基本增删改查(一)
14.1 基于SQLAlchemy实现基本的创建数据表操作;
增加;
#!/usr/bin/python3 # -*- coding:utf-8 -*- # Project: SQLALchemy # Software: PyCharm # Time : 2018-09-22 15:14 # File : 2.单表的增加操作.py # Author : 天晴天朗 # Email : [email protected] import models from sqlalchemy.orm import sessionmaker from sqlalchemy import create_engine engine = create_engine("mysql+pymysql://fda!fda%*)@mysql.dfa.com:3306/flask_session?charset=utf8") xxxx = sessionmaker(bind=engine) session = xxxx() # 单条记录增加 # obj = models.Classes(name = "全栈1期") # session.add(obj) # 多条记录增加; objs = [ # models.Classes(name = '全栈2期'), models.Classes(name='全栈3期'), models.Classes(name='全栈4期'), models.Classes(name='全栈5期'), ] session.add_all(objs) session.commit() session.close()
查询;
#!/usr/bin/python3 # -*- coding:utf-8 -*- # Project: SQLALchemy # Software: PyCharm # Time : 2018-09-22 15:29 # File : 3.单表的查询操作.py # Author : 天晴天朗 # Email : [email protected] from sqlalchemy.orm import sessionmaker from sqlalchemy import create_engine import models engine = create_engine("mysql+pymysql://fdafda!@%*)@fa.fda.com:3306/flask_session?charset=utf8") maker = sessionmaker(bind=engine) session = maker() # 查询; result = session.query(models.Classes).all() # print(result)#[, for item in result: print(item.id, item.name) session.commit() session.close(), , , ]
删除;
#!/usr/bin/python3 # -*- coding:utf-8 -*- # Project: SQLALchemy # Software: PyCharm # Time : 2018-09-22 15:33 # File : 4.单表的删除操作.py # Author : 天晴天朗 # Email : [email protected] from sqlalchemy.orm import sessionmaker from sqlalchemy import create_engine import models engine = create_engine("mysql+pymysql://ffdfdaf!@%*)@fda.cuifdasxiaozhao.com:3306/flask_session?charset=utf8") maker = sessionmaker(engine) session = maker() # 删除 result = session.query(models.Classes).filter(models.Classes.id > 13).delete() session.commit() session.close()
修改;
#!/usr/bin/python3 # -*- coding:utf-8 -*- # Project: SQLALchemy # Software: PyCharm # Time : 2018-09-22 15:38 # File : 5.单表的修改操作.py # Author : 天晴天朗 # Email : [email protected] from sqlalchemy.orm import sessionmaker from sqlalchemy import create_engine import models engine = create_engine("mysql+pymysql://root:Tfdasfda1!@%*)@123.45.67.89:3306/flask_session?charset=utf8") maker = sessionmaker(engine) session = maker() # 更新操作;˚ session.query(models.Classes).filter(models.Classes.id > 0).update({models.Classes.name: models.Classes.name + "999"}, synchronize_session=False) # 尾部的参数决定了是进行字符串操作还是数学运算操作; session.commit() session.close()
15 SQLAlchemy实现基本增删改查(二)
#!/usr/bin/python3 # -*- coding:utf-8 -*- # Project: SQLALchemy # Software: PyCharm # Time : 2018-09-22 15:38 # File : 5.单表的修改操作.py # Author : 天晴天朗 # Email : [email protected] from sqlalchemy.orm import sessionmaker from sqlalchemy import create_engine import models engine = create_engine("mysql+pymysql://root:Tqtl911!@%*)@mysql.cuixiaozhao.com:3306/flask_session?charset=utf8") maker = sessionmaker(engine) session = maker() # 更新操作;˚ session.query(models.Classes).filter(models.Classes.id > 0).update({models.Classes.name: models.Classes.name + "999"}, synchronize_session=False) # 尾部的参数决定了是进行字符串操作还是数学运算操作; session.commit() session.close()
16 SQLAlchemy小练习
16.1 小练习;
#!/usr/bin/python3 # -*- coding:utf-8 -*- # Project: SQLALchemy # Software: PyCharm # Time : 2018-09-22 16:15 # File : 7.练习.py # Author : 天晴天朗 # Email : [email protected] from sqlalchemy.orm import sessionmaker from sqlalchemy import create_engine, text import models engine = create_engine("mysql+pymysql://root:Tqtl911!@%*)@mysql.cuixiaozhao.com:3306/flask_session?charset=utf8") maker = sessionmaker(bind=engine) session = maker() obj = models.Student(username='崔晓丝', password='123456', class_id=2) session.add(obj) # 在学生表中找到崔晓丝; obj1 = session.query(models.Student).filter(models.Student.username == '崔晓丝').first() print(obj1) ## 找到所有学生; # 1、LOW B查询方式; # objs = session.query(models.Student).all() # for obj in objs: # cls_obj = session.query(models.Classes).filter(models.Classes.id ==obj.class_id).first() # print(obj.id,obj.username,obj.class_id,cls_obj.name) # 2、主动连表操作; objs = session.query(models.Student.id, models.Student.username, models.Classes.name).join(models.Classes, isouter=True).all() print(objs) # 3、relationship引入; objs2 = session.query(models.Student).all() for item in objs2: print(item.id,item.username,item.class_id,item.cls.name) session.commit() session.close() # 4、全栈2期所有的学生 obj3 = session.query(models.Classes).filter(models.Classes.name =="全栈2期999").first() student_list = obj3.stus for i in student_list: print(i.id,i.username) print("全栈2期所有的学生",student_list)
17 SQLAlchemy常见操作
17.1 SQLAlchemy常见操作;
- 分组
- 连表
- 组合
- 条件
- 通配符
- 限制
# 条件 ret = session.query(Users).filter_by(name='alex').all() ret = session.query(Users).filter(Users.id > 1, Users.name == 'eric').all() ret = session.query(Users).filter(Users.id.between(1, 3), Users.name == 'eric').all() ret = session.query(Users).filter(Users.id.in_([1,3,4])).all() ret = session.query(Users).filter(~Users.id.in_([1,3,4])).all() ret = session.query(Users).filter(Users.id.in_(session.query(Users.id).filter_by(name='eric'))).all() from sqlalchemy import and_, or_ ret = session.query(Users).filter(and_(Users.id > 3, Users.name == 'eric')).all() ret = session.query(Users).filter(or_(Users.id < 2, Users.name == 'eric')).all() ret = session.query(Users).filter( or_( Users.id < 2, and_(Users.name == 'eric', Users.id > 3), Users.extra != "" )).all() # 通配符 ret = session.query(Users).filter(Users.name.like('e%')).all() ret = session.query(Users).filter(~Users.name.like('e%')).all() # 限制 ret = session.query(Users)[1:2] # 排序 ret = session.query(Users).order_by(Users.name.desc()).all() ret = session.query(Users).order_by(Users.name.desc(), Users.id.asc()).all() # 分组 from sqlalchemy.sql import func ret = session.query(Users).group_by(Users.extra).all() ret = session.query( func.max(Users.id), func.sum(Users.id), func.min(Users.id)).group_by(Users.name).all() ret = session.query( func.max(Users.id), func.sum(Users.id), func.min(Users.id)).group_by(Users.name).having(func.min(Users.id) >2).all() # 连表 ret = session.query(Users, Favor).filter(Users.id == Favor.nid).all() ret = session.query(Person).join(Favor).all() ret = session.query(Person).join(Favor, isouter=True).all() # 组合 q1 = session.query(Users.name).filter(Users.id > 2) q2 = session.query(Favor.caption).filter(Favor.nid < 2) ret = q1.union(q2).all() q1 = session.query(Users.name).filter(Users.id > 2) q2 = session.query(Favor.caption).filter(Favor.nid < 2) ret = q1.union_all(q2).all() 常用操作
18 上述内容总结
18.1 表操作;
18.2 数据进行操作;
#!/usr/bin/python3 # -*- coding:utf-8 -*- # Project: SQLALchemy # Software: PyCharm # Time : 2018-09-22 19:10 # File : 1.总结.py # Author : 天晴天朗 # Email : [email protected] import models from sqlalchemy.orm import sessionmaker from sqlalchemy import create_engine engine = create_engine("mysql+pymysql://root:Tqtl911!@%*)@mysql.cuixiaozhao.com:3306/flask_session?charset=utf8") xxxx = sessionmaker(bind=engine) session = xxxx() session.add session.add_all() session.query(Users).all() session.query(Users.id, Users.name).filter(User.name == 'alex') session.query(Users.id, Users.name).filter_by(name='alex') session.query(Users.id, Users.name).filter_by(name='alex').filter() session.query(Users.id, Users.name).filter(User.name == 'alex').update({}, 字符串) session.query(Users.id, Users.name).filter(User.name == 'alex').update({}, 计算) session.query(Users.id, Users.name).filter(Users.name == 'alex').delete()
19 homework
第6章 章节六
01 内容概要
1.1 WTForms验证流程
1.2 SQLAlchemy下的lrelationship以及子查询;
02 内容回顾
2.1 315++面试题准备;
2.2 谈谈你对Python和其他语言的区别?
2.3 为什么要学习Python?
2.4 基本的数据类型-字符串、字典、元组、列表、集合、collections
2.5 函数:
-函数的参数传递的是什么?
-def func(a,b=[]):pass
-lambda 表达式
-列表生成式
-生成器表达式
-常见的内置函数:map、reduce、filter、zip、instance、type
2.6 回顾;
2.6.1 WTForms作用?
2.6.2 WTForms涉及到的作用点?哪里用到了?
- metaclass
- 封装:UnboundField
- _new__
- __mro__
- setattr
- type(...)
2.6.3 ORM和原生SQL比较?
2.6.4 你用过的ORM框架有哪些?Django ORM SQLAlchemy,所有的语言都有ORM;
2.6.5 DBFirst、CodeFIrst;
2.6.6 SQLAlchemy自带数据库连接池;
03 WTforms组件验证流程
04 SQLAlchemy操作补充
4.1 relationship帮助我们做跨表操作-增加和查询;
4.2 子查询;
05 homework
5.1 SQLAlchemy中设置表:引擎、编码;
5.2 Django中的DBFirst示例;
5.3 在Flask程序中应用SQLAlchemy;
第7章 章节七
01 内容概要
1.1 Flask内容扫尾-Flask目录创建;
1.2 Flask-script;
1.3 flask-sqlalchemy;
1.4 flask-migrate;
1.5 flask自定义组件;
1.6 其他-多app应用;
1.7 离线脚本&信号(blinker,相当于埋点,需要的时候触发执行即可);
02 内容回顾
2.1 谈谈你对Python和其他语言的区别?
2.1.1 编译型和解释性的区别;
2.1.2 解释型:Python、PHP
2.1.3 编译型:C 、C++
2.1.4 混合型:Java
2.2 为什么要学习Python?
2.2.1 简单易学;
2.2.2 生态圈比较强大;
2.2.3 发展趋势比较好,人工智能、数据分析;
2.2.4 还有很多...
2.3 Python中的数据类型?
- 字符串
- 字典
- 元组
- 列表
- 集合
- collections
2.4 函数
- 函数参数传递的是什么?
- def func(a,b=[]):pass
- lambda 表达式
- 列表生成式
- 生成器表达式(for i in range(1))
-
常见内置函数-map reduce filter zip instance type
2.5 生成器、迭代器、装饰器以及可迭代对象
- 迭代器-主要体现__next__方法;
- 生成器,迭代器的一种,一个函数存在yield关键字,生成器函数,函数执行,才是生成器,场景:range|xrange,redis取值,stark组件;
- 可迭代对象,一个类的内部实现__iter__方法且返回一个迭代器;WTForms中对form对象进行循环时候,显示form中包含的所有字段;列表、字典、元组;
- 装饰器,在不改变原函数代码的基础上,在执行前后进行定制操作;flask路由系统,csrf_token,Django内置的登录;flask_before_request,Django的缓存;
03 Flask-script组件
3.1 flask-script的作用;
- python manage.py runserver
- python manage.py 自定义命令
#!/usr/bin/python3 # -*- coding:utf-8 -*- # Project: FullFlask # Software: PyCharm # Time : 2018-09-23 15:51 # File : manage.py # Author : 天晴天朗 # Email : [email protected] from FullFlask import create_app from flask_script import Manager app = create_app() manager = Manager(app) @manager.command def custom(arg): print(arg) @manager.option('-n', '--name', dest='name') @manager.option('-u', '--url', dest='url') def cmd(name, url): """ 自定义命令: 执行:python manage.py cmd -n cuixiaozhao -u http://cuixiaozhao.com 执行:python manage.py cmd --name cuixiaozhao --url http://cuixiaozhao.com :param name: :param url: :return: """ print(name, url) if __name__ == '__main__': # app.run() manager.run()
04 FLask-SQLAlchemy组件应用(一)
4.1 基于SQLAlchemy进行查询数据;
4.2 Flask项目目录结构如下;
#!/usr/bin/python3 # -*- coding:utf-8 -*- # Project: FullFlask # Software: PyCharm # Time : 2018-09-23 15:54 # File : accounts.py # Author : 天晴天朗 # Email : [email protected] from flask import blueprints from FullFlask import models ac = blueprints.Blueprint('ac', __name__) @ac.route('/login', methods=['GET', 'POST']) def login(): from sqlalchemy.orm import sessionmaker from sqlalchemy import create_engine engine = create_engine("mysql+pymysql://root:Tqtl911!@%*)@mysql.cuixiaozhao.com:3306/FullFlask?charset=utf8") maker = sessionmaker(bind=engine) session = maker() result = session.query(models.Users).all() session.close() print( result) # [, return 'Login it.', , ]
05 Flask-SQLAlchemy组件应用(二)
5.1 SQLAlchemy组件应用二;
#!/usr/bin/python3 # -*- coding:utf-8 -*- # Project: FullFlask # Software: PyCharm # Time : 2018-09-23 16:37 # File : settings.py # Author : 天晴天朗 # Email : [email protected] class BaseConfig(object): SQLALCHEMY_DATABASE_URI = "mysql+pymysql://root:Tqtl911!@%*)@mysql.cuixiaozhao.com:3306/FullFlask?charset=utf8" SQLALCHEMY_POOL_SIZE = 5 SQLALCHEMY_POOL_TIMEOUT = 30 SQLALCHEMY_POOL_RECYCLE = -1 # 追踪对象的修改并且发送信号; SQLALCHEMY_TRACK_MODIFICATIONS = False class ProductionConfig(BaseConfig): pass class DevelopmentConfig(BaseConfig): pass class TestConfig(BaseConfig): pass """ 小结: 1、flask-sqlalchemy的作用:将SQLAlchemy相关的所有功能都封装到db=flask_sqlalchemy.SQLAlchemy()对象中; -创建表; class Users( ): pass -操作表; db.session """
06 Flask-SQLAlchemy组件应用(三)
6.1 pip3 install flask-sqlalchemy安装;
6.2 离线脚本的使用;
#!/usr/bin/python3 # -*- coding:utf-8 -*- # Project: FullFlask # Software: PyCharm # Time : 2018-09-23 17:08 # File : drop_table.py # Author : 天晴天朗 # Email : [email protected] "" """ 1、Web运行时候,flask程序运行起来,用户通过浏览器访问; 2、离线脚本,即自定义的一个py文件+使用flask中定义好的功能; """ from FullFlask import db from FullFlask import create_app from FullFlask import models app = create_app() with app.app_context(): # db.drop_all() # db.create_all() data = db.session.query(models.Users).all() print(data)
07 Flask-SQLAlchemy组件应用总结
7.1 在__init__.py文件中创建db对象;
7.2 在__init__.py中的create_app函数中让将app传入到app中;
7.3 写配置文件,将连接字符串定义在配置文件中;
7.4 定义models.py文件,导入第一步的db;
7.5 创建数据库表,编写离线脚本:drop_table.py;
7.6 在视图函数中,使用SQLAlchemy操作数据库;
08 SQLAlchemy创建session的两种方式
8.1 两种创建session的方式;
- 基于scopted_sessionn进行session = scopted_session(maker)创建
- 基于传统方式创建;
- PS:flask-session默认使用scopted_session创建,不再担心多线程问题;
09 Flask-Migrate组件
9.1 flask-migrate:做数据库迁移,依赖如下包:
- flask-script
- flask-sqlalchemy
9.2 生成数据库迁移命令;
- python manage.py db init
- python manage.py db migrate
- python manage.py db upgrade
10 Flask自定义拓展
11 Flask多app应用
11.1 Flask的多app应用;
本质就是对URL的分发和处理;
#!/usr/bin/python3 # -*- coding:utf-8 -*- # Project: FullFlask # Software: PyCharm # Time : 2018-09-23 21:32 # File : 多app应用.py # Author : 天晴天朗 # Email : [email protected] from flask import Flask from werkzeug.wsgi import DispatcherMiddleware from werkzeug.serving import run_simple app01 = Flask('app01') app02 = Flask('app02') dm = DispatcherMiddleware(app01, { '/app02': app02, }) if __name__ == '__main__': run_simple('localhost', 5000, dm)
12 Flask信号blinker
12.1 汽车赛道举例;
12.2 pip3 install blinker# 安装信号;
12.3 常见信号;
# Core signals. For usage examples grep the source code or consult # the API documentation in docs/api.rst as well as docs/signals.rst template_rendered = _signals.signal('template-rendered') before_render_template = _signals.signal('before-render-template') request_started = _signals.signal('request-started') request_finished = _signals.signal('request-finished') request_tearing_down = _signals.signal('request-tearing-down') got_request_exception = _signals.signal('got-request-exception') appcontext_tearing_down = _signals.signal('appcontext-tearing-down') appcontext_pushed = _signals.signal('appcontext-pushed') appcontext_popped = _signals.signal('appcontext-popped') message_flashed = _signals.signal('message-flashed')
12.4 flask_signals.py;
#!/usr/bin/python3 # -*- coding:utf-8 -*- # Project: FullFlask # Software: PyCharm # Time : 2018-09-23 21:48 # File : Flask-signal.py # Author : 天晴天朗 # Email : [email protected] from flask import Flask, signals app = Flask(__name__) def func1(*args, **kwargs): print('触发信号:request_started') def func2(*args, **kwargs): print('触发信号:request_started') signals.request_started.connect(func1) signals.appcontext_pushed.connect(func2) @app.route('/login') def login(): return 'Login' if __name__ == '__main__': app.run()
13 Flask信号和before_request的区别
13.1 brefore_request,可以控制请求是否可以继续往后执行;
13.2 信号,在原来的基础增加额外的操作和值;
14 内容总结和作业
14.1 Flask写完了,如何使用Flask做出个项目;
14.2 代码发布系统,比如RabbitMQ、saltstack、Celery;
14.3 面试相关:
14.3.1 手写Flask内置HelloWorld!
14.3.2 Flask和其他框架的区别?
14.3.3 Flask内置组件:
- 配置
- 路由
- 视图
- 模板
- session
- 闪现
- 蓝图
- 中间件
- 特殊装饰器
14.3.4 Flask第三方组件:
- flask-session——默认session放在签名的cookie中,使用Redis存储session信息;
- flask-SQLAlchemy;
- flask-migrate;
- flask-script;
- flask-....还有很多!
- blinker
14.3.5 公共组件:
- WTForms
- DBUtils
- SQLAlchemy
14.3.6 自定义Flask组件:
- auth,参考flask-login组件
14.3.7 上下文管理机制:
- 为什么使用LocalStack对Local对象进行操作?目的是要将Local中的值;
14.3.8 Flask项目目录维护;