FlaskWeb開發從入門到放棄(二)

第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.htmlhtml

問題一: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類中
        二、視圖函數中,經過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})


# 二、類由自定義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)
"""
一、類由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


"""
小結:
一、默認類由type實例化建立;
二、某個類指定metaclass = MyType,那麼當前類的全部派生類都因爲MyType建立;
三、實例化對象:
    -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);html5

當有了對應關係後,再也不須要編寫SQL語句,取而代之是操做:類、對象;python

8.2 ORM和原生SQL的優缺點?

  8.2.1 ORM;mysql

  • 快速開發
  • 性能差

  8.2.2 SQL;web

  • 性能好
  • 開發速度慢

  8.2.3 DB First(已經使用原生SQL開發,根據數據庫的表生成類);面試

  8.2.4 Code First(ORM是CodeFirst,根據類建立數據表);redis

  • python3 manage.py inspect

  8.2.5 ORM是如何實現的?內置解析器實現;經過對象和類轉化成字符換;sql

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
""
"""
一、安裝pip3 install sqlalchemy ;
二、依賴於pymysql進行數據庫鏈接;
三、並不支持修改表結構,僅支持在數據庫修改字段後,再從新在此處修改;
"""
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>

# 找到全部學生;
# 一、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)
# 二、主動連表操做;
objs = session.query(models.Student.id, models.Student.username, models.Classes.name).join(models.Classes,                                                                                        isouter=True).all()
print(objs)

# 三、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()


# 四、全棧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 函數:

-函數的參數傳遞的是什麼?django

-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


"""
小結:
一、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
""
"""
一、Web運行時候,flask程序運行起來,用戶經過瀏覽器訪問;
二、離線腳本,即自定義的一個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項目目錄維護;

相關文章
相關標籤/搜索