WEB后端服务-Flask第四天

WEB后端服务-Flask第四天

一、 ORM设计思想

相对于数据库的操作,设计DAO结构的目的是简化数据库的操作,把SQL语句封装到基础类(BasDao)中,但是要求开发人员必须特别熟悉SQL语句和Python的基础。自己设计Dao的优点有效防止SQL注入风险。通过使用ORM避免不会SQL的开发人员能够快速操作数据库,ORM的思想将实体类(Model或Entries)和数据库表直接建立关联关系,即类->表, 类对象->表中的记录,类对象的属性->表的字段。

ORM ( Object Relationshap Mapping)对象关系映射。

  • 类和表
  • 类实例即是表的记录
  • 类属性即为表的字段

当ORM关系映射成功之后,直接操作类或对象,即操作数据库中表或记录。

简单地实现ORM( 自省+元类 ):

class User():
     id = 100
     name = 20
     money = 20000
     
def save(entity):
    sql = "insert into %s(%s) values(%s)"
    table= entity.__class__.__name__.lower()
    colnames = ','.join([col for col in entity.__dict__])
    colplaceholders = ','.join([ "%%(%s)s" % col for col in entity.__dict__])

    sql = sql % (table, colnames, colplaceholders)
    print(sql)
    
u = User()
u.id = 1900
u.name = 'disen'
u.money = 20000
save(u)

二、Flask-SQLAlchemy插件

2.1 安装

pip install flask-sqlalchemy -i https://mirrors.aliyun.com/pypi/simple

2.2 配置

在settings.Dev类进行配置

# 数据库连接的路径 dialect+driver://user:password@ip:port/db?charset=utf8
SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://root:root@10.36.174.19:3306/bank'
SQLALCHEMY_TRACK_MODIFICATIONS = True  # 可扩展
SQLALCHEMY_COMMIT_ON_TEARDOWN = True  # 回收资源时自动提交事务
SQLALCHEMY_ECHO = True  # 显示调试SQL

2.3 创建SQLAlchemy实例并初始化

创建 models模块,在它的"__init__.py"脚本中创建

from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()

在创建Flask对象app的脚本中,初始化SQLAlchemy类对象。

from models import db
...

db.init_app(app) # 初始化应用环境

2.4 实战项目

  1. 将银行系统下的所有表创建相应的模型类

    1.1 声明用户的模型类 UserEntity, 继承 db.Model 父类

    # 默认情况下: 类名即为表名
    class User(db.Model):
         # 声明字段(属性), 默认情况下属性名与字段相同
        id = db.Column(db.Integer, primary_key=True, autoincrement=True)
        number = db.Column(db.String(18), unique=True)
        name = db.Column(db.String(20), nullable=False )
        phone = db.Column(db.String(20))
        password = db.Column(db.String(100), nullable=False )
    

    1.2 声明银行模型

    class Back(db.Model):
        id = db.Column(db.Integer, primary_key=True, autoincrement=True)
        name = db.Column(db.String(50), unique=True)
        address = db.Column(db.String(200), nullable=False)
    

    1.3 声明银行卡模型

    class Card(db.Model):
        id = db.Column(db.Integer, primary_key=True, autoincrement=True)
        number = db.Column(db.String(20), unique=True)
        money = db.Column(db.Float(2), default=0, server_default='0')
        passwd = db.Column(db.String(100))
    
        user_id = db.Column(db.Integer)
        back_id = db.Column(db.Integer)
    
        @property
        def username(self):
            return User.query.get(self.user_id).name
    
        @property
        def bankname(self):
            return Back.query.get(self.back_id).name
    

    注意: server_default的属性值是字符串类型。

    1.4 声明交易模型

  2. 更新所有查询列表页面

    2.1 在用户的list2路由的处理函数中使用User模型类

    from models import User
    data = {
        'users':  User.query.all(),
        'session': session
    }
    

    User.query.all() 从数据库中查询所有的用户信息。

中午默写

  1. 简述模板中过滤器的作用

    针对数据进行处理,如格式化、提取、替换、反转等相关的数据处理。

    flask的过滤器都定义在 jinja2.filters.py。

    自定义过滤器, 定义一个函数,使用@app.template_filter(‘过滤器名称’) 装饰。函数的第一个参数是转换数据的value, 第二个及之后参数,是根据功能或需求传入的。

  2. 简述{% include %} 和 {% extends % } 的区别

    include 导入整个静态网页,不能进行修改其中的某个块区内容

    extends 继承父页面,是整个网页, 某个块区的内容是可以修改, 使用 {% block %}.

  3. 简述"点"语法包含哪些

    对象.属性

    字典.key

    列表.索引下标, 如 {{ cates.0 }}

三、SQLAlchemy的CURD

3.1 模型新增数据(Create)

app.app_context().push()
user = User()
user.name = '刘晓莺2'
user.phone = '18619018876'
user.number = '19190191929298821'
user.password = crypt.pwd('9999')

db.session.add(user)
db.session.commit()  # 提交事务
user = User(name='蒋李龙',
            number='1019192929111',
            phone='111122099',
            password=crypt.pwd('112029001'))

db.session.add(user)
db.session.commit()  # 提交事务

3.2 模型更新数据(Update)

app.app_context().push()
user = User.query.get(72)
print(user)

user.phone = '121'
user.name = '高新医院'

# db.session.add(user)
db.session.commit()  # 自动检查数据是否发生变化

3.3 模型删除数据(Delete)

 def test_delete(self):
    app.app_context().push()
    db.session.delete(User.query.get(79))
    db.session.commit()

3.4 模型查询数据(Read)

# 查询所有姓名中包含"李"字的用户
for u in User.query.filter(User.name.contains('李')):
    print(u)
# 查询所有"李"姓的用户
for u in User.query.filter(User.name.startswith('李')):
    print(u)
for u in User.query.filter(User.name == '李成'):
    print(u)
# 从查询结果中读取一条记录
u = User.query.filter(User.number == '88888888888').one()
print(u)
filter = User.query.filter(User.name == "李成",
                            User.password == crypt.pwd("000000"))
try:
    login_user = filter.one()
    print(login_user)
except:
    print('账号或口令错误')

crypt.pwd()函数的定义如下:

import hashlib


def pwd(txt, hash_name='md5'):
    # 重命名的快捷键: Fn+Shift+F6
    hash_ = hashlib.md5() if hash_name == 'md5' else hashlib.sha1()
    hash_.update(txt.encode('utf-8'))
    return hash_.hexdigest()
 # 查询编号不于10的,或者是银行名包含"业"字
for bank in Back.query.filter(db.or_(
    Back.id >= 10,
    Back.name.like('%业%')
)):
    print(bank.id, bank.name, bank.address)
 # 查询非"西安"的银行
for bank in Back.query.filter(db.not_(Back.name.contains('西安'))):
    print(bank.id, bank.name, bank.address)
app.app_context().push()
# __ge__() 相当于 >=
for card in Card.query.filter(Card.money.__ge__(5000)):
    print(card.number, card.money)
3.4.1 session的查询

query()方法中指定是查询的字段信息, filter()指定是条件

db.session.query(User.name, User.phone).filter(User.name.like('%i%')).all()
db.session.query(User.number, user.phone).first() # 查看第一条

针对query()查询结果集可以使用first()也可以使用all()及get(id)

针对filter()查询结果集可以使用one() 、all()

3.4.2 模型类的查询

模型类可以直接发起查询, 默认情况查询模型下的所有字段。

User.query.filter(name='disen')
# User.query(User.name, User.phone).all() # 模型的query是不能被调用的
3.4.3 模型字段查询条件
== 等值查询
!= 不相等
>=  或 __ge___ ()大于等于
<= 或 __le__ ()小于等于
in_((1,)) 包含
like() 模糊匹配
startswith() 字符串开头匹配
endswith() 字符串结尾匹配
contains() 字符串包含匹配
3.4.4 排序与分页

排序: order_by(), 可以在query和filter之后可以使用order_by。

# 按身份证号排序
# 先按姓名排序,姓名相同时,再按身份证号排序
# 默认按升序 ASC-> asc(), 可以指定降序 DESC-> desc()
for u in User.query.order_by(User.name, User.number.desc()).all():
    print(u.number, u.name, u.phone)
print('------------梁------------------')
for u in User.query \
        .filter(User.name.startswith('梁')) \
        .order_by(User.phone.desc()).all():
    print(u.name, u.phone, u.number)
# 查询银行卡的余额,按余额的降序方式排序
for card in db.session.query(Card)\
        .order_by(Card.money.desc())\
        .all():
    print(card.number, card.money)

分页: offset(), limit()

如果分页函数与ordery_by组合使用时,必须放在order_by之后。分页函数可以用在query和filter之后。

# 查询18 或 15开头手机号的用户信息
# 先按手机号排序, 再分页
query_set = User.query.filter(db.or_(
    User.phone.startswith('18'),
    User.phone.startswith('15')
)).order_by(User.phone);


for u in self.page_data(query_set, page=3).all():
    print(u.name, u.phone)
def page_data(self, query_set, page_size=5, page=1):
    total = query_set.count()
    pages = total // page_size + (1 if total % page_size >0 else 0)
    print('总条数:%s, 每页显示 %s 条, 总页数:  %s ' % (total, page_size, pages))

    if page > pages:
        page = pages
    elif page <= 0:
        page = 1
    print('-------显示第 %s 页--------' % page)
    return query_set.offset((page-1)*page_size).limit(page_size)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值