第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 : tqtl@tqtl.org # 創建類的兩種方式; # 方式一: 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 : tqtl@tqtl.org "" """ 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 : tqtl@tqtl.org "" """ 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://<user>:<password>@<host>[:<port>]/<dbname> pymysql mysql+pymysql://<username>:<password>@<host>/<dbname>[?<options>] MySQL-Connector mysql+mysqlconnector://<user>:<password>@<host>[:<port>]/<dbname> 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 : tqtl@tqtl.org 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 : tqtl@tqtl.org 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 : tqtl@tqtl.org 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)#[<models.Classes object at 0x10dcb2358>, <models.Classes object at 0x10dcb23c8>, <models.Classes object at 0x10dcb2438>, <models.Classes object at 0x10dcb24a8>, <models.Classes object at 0x10dcb2518>] 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 : tqtl@tqtl.org 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 : tqtl@tqtl.org 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 : tqtl@tqtl.org 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 : tqtl@tqtl.org 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) # <models.Student object at 0x108762a90> # 找到所有學生; # 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 : tqtl@tqtl.org 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 : tqtl@tqtl.org 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 : tqtl@tqtl.org 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) # [<FullFlask.models.Users object at 0x106123c88>, <FullFlask.models.Users object at 0x106123dd8>, <FullFlask.models.Users object at 0x106123a90>, <FullFlask.models.Users object at 0x1061239e8>] 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 : tqtl@tqtl.org 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 : tqtl@tqtl.org "" """ 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 : tqtl@tqtl.org 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 : tqtl@tqtl.org 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項目目錄維護;