1、flask-sqlalchemy安装

pip install flask_sqlalchemy

2、SQLAlchemy连接数据库

from sqlalchemy import create_engine

HOSTNAME = '127.0.0.1'
PORT = '3306'
DATABASE = 'flask_study'
USERNAME = 'root'
PASSWORD = 'tian'

# dialect+driver://username:password@host:port/database
DB_URI = "mysql+pymysql://{username}:{password}@{host}:{port}/{db}?charset=utf8".format(username=USERNAME,
                                                                                        password=PASSWORD,
                                                                                        host=HOSTNAME, port=PORT,
                                                                                        db=DATABASE)

engine = create_engine(DB_URI) #使用create_engine创建一个引擎,然后再调用这个引擎的connect()方法
conn = engine.connect()

3、定义ORM模型并映射到数据库

ORM:对象关系映射

创建一个ORM模型,这个ORM模型必须继承自sqlalchemy给我们提供好的基类
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base

engine = create_engine(DB_URI) #连接数据库

Base = declarative_base(engine) #继承flask提供的基类

#  必须继承自sqlalchemy给我们提供好的基类
class User(Base):
    __tablename__ = 'User'
    name = Column(String(50), nullable=True)
    age = Column(Integer)
    id = Column(Integer, primary_key=True, nullable=False)



#  将创建好的ORM模型,映射到数据库中。
Base.metadata.create_all()

4、SQLAlchemy对数据的增删改查

①用session做数据的增删改查操作

所有和数据库的ORM操作都必须通过一个叫做`session`的会话对象来实现,通过以下代码来获取会话对象

from sqlalchemy.orm import sessionmaker

    engine = create_engine(DB_URI)
    session = sessionmaker(engine)()

②增:

obj = User(name='tian', age=18)
session.add(obj)
session.commit()

③删:

obj = session.query(User).first()
session.delete(obj)
session.commit()

④改:

obj = session.query(User).first()
obj.name='mingbo'
session.commit()

⑤查:

obj = session.query(User).first()
print(obj)

5、SQLAlchemy常见数据类型

1. Integer:整形,映射到数据库中是int类型。
2. Float:浮点类型,映射到数据库中是float类型。他占据的32位。
3. Double:双精度浮点类型,映射到数据库中是double类型,占据64位。
4. String:可变字符类型,映射到数据库中是varchar类型.
5. Boolean:布尔类型,映射到数据库中的是tinyint类型。
6. DECIMAL:定点类型。是专门为了解决浮点类型精度丢失的问题的。这个类型使用的时候需要传递两个参
数,第一个参数是用来标记这个字段总能能存储多少个数字,第二个参数表示小数点后有多少位。
7. Enum:枚举类型。指定某个字段只能是枚举中指定的几个值,不能为其他值。在ORM模型中,使用Enum来作为枚举
8. Date:存储时间,只能存储年月日。映射到数据库中是date类型。在Python代码中,可以使用`datetime.date`来指定。
9. DateTime:存储时间,可以存储年月日时分秒毫秒等。映射到数据库中也是datetime类型。
在Python代码中,可以使用`datetime.datetime`来指定。
10. Time:存储时间,可以存储时分秒。映射到数据库中也是time类型。在Python代码中,可以使用`datetime.time`来至此那个。
11. Text:存储长字符串。一般可以存储6W多个字符。如果超出了这个范围,可以使用LONGTEXT类型。映射到数据库中就是text类型。
12. LONGTEXT:长文本类型,映射到数据库中是longtext类型。

6、Column常用参数

  1.  primary_key:设置某个字段为主键。
  2.  autoincrement:设置这个字段为自动增长的。
  3.  default:设置某个字段的默认值。在发表时间这些字段上面经常用。
  4.  nullable:指定某个字段是否为空。默认值是True,就是可以为空。
  5.  unique:指定某个字段的值是否唯一。默认是False。
  6.  onupdate:在数据更新的时候会调用这个参数指定的值或者函数。在第一次插入这条数据的时候,不会用onupdate的值,只会使用default的值。常用的就是`update_time`(每次更新数据的时候都要更新的值)。
  7. name:指定ORM模型中某个属性映射到表中的字段名。如果不指定,那么会使用这个属性的名字来作为字段名。如果指定       了,就会使用指定的这个值作为参数。这个参数也可以当作位置参数,在第1个参数来指定。

7、query可用参数:

  1.  func.count:统计行的数量。
  2.  func.avg:求平均值。
  3. func.max:求最大值。
  4. func.min:求最小值。
  5. func.sum:求和。

只要mysql中有的聚合函数,都可以通过func调用。

示例:

from sqlalchemy import func
result = session.query(func.max(Article.price)).first()

8、filter过滤:

1. equals:

obj = session.query(User).filter(User.name=='mingbo').first()
print(obj)

2. not equals:

obj = session.query(User).filter(User.name!='mingbo').all()

3. like:

query.filter(User.name.like('%ed%'))

4. in:

query.filter(User.name.in_(['ed','wendy','jack']))
    # 同时,in也可以作用于一个Query
    query.filter(User.name.in_(session.query(User.name).filter(User.name.like('%ed%'))))

5. not in:

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

6.  is null:

query.filter(User.name==None)
    # 或者是
    query.filter(User.name.is_(None))

7. is not null:

query.filter(User.name != None)
    # 或者是
    query.filter(User.name.isnot(None))

8. and:

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

9. or:

from sqlalchemy import or_  
query.filter(or_(User.name=='ed',User.name=='wendy'))

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

9、外键及其四种约束讲解:

外键约束有以下几项:
1. RESTRICT:父表数据被删除,会阻止删除。默认就是这一项。
2. NO ACTION:在MySQL中,同RESTRICT。
3.  CASCADE:级联删除。
4.  SET NULL:父表数据被删除,子表数据会设置为NULL。

10、外键关系

个人觉得,比Django的ORM查询好用许多。

SQLAlchemy提供了一个relationship,这个类可以定义属性,以后在访问相关联的表的时候就直接可以通过属性访问的方式就可以访问得到。

①一对多

作者和文章有一对多的关系。

class User(Base):
    __tablename__ = 'user'
    id = Column(Integer, primary_key=True, autoincrement=True)
    username = Column(String(50), nullable=False)

    # articles = relationship("Article")

    def __repr__(self):
        return "<User(username:%s)>" % self.username


class Article(Base):
    __tablename__ = 'article'
    id = Column(Integer, primary_key=True, autoincrement=True)
    title = Column(String(50), nullable=False)
    content = Column(Text, nullable=False)
    uid = Column(Integer, ForeignKey("user.id"))

    author = relationship("User", backref="articles", uselist=False)  # backref只需在一个表里写就行,反向引用,

    def __repr__(self):
        return "<Article(title:%s,content:%s)>" % (self.title, self.content)

查询某个作者的文章题目:
 

use_obj=session.query(User).first()
for article in use_obj.articles:   
    #articles是backref的值
    print(article.title)

查询某篇文章的作者:

article_obj=session.query(Article).first()
print(article_obj.author.username)

②一对一

把一张表中不常用的字段放到另一张表。是一对一的关系。

在sqlalchemy中,如果想要将两个模型映射成一对一的关系,那么应该在父模型中,指定引用的时候,要传递一个`uselist=False`这个参数进去。就是告诉父模型,以后引用这个从模型的时候,不再是一个列表了,而是一个对象了。

作者和作者详情是一对一的关系:
 

class User(Base):
    __tablename__ = 'user'
    id = Column(Integer,primary_key=True,autoincrement=True)
    username = Column(String(50),nullable=False)

    # extend = relationship("UserExtend",uselist=False)

    def __repr__(self):
        return "<User(username:%s)>" % self.username

class UserExtend(Base):
    __tablename__ = 'user_extend'
    id = Column(Integer, primary_key=True, autoincrement=True)
    school = Column(String(50))
    uid = Column(Integer,ForeignKey("user.id"))

    user = relationship("User",backref=backref("extend",uselist=False))

③多对多

1. 先把两个需要做多对多的模型定义出来 2. 使用Table定义一个中间表,中间表一般就是包含两个模型的外键字段就可以了,并且让他们两个来作为一个“复合主键”。 3. 在两个需要做多对多的模型中随便选择一个模型,定义一个relationship属性,来绑定三者之间的关系,在使用relationship的时候,需要传入一个secondary=中间表。

文章和标签是多对多的关系:
 

from sqlalchemy import Table
from sqlalchemy.orm import sessionmaker.relationship,backref

article_tag = Table(
    "article_tag",  # 表名
    Base.metadata,  #
    Column("article_id", Integer, ForeignKey("article.id"), primary_key=True),  # 列名,类型,外键映射,作为主键(唯一)
    Column("tag_id", Integer, ForeignKey("tag.id"), primary_key=True)
)


class Article(Base):
    __tablename__ = 'article'
    id = Column(Integer, primary_key=True, autoincrement=True)
    title = Column(String(50), nullable=False)

    # tags = relationship("Tag",backref="articles",secondary=article_tag)

    def __repr__(self):
        return "<Article(title:%s)>" % self.title


class Tag(Base):
    __tablename__ = 'tag'
    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String(50), nullable=False)

    articles = relationship("Article", backref="tags", secondary=article_tag)  # secondary指向第三张表。
#Article是关联表,,backref是Article表用来查Tag表时用到的。

    def __repr__(self):
        return "<Tag(name:%s)>" % self.name

①查询一篇文章的标签

article_obj = session.query(Article).first()
for i in article_obj.tags:
    print(i.id,i.name)

②查询某个标签有哪些文章

tag_obj = session.query(Tag).first()
for i in tag_obj.articles:
    print(i.id,i.title)

总得来说,SQLAlchemy的数据库查询比Django的数据库查询方便了许多,对正向和反向的查询很容易实现。