Flask数据库

文章目录

一、ORM

1.1 什么是ORM

ORM 全拼Object-Relation Mapping. 称为对象-关系映射主要实现模型对象到关系数据库数据的映射.比如:把数据库表中每条记录映射为一个模型对象

Flask数据库

; 1.2 ORM的优缺点有哪些?

优点 :

  • 对数据库的操作都转化成对类,属性和方法的操作.

  • 不用编写各种数据库的sql语句.

  • 不在关注,使用的是mysql、oracle…等数据库

缺点 :
相比较直接使用SQL语句操作数据库,有性能损失.

1.3 Flask-SQLAlchemy安装及设置

  • SQLALchemy 实际上是对数据库的抽象,让开发者不用直接和 SQL 语句打交道,而是通过 Python 对象来操作数据库,在舍弃一些性能开销的同时,换来的是开发效率的较大提升
  • SQLAlchemy是一个关系型数据库框架,它提供了高层的 ORM 和底层的原生数据库的操作。flask-sqlalchemy 是一个简化了 SQLAlchemy 操作的flask扩展。
    文档地址:

安装

pip install flask-sqlalchemy

如果连接的是 mysql 数据库,需要安装 flask-mysqldb或者pymysql
pymysql 是在 Python3.x 版本中用于连接 MySQL 服务器的一个库,Python2中则使mysqldb。

pip install flask-mysqldb

如果flask-mysqldb安装不上,安装, pip install pymysql

数据库连接设置
设置数据库的链接地址,追踪信息
格式: mysql://<用户名>:<密码>@:<端口>/&#x6570;&#x636E;&#x5E93;&#x540D;<!--端口--><!--密码--><!--用户名-->
如果安装pymysql ,需要这样连接数据库

mysql+pymysql://<用户名>:<密码>@:<端口>/&#x6570;&#x636E;&#x5E93;&#x540D;<!--端口--><!--密码--><!--用户名-->

数据库链接地址
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:mysql@127.0.0.1:3306/test'
动态追踪修改设置,如未设置只会提示警告
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True

若要查看映射的sql语句,设置: app.config['SQLALCHEMY_ECHO'] = True
配置完成需要去 MySQL 中创建项目所使用的数据库

 mysql -uroot -pmysql
 create database test charset utf8;
"""
操作流程:

- 1.安装扩展
  - pip install flask_sqlalchemy
  - pip install flask_mysqldb / pymysql
- 2.设置数据库的配置信息
- 3.创建sqlalchemy对象db,关联app
- 4.编写模型类,字段,继承自db.Model,
- 5.操作数据库
  - 增删改
  - 查询
"""
from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)

2.设置数据库的配置信息
设置数据库的链接信息,
app.config["SQLALCHEMY_DATABASE_URI"] = "mysql://tom:123456@10.0.0.130:3306/test"
该字段增加了大量的开销,会被禁用,建议设置为False
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False

3.创建sqlalchemy对象db,关联app
db = SQLAlchemy(app)

4.编写模型类,字段,继承自db.Model,才能被映射
class Student(db.Model):
    # 如果不指定表名称,默认就是类名的小写,需要自己指定,需要如下
    __tablename__ = "students"
    # 主键, 参数1: 表示id的类型, 参数2: 表示id的约束类型
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(32))

@app.route('/')
def hello_world():
    return "helloworld"

if __name__ == '__main__':
    # 删除继承自db.Model的表
    db.drop_all()

    # 5.创建数据库的表,创建的是继承自db.Model的表
    db.create_all()

    app.run(debug=True)

mysql> show tables
    -> ;
+----------------+
| Tables_in_test |
+----------------+
| students       |
+----------------+
1 row in set (0.00 sec)

mysql> desc students;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| id    | int(11)     | NO   | PRI | NULL    | auto_increment |
| name  | varchar(32) | YES  |     | NULL    |                |
+-------+-------------+------+-----+---------+----------------+

1.4 其他配置信息

Flask数据库
连接不同类型数据库参考
bind操作多数据库

; 1.5 常用的SQLAlchemy字段类型

Flask数据库

1.6常用的SQLAlchemy列选项

Flask数据库

; 常用的SQLAlchemy关系选项

Flask数据库
与mysql数据类型对应关系:
Flask数据库

二、数据库基本操作

在Flask-SQLAlchemy中,插入、修改、删除操作,均由数据库会话管理。
会话用 db.session 表示。在准备把数据写入数据库前,要先将数据添加到会话中然后调用 db.session.commit() 方法提交会话。

在 Flask-SQLAlchemy 中,查询操作是通过 query 对象操作数据。
最基本的查询是返回表中所有数据,可以通过过滤器进行更精确的数据库查询。

2.1 数据库增删改

"""
增删改

- 全部都是使用db.session操作
- 常见方法:
  - db.session.add(obj) 添加单个对象
  - db.session.add_all([obj1,obj2]) 添加多个对象
  - db.session.delete(obj) 删除单个对象
  - db.session.commit() 提交会话
  - db.drop_all() 删除继承自db.Model所有表
  - db.create_all() 创建继承自db.Model的所有表
  - 其他:
    - db.session.rollback() 回滚
    - db.session.remove() 移除会话
  - 案例: 编写两个模型类, 一个角色模型类,  还有一个用户模型类
    - 关系: 一对多
"""

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)

1.设置数据库的配置信息
app.config["SQLALCHEMY_DATABASE_URI"] = "mysql+pymysql://tom:123456@10.0.0.130:3306/test"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False

2.创建SQLalchemy对象,关联app
db = SQLAlchemy(app)

3.编写模型类
角色(一方)
class Role(db.Model):
    __tablename__ = "roles"
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(32))

    # 如果一个类继承自object那么重写__str__方法即可, 如果是继承自db.Model那么需要重写__repr__方法
    def __repr__(self):
        return "" % self.name

用户(多方)
class User(db.Model):
    __tablename__ = "users"
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(32))

    # 建立外键
    role_id = db.Column(db.Integer, db.ForeignKey(Role.id))

    # 如果一个类继承自object那么重写__str__方法即可修改对象的默认输出, 如果是继承自db.Model那么需要重写__repr__方法
    def __repr__(self):
        return "" % self.name

@app.route('/')
def hello_world():
    return "helloworld"

if __name__ == '__main__':
    # 先删除表,后创建
    db.drop_all()
    db.create_all()

    app.run(debug=True)
mysql> desc roles;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| id    | int(11)     | NO   | PRI | NULL    | auto_increment |
| name  | varchar(32) | YES  |     | NULL    |                |
+-------+-------------+------+-----+---------+----------------+

mysql> desc users;
+---------+-------------+------+-----+---------+----------------+
| Field   | Type        | Null | Key | Default | Extra          |
+---------+-------------+------+-----+---------+----------------+
| id      | int(11)     | NO   | PRI | NULL    | auto_increment |
| name    | varchar(32) | YES  |     | NULL    |                |
| role_id | int(11)     | YES  | MUL | NULL    |                |
+---------+-------------+------+-----+---------+----------------+

具体操作:


In [1]: from demo02role_user import *

In [2]: role=Role(name="admin")

In [3]: role2=Role(name="ops")

In [5]: db.session.add_all([role,role2])

In [6]: db.session.commit()

mysql> select * from roles;
+----+-------+
| id | name  |
+----+-------+
|  1 | admin |
|  2 | ops   |
+----+-------+

In [7]: user1=User(name="laowang",role_id=role.id)

In [8]: user2=User(name="laozhang",role_id=role2.id)

In [9]: db.session.add_all([user1,user2])

In [10]: db.session.commit()
mysql> select * from users;
+----+----------+---------+
| id | name     | role_id |
+----+----------+---------+
|  1 | laowang  |       1 |
|  2 | laozhang |       2 |
+----+----------+---------+
2 rows in set (0.00 sec)

In [11]: user2.name
Out[11]: 'laozhang'

In [12]: user2.name="laowu" # 改

In [13]: db.session.commit()

mysql> select * from users;
+----+---------+---------+
| id | name    | role_id |
+----+---------+---------+
|  1 | laowang |       1 |
|  2 | laowu   |       2 |
+----+---------+---------+
2 rows in set (0.00 sec)

In [14]: db.session.delete(user2) #删

In [15]: db.session.commit()
mysql> select * from users;
+----+---------+---------+
| id | name    | role_id |
+----+---------+---------+
|  1 | laowang |       1 |
+----+---------+---------+

2.2 添加数据

realtionship描述了Role和User的关系。
第一个参数为对应参照的类”User”
第二个参数backref为类User,反向引用属性
第三个参数lazy决定了什么时候SQLALchemy从数据库中加载数据
如果设置为子查询方式(subquery),则会在加载完Role对象后,就立即加载与其关联的对象,这样会让总查询数量减少,但如果返回的条目数量很多,就会比较慢
设置为 subquery 的话,role.users 返回所有数据列表
另外,也可以设置为动态方式(dynamic),这样关联对象会在被使用的时候再进行加载,并且在返回前进行过滤,如果返回的对象数很多,或者未来会变得很多,那最好采用这种方式

"""
查询
relationship 属性方便关联查询,通常写在一方,并且不会在数据库产生响应的字段
"""

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)

1.设置数据库的配置信息
app.config["SQLALCHEMY_DATABASE_URI"] = "mysql+pymysql://tom:123456@10.0.0.130:3306/test"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
app.config["SQLALCHEMY_ECHO"] = True

2.创建SQLalchemy对象,关联app
db = SQLAlchemy(app)

3.编写模型类
角色(一方)
class Role(db.Model):
    __tablename__ = "roles"
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(32))

    # 给role添加了一个users属性, 那么查询的方式是, role.users
    # 给user添加了一个role属性, 那么查询的方式是, user.role
    users = db.relationship("User", backref="role", lazy="dynamic")

    # 如果一个类继承自object那么重写__str__方法即可, 如果是继承自db.Model那么需要重写__repr__方法
    def __repr__(self):
        return "" % self.name

用户(多方)
class User(db.Model):
    __tablename__ = "users"
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(32))
    email = db.Column(db.String(32))
    password = db.Column(db.String(32))

    # 建立外键
    role_id = db.Column(db.Integer, db.ForeignKey(Role.id))

    # 如果一个类继承自object那么重写__str__方法即可, 如果是继承自db.Model那么需要重写__repr__方法
    def __repr__(self):
        return "" % (self.id, self.name, self.email, self.password)

@app.route('/')
def hello_world():
    return "helloworld"

if __name__ == '__main__':
    # 为了演示方便,先删除表,后创建
    db.drop_all()
    db.create_all()

    # 创建测试数据
    ro1 = Role(name='admin')
    db.session.add(ro1)
    db.session.commit()

    # 再次插入一条数据
    ro2 = Role(name='user')
    db.session.add(ro2)
    db.session.commit()

    # 多条用户数据
    us1 = User(name='wang', email='wang@163.com', password='123456', role_id=ro1.id)
    us2 = User(name='zhang', email='zhang@189.com', password='201512', role_id=ro2.id)
    us3 = User(name='chen', email='chen@126.com', password='987654', role_id=ro2.id)
    us4 = User(name='zhou', email='zhou@163.com', password='456789', role_id=ro1.id)
    us5 = User(name='tang', email='tang@itheima.com', password='158104', role_id=ro2.id)
    us6 = User(name='wu', email='wu@gmail.com', password='5623514', role_id=ro2.id)
    us7 = User(name='qian', email='qian@gmail.com', password='1543567', role_id=ro1.id)
    us8 = User(name='liu', email='liu@itheima.com', password='867322', role_id=ro1.id)
    us9 = User(name='li', email='li@163.com', password='4526342', role_id=ro2.id)
    us10 = User(name='sun', email='sun@163.com', password='235523', role_id=ro2.id)
    db.session.add_all([us1, us2, us3, us4, us5, us6, us7, us8, us9, us10])
    db.session.commit()

    app.run(debug=True)

SQLAlchemy查询过滤器

用来过滤数据,返回查询的结果集

Flask数据库

; SQLAlchemy查询执行器

用来执行结果集,得到具体数据

Flask数据库
总结:
Flask数据库

查:

数据库增加,删除,修改操作:
增加:
user = User(name='laowang')
db.session.add(user)
db.session.commit()

修改:
user.name = 'xiaohua'
db.session.commit()

删除:
db.session.delete(user)
db.session.commit()

以下12条查询语句:
特点:
模型.query: 得到了所有模型的数据的结果集对象
模型.query.过滤器: 过滤出了想要的数据,还是一个查询结果集对象
模型.query.过滤器.执行器: 取出了结果集中的内容

查询所有用户数据
User.query.all() ==> [user1,user2]

查询有多少个用户
User.query.count()

查询第1个用户
User.query.first()

查询id为4的用户[3种方式]
User.query.get(4) (这里面只能是数字 或 '4') 查询不到不会报错
User.query.filter_by(id = 4).first() (一个等号)查询不到不会报错
User.query.filter(User.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(User.name != 'wang').all()
或者
from sqlalchemy import not_
User.query.filter(not_(User.name == 'wang')).all()

查询名字和邮箱都以 li 开头的所有数据[2种方式]
from sqlalchemy import and_
User.query.filter(User.name.startswith('li'),User.email.startswith('li')).all()
User.query.filter(and_(User.name.startswith('li'),User.email.startswith('li'))).all()

查询password是 123456 或者 emailcom 结尾的所有数据
from sqlalchemy import or_
User.query.filter(or_(User.password == '123456',User.email.endswith('com'))).all()

查询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 = Role.query.filter(Role.id == user.role_id).first()

查询所有用户数据,并以邮箱排序
User.query.order_by(User.email).all()
User.query.order_by(User.email.desc()).all() # 升序

每页3个,查询第2页的数据
paginate = User.query.paginate(page, per_page,Error_out)
paginate = User.query.paginate(2,3,False)
page: 哪一个页
per_page: 每页多少条数据
Error_out: False 查不到不报错

paginate .pages: 共有多少页
paginate .items: 当前页数的所有对象
paginate .page: 当前第几页

限制查询2条数据
User.query.limit(2).all()

sqlalchemy查询常见的过滤方式
filter过滤条件:
过滤是数据提取的一个很重要的功能,以下对一些常用的过滤条件进行解释,并且这些过滤条件都是只能通过filter方法实现的:
1. equals : ==
    news= session.query(News).filter(News.title == "title1").first()
    query里面是列查询,字段,传入模型名表示全字段 。
    filter是行查询,没有filter表示全表查询
2. not equals  :  !=
    query(User).filter(User.name != 'ed')

3. like[不区分大小写]  & ilike[区分大小写]:
    query(User).filter(User.name.like('%ed%··'))
 query(User).filter(User.name.like('__ed%__')) _表示站位符

4. in:
    query(User).filter(User.name.in_(['ed','wendy','jack']))

5. not in:
    query(User).filter(~User.name.in_(['ed','wendy','jack']))

6.  is null:
    query(User).filter(User.name==None)
    # 或者是
    query(User).filter(User.name.is_(None))

7. is not null:
    query(User).filter(User.name != None)
    # 或者是
    query(User).filter(User.name.isnot(None))

8. and:
    query(User).filter(and_(User.name=='ed',User.fullname=='Ed Jones'))
    # 或者是传递多个参数
    query(User).filter(User.name=='ed',User.fullname=='Ed Jones')
    # 或者是通过多次filter操作
    query(User).filter(User.name=='ed').filter(User.fullname=='Ed Jones')

9. or:
    query(User).filter(or_(User.name=='ed',User.name=='wendy'))

如果想要查看orm底层转换的sql语句,可以在filter方法后面不要再执行任何方法直接打印就可以看到了。比如:
        news = session.query(News).filter(or_(News.title=='abc',News.content=='abc'))
        print(news)

数据库查询之relationship属性

* 解释: 为了方便数据库的关联查询
* 特点:
  * 1.不会在数据库产生实体字段
  * 2.关系属性,需要在一方添加
  * 3.外键是添加在多方的, 并且关系属性的使用,需要依赖于外键

* 需求:
  * 1.如果知道了角色的情况下,能否快速查询出,哪些用户扮演了该角色

    * 原始查询方法:
      * role = Role.query.get(1)
      * users = User.query.filter(User.role_id == role.id).all()

    * 快速查询:
      * 使用relationship添加关系属性,就可以快速查询了.

      * 格式:在一方添加
        * users = db.relationship("多方的模型类")

      * 使用格式:
        * role = Role.query.get(1)
        * users = role.users

反向查询backref属性

* 解释:如果知道了用户的情况下,能否快速查询出,哪些该用户扮演了哪个角色
- 原始查询方法:
  - user = User.query.get(1)
  - role = Role.querye.filter(Role.id == user.role_id).first()
- 快速查询:
  - 使用backref添加反向属性,就可以快速查询了
  - 格式:
    - users = db.relationship("多方的模型类",backref="role")
  - 快速查询:
    - user = User.query.get(1)
    - role = user.role

懒加载技术lazy

* 解释: 一旦使用了relationship,backref,那么系统会自动做子查询
  * 默认子查询(subquery): 查询出了一方, 就会自动的将关联的一方查询出来,会影响系统性能
  * 要设置为动态查询(dynamic): 只有用到了才去查询
* lazy使用
  * db.relationship("多方的模型类",backref="role",lazy="dynamic")

user.role.all()

Original: https://blog.csdn.net/m0_46090675/article/details/120982657
Author: 万wu皆可爱
Title: Flask数据库

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/746514/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球