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.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-zd$@$!%*?&]{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项目目录维护;

原文地址:https://www.cnblogs.com/tqtl911/p/9686998.html