python_flask_ORM

 

ORM (Object-Relation Mapping) 对象-关系映射.

主要实现模型对象到关系数据库数据的映射.

优缺点:

  • 优点:
    • 只需要面向对象编程,不需要使用sql语言
    • 实现数据模型和数据库的解藕,及不用关心是什么数据库,更改简单配置即可更换数据库。
  • 缺点
    • 有部分性能损耗

1、flask_sqllalchemy的基本配置

  • 安装:pip install flask_sqlalchemy
    • 如果链接mysql数据库需要按张mysqldb:pip install flask_mysql
  • 基本配置
    • 配置链接数据库
      # 链接mysql数据库:mysql://用户名:密码@ip地址:端口/库
      app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:[email protected]:3306/test'
    • 其他配置
      # 动态追踪修改设置,如未设置只会提示警告
      app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
      #查询时会显示原始SQL语句
      app.config['SQLALCHEMY_ECHO'] = True
    • 配置完成后需要去mysql中创建所需的库
    • 其他配置
    • 链接其他数据库
      # Postgres
      postgresql://scott:tiger@localhost/mydatabase
      
      # Oracle
       oracle://scott:[email protected]:1521/sidname
      
      # SQlite(注意开头是四个"/" )
      sqlite:////absolute/path/to/foo.db
  • 常用的SQLAlchemy字段类型
类型名 python中类型 说明
Integer int 普通整数,一般是32位
SmallInteger int 取值范围小的整数,一般是16位
BigInteger int或long 不限制精度的整数
Float float 浮点数
Numeric decimal.Decimal 普通整数,一般是32位
String str 变长字符串
Text str 变长字符串,对较长或不限长度的字符串做了优化
Unicode unicode 变长Unicode字符串
UnicodeText unicode 变长Unicode字符串,对较长或不限长度的字符串做了优化
Boolean bool 布尔值
Date datetime.date 时间
Time datetime.datetime 日期和时间
LargeBinary str 二进制文件
  • 常用的SQLAlchemy列选项
选项名 说明
primary_key 如果为True,代表表的主键
unique 如果为True,代表这列不允许出现重复的值
index 如果为True,为这列创建索引,提高查询效率
nullable 如果为True,允许有空值,如果为False,不允许有空值
default 为这列定义默认值
  • 常用的SQLAlchemy关系选项
选项名 说明
backref 在关系的另一模型中添加反向引用
primary join 明确指定两个模型之间使用的联结条件
uselist 如果为False,不使用列表,而使用标量值
order_by 指定关系中记录的排序方式
secondary 指定多对多关系中关系表的名字
secondary join 在SQLAlchemy中无法自行决定时,指定多对多关系中的二级联结条件
  • 配置变量 
    from flask import Flask
    from flask_sqlalchemy import SQLAlchemy
    
    
    app = Flask(__name__)
    
    # 设置连接数据库的URL
    app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:[email protected]:3306/test'
    
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
    # 查询时会显示原始SQL语句
    app.config['SQLALCHEMY_ECHO'] = True
    实例化链接
    db = SQLAlchemy(app)
  • 简单定义
class User(db.Model):
    # 定义表明(不定义用的是模型对象名的小写)
    __tablename__ = 'users'
    # 定义列对象
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True, index=True)
    
  • 一对多模型
    class Role(db.Model):
        #关键代码
        us = db.relationship('User', backref='role', lazy='dynamic')
    
    
    class User(db.Model):
    
        role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))
    
    """
    其中realtionship描述了Role和User的关系。在此文中,第一个参数为对应参照的类"User"
    第二个参数backref为类User申明新属性的方法
    第三个参数lazy决定了什么时候SQLALchemy从数据库中加载数据
    如果设置为子查询方式(subquery),则会在加载完Role对象后,就立即加载与其关联的对象,这样会让总查询数量减少,但如果返回的条目数量很多,就会比较慢
    设置为 subquery 的话,role.users 返回所有数据列表
    另外,也可以设置为动态方式(dynamic),这样关联对象会在被使用的时候再进行加载,并且在返回前进行过滤,如果返回的对象数很多,或者未来会变得很多,那最好采用这种方式
    设置为 dynamic 的话,role.users 返回查询对象,并没有
    """
  • 多对多模型
    tb_student_course = db.Table(
        'tb_student_course',
         db.Column('student_id', db.Integer, db.ForeignKey('students.id')),
         db.Column('course_id', db.Integer, db.ForeignKey('courses.id'))
                                 )
    
    class Student(db.Model):
        __tablename__ = "students"
        id = db.Column(db.Integer, primary_key=True)
        name = db.Column(db.String(64), unique=True)
    
        courses = db.relationship('Course', secondary=tb_student_course,
                                  backref=db.backref('students', lazy='dynamic'),
                                  lazy='dynamic')
    
    class Course(db.Model):
        __tablename__ = "courses"
        id = db.Column(db.Integer, primary_key=True)
        name = db.Column(db.String(64), unique=True)
    
    
    """
    多对多通过第三方表 tb_student_course 建立链接,表内只有两个外键分别指向多对多的两个表的ID(主键)
    """
  • 自关联模型
    • 自关联一对多(适用于省市区三级联动,评论的父评论和子评论的关系)
      class Comment(db.Model):
          """评论"""
          __tablename__ = "comments"
      
          id = db.Column(db.Integer, primary_key=True)
          # 评论内容
          content = db.Column(db.Text, nullable=False)
          # 父评论id
          parent_id = db.Column(db.Integer, db.ForeignKey("comments.id"))
          # 父评论(也是评论模型)
          parent = db.relationship("Comment", remote_side=[id],
                                   backref=db.backref('childs', lazy='dynamic'))
      
    • 自关联的多对多(用户之间的关注信息)
      tb_user_follows = db.Table(
          "tb_user_follows",
          db.Column('follower_id', db.Integer, db.ForeignKey('info_user.id'), primary_key=True),  # 粉丝id
          db.Column('followed_id', db.Integer, db.ForeignKey('info_user.id'), primary_key=True)  # 被关注人的id
      )
      
      class User(db.Model):
          """用户表"""
          __tablename__ = "info_user"
      
          id = db.Column(db.Integer, primary_key=True)  
          name = db.Column(db.String(32), unique=True, nullable=False)
          # 用户所有的粉丝,添加了反向引用followed,代表用户都关注了哪些人
          followers = db.relationship('User',
                                      secondary=tb_user_follows,
                                      primaryjoin=id == tb_user_follows.c.followed_id,
                                      secondaryjoin=id == tb_user_follows.c.follower_id,
                                      backref=db.backref('followed', lazy='dynamic'),
                                      lazy='dynamic')
      
      
      """
      通过类似普通多对多的第三方表来维护自关联的多对多关系
      多对多通常使用第三方表来维护关系
      """

常用的SQLAlchemy查询过滤器

过滤器 说明
filter() 把过滤器添加到原查询上,返回一个新查询
filter_by() 把等值过滤器添加到原查询上,返回一个新查询
limit 使用指定的值限定原查询返回的结果
offset() 偏移原查询返回的结果,返回一个新查询
order_by() 根据指定条件对原查询结果进行排序,返回一个新查询
group_by() 根据指定条件对原查询结果进行分组,返回一个新查询

常用的SQLAlchemy查询执行器

方法 说明
all() 以列表形式返回查询的所有结果
first() 返回查询的第一个结果,如果未查到,返回None
first_or_404() 返回查询的第一个结果,如果未查到,返回404
get() 返回指定主键对应的行,如不存在,返回None
get_or_404() 返回指定主键对应的行,如不存在,返回404
count() 返回查询结果的数量
paginate() 返回一个Paginate对象,它包含指定范围内的结果

基本操作

插入

  • # 创建模型类对象
    ro1 = Role(name='admin')
    # 执行add添加命令
    db.session.add(ro1)
    # 如果是多条数据(多个用于提交的模型类对象)可使用add_all提交列表数据
    # db.session.add_all([us1,us2,us3,us4,us5,us6,us7,us8,us9,us10])
    # 提交到数据库(未提交数据库不发生改变)
    db.session.commit()

查询

  • filter_by精确查询
    # 查询name是wang的所有对象
    User.query.filter_by(name='wang').all()
  • frist返回第一个对象
    # 查询name是wang的第一个对象
    User.query.filter_by(name='wang').first()
  • all返回查询到所有对象(返回一个查询集合)
    # 查询name是wang的所有对象
    User.query.filter_by(name='wang').all()
  • filter模糊查询
    # 查询name结尾是‘g’的所有数据
    User.query.filter(User.name.endswith('g')).all()
  • get查询主键
    # 查询主键ID为 1 的对象
    User.query.get(1)
  • 逻辑非查询
    # 返回name不是‘wang’的所有用户
    User.query.filter(User.name!='wang').all()
  • 逻辑与,需要导入and
    # 查询所有name是wang的并且emali以‘163.com’结尾的用户
    from sqlalchemy import and_
    User.query.filter(and_(User.name!='wang',User.email.endswith('163.com'))).all()
  • 逻辑或,需要导入or_
    # 查询所有name是wang或者emali以‘163.com’结尾的用户
    from sqlalchemy import or_
    User.query.filter(or_(User.name!='wang',User.email.endswith('163.com'))).all()
  • not_取反操作
    # name是chen的都不要,及取name是‘chen’的反
    from sqlalchemy import not_
    User.query.filter(not_(User.name=='chen')).all()

一般查询操作总汇(包括其他部分查询)

 """
    查询所有用户数据
        User.query.all()
    查询有多少个用户
        User.query.count()
    查询第1个用户
        User.query.first()
    查询id为4的用户[3种方式]
        User.query.get(4)
        User.query.filter(User.id == 4).first()
        User.query.filter_by(id=4).first()
    查询名字结尾字符为g的所有数据[开始/包含]
        User.query.filter(User.name.endswith('g')).all()
        User.query.filter(User.name.startswith('g')).all()
        User.query.filter(User.name.contains('g')).all()
    查询名字不等于wang的所有数据[2种方式]
        User.query.filter(not_(Usme == 'wang')).all()
        User.query.filter(User.name != 'er.nawang').all()
    查询名字和邮箱都以 li 开头的所有数据[2种方式]
        User.query.filter(and_(User.name.startswith("li"), User.email.startswith("li"))).all()
        User.query.filter(User.name.startswith("li"), User.email.startswith("li")).all()
    查询password是 `123456` 或者 `email` 以 `itheima.com` 结尾的所有数据
        [User: 1 wang, User: 5 tang, User: 8 liu]
    查询id为 [1, 3, 5, 7, 9] 的用户列表
        User.query.filter(User.id.in_([1,3,5,7,9])).all()
    查询name为liu的角色数据
        user = User.query.filter(User.name == "liu").first()
        Role.query.get(user.role_id)
    查询所有用户数据,并以邮箱排序
        User.query.order_by(User.email).all()
        User.query.order_by(User.email.desc()).all()  倒序
    每页3个,查询第2页的数据
        User.query.paginate(2, 3, False).items
    """

 

错误之处欢迎指出

猜你喜欢

转载自blog.csdn.net/jlb1024/article/details/81515155
今日推荐