SQLAlchemy 简单用法

安装SQLAlchemy

pip install sqlalchemy

使用 SQLAlchemy

1. 创建连接

engine = create_engine(r'sqlite:///C:\test.db')

2. 声明映射

from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Integer, Column, String
from sqlalchemy.orm import relationship

Base = declarative_base()

class User(Base):
    # 定义表明
    __tablename__ = 'users'

    id = Column(Integer, autoincrement=True, primary_key=True, nullable=False)
    name = Column(String, doc="姓名", comment="姓名")
    fullname = Column(String, doc="全名", comment="全名")
    nickname = Column(String, doc="暱称", comment="暱称")
    addresses = relationship("Address", back_populates="user")

3. 创建会话
创建会话时直接绑定engine

Session = sessionmaker(bind=engine)

如果暂时没有定义 Engine,也可以先设置
Session = sessionmaker(),稍后,当使用 create_engine()定义了Engine后 ,使用 configure():

Session.configure(bind=engine)  # once engine is available

4. 声明实例

session = Session()

5. 创建表

# 创建所有不存在的表
Base.metadata.create_all(engine)

# 创建单个表
User.__table__.create(engine, checkfirst=True)

# 创建多个表(在list中添加表明)
table_objects = [User.__table__]  # 通过Model.__table__的方式添加
table_objects = [Base.metadata.tables["users"]]  #  直接通过定义的表明添加
Base.metadata.create_all(engine, tables=table_objects)

6. 添加和更新对象
添加对象

# 创建实例
session = Session()
# 添加单个用户
new_user = User(name='jack', fullname='Jack Bean', nickname='gjffdd')
session.add(new_user)  #  只add时,数据未提交到数据库
session.commit()  #  只有commit后才提交到数据库,在数据看到

# 添加多个用户
session.add_all([
    User(name='wendy', fullname='Wendy Williams', nickname='windy'),
    User(name='mary', fullname='Mary Contrary', nickname='mary'),
    User(name='fred', fullname='Fred Flintstone', nickname='freddy')])
session.flush()	 # 必须手动flush
session.commit()

# 批量插入ORM版
session.bulk_save_objects([User(name='wendy', fullname='Wendy Williams', nickname='windy') for i in xrange(1000)])
# 批量插入非ORM版
result = session.execute(
     User.__table__.insert(),
     [{'name': 'wang', 'age': 10}, {}] )
     
# 只add未提交前可进行回滚
session.rollback()

更新对象

user = session.query(User).filter_by(name='jack').first()
user.name = "test update"
session.commit()
print(user.name)  #  test update

7.删除

result = session.query(User).filter_by(name='jack').delete()
# 删成功返回1,否则0
session.commit()

8.查询

result = session.query(User).filter(User.name.like('%ed')).order_by(User.id)

  • all() 返回所有查询的结果(一个列表) result.all()
  • first() 返回第一个结果result.first()
  • [] 直接根据索引取 result[:]

查询规则

# get(8) 查询id为8的用户信息
session.query(User).get(8)
# distinct() 与 SQL 的 distinct 语句行为一致
query(User).filter(User.name == "test").distinct(User.id).all()
# limit() 限制返回的记录条数
query(User).filter(User.id == 3).limit(3).all()
# count() 
session.query(User).filter(User.name.like('%ed')).count()
# order_by 
#.order_by(字段) # 正序 
#.order_by(-字段) # 倒序
#.order_by(desc('字段'))  # 倒序
#.order_by('字段')  # 正序
from sqlalchemy import desc, asc
query(User).order_by(-User.id)
query(User).order_by(desc(User.id))
query(User).order_by(asc(User.id))
query(User).order_by(User.id.desc())
query(User).order_by(User.id.asc())

# 等
query.filter(User.name == 'ed')
# 不等
query.filter(User.name != 'ed')
# like
query.filter(User.name.like('%ed%'))
# ilike不区分大小写
query.filter(User.name.ilike('%ed%'))
# in
query.filter(User.name.in_(['ed', 'wendy', 'jack']))
 query.filter(User.name.in_(
     session.query(User.name).filter(User.name.like('%ed%'))
 ))
# not in
query.filter(~User.name.in_(['ed', 'wendy', 'jack']))
# is null
query.filter(User.name == None)
query.filter(User.name.is_(None))
# is not null
query.filter(User.name != None)
query.filter(User.name.isnot(None))
# and
# use and_()
from sqlalchemy import and_
query.filter(and_(User.name == 'ed', User.fullname == 'Ed Jones'))
# or send multiple expressions to .filter()
query.filter(User.name == 'ed', User.fullname == 'Ed Jones')
# or chain multiple filter()/filter_by() calls
query.filter(User.name == 'ed').filter(User.fullname == 'Ed Jones')
# or
from sqlalchemy import or_
query.filter(or_(User.name == 'ed', User.name == 'wendy'))
# match
query.filter(User.name.match('wendy'))

9. 直接执行SQL

engine = create_engine(r'sqlite:///C:\test_new.db')
connection = engine.connect()
cursor = connection.execute("select * from users")
print(cursor.fetchall())

10. 输入、输出json化
需要在定义model时,自定义一个to_json的方法

class User(Base):
    __tablename__ = 'users'

    id = Column(Integer, autoincrement=True, primary_key=True, nullable=False)
    name = Column(String, doc="姓名", comment="姓名")
    fullname = Column(String, doc="全名", comment="全名")
    nickname = Column(String, doc="暱称", comment="暱称")
    
    def from_json(self, **kwargs):
        """更新数据以json格式的数据"""
        _dict = self.__dict__
        for key in kwargs:
            if key in _dict:
                setattr(self, key, kwargs[key])
                
    def to_json(self):
        """返回json格式的数据"""
        _dict = self.__dict__
        if "_sa_instance_state" in _dict:
            del _dict["_sa_instance_state"]
        return _dict
    
    # 第二种
    def to_dict(self):
        return {c.name: getattr(self, c.name, None)
                for c in self.__table__.columns}    
                
    # 第三种方法
    # def to_json(self):
    #     return {
    #             "id": self.id, 
    #             "name": self.name,
    #             "fullname": self.fullname,
    #             "nickname": self.nickname
    #              }
    
# 单个数据       
user = session.query(User).filter_by(name='jack').first()
print(user.to_json())
# 数据集
users = session.query(User).filter_by(name='jack').all()
print([i.to_json() for i in users])

# 更新name为Jack的数据
users = session.query(User).filter_by(name='jack').all()
update_data = {"name": "test json","fullname": "123", "nickname": "456"}
users.from_json(**update_data)
session.commit()

11.多对多关联

from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Integer, Column, String, ForeignKey, Table
from sqlalchemy.orm import sessionmaker
from sqlalchemy.orm import relationship

# 创建连接
engine = create_engine(r'sqlite:///C:\test_relationship.db')
# 声明映射
Base = declarative_base()
# 创建会话
Session = sessionmaker(bind=engine)


# 多对多
registrations = Table(
    'sc', Base.metadata,
    Column('student_id', Integer, ForeignKey('students.id')),
    Column('course_id', Integer, ForeignKey('courses.id'))
)


class Student(Base):
    __tablename__ = 'students'
    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String)
    courses = relationship('Course',
                              secondary=registrations,
                              backref="students",
                              lazy='dynamic')
    
    def to_dict(self):
        return {c.name: getattr(self, c.name, None)
                for c in self.__table__.columns}


class Course(Base):
    __tablename__ = 'courses'
    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String)
    
    def to_dict(self):
        return {c.name: getattr(self, c.name, None)
                for c in self.__table__.columns}


student = Student(**{"name": "小明"})
student1 = Student(**{"name": "小红"})
student2 = Student(**{"name": "小青"})
student3 = Student(**{"name": "小白"})

course1 = Course(**{"name": "数学"})
course2 = Course(**{"name": "英语"})
course3 = Course(**{"name": "语文"})


# 创建所有不存在的表
Base.metadata.create_all(engine)
session = Session()

# student.courses.append(course3)   # 将关联数据插入关联的表中
# student3.courses.append(course2)
# student1.courses.append(course3)  # 将关联数据插入关联的表中
# session.add_all([course1,course2,course3,student,student1,student2,student3])
# session.commit()


results = session.query(Student).filter(Student.id == 10).first()
print(results.courses[0].to_dict())
print(results.courses.all())

12. 例子

from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Integer, Column, String
from sqlalchemy.orm import sessionmaker

# 创建连接
engine = create_engine(r'sqlite:///C:\test_new.db')
# 声明映射
Base = declarative_base()
# 创建会话
Session = sessionmaker(bind=engine)


class Book(Base):
    __tablename__ = 'books'

    id = Column(Integer, autoincrement=True, primary_key=True, nullable=False)
    name = Column(String, doc="书名", comment="书名")
    category_id = Column(Integer, nullable=False)

    def to_json(self):
        """返回json格式的数据"""
        _dict = self.__dict__
        if "_sa_instance_state" in _dict:
            del _dict["_sa_instance_state"]
        return _dict

    def to_dict(self):
        return {c.name: getattr(self, c.name, None)
                for c in self.__table__.columns}


class Category(Base):
    __tablename__ = "categories"
    id = Column(Integer, autoincrement=True, primary_key=True, nullable=False)
    name = Column(String, doc="分类", comment="分类")

    def to_json(self):
        """返回json格式的数据"""
        _dict = self.__dict__
        if "_sa_instance_state" in _dict:
            del _dict["_sa_instance_state"]
        return _dict

    def to_dict(self):
        return {c.name: getattr(self, c.name, None)
                for c in self.__table__.columns}


# 创建所有不存在的表
Base.metadata.create_all(engine)
session = Session()

category = Category(**{"name": "历史"})
category1 = Category(**{"name": "军事"})
category2 = Category(**{"name": "小说"})
category3 = Category(**{"name": "传记"})

book = Book(**{"name": "水浒传", "category_id": "1"})
book1 = Book(**{"name": "西游记", "category_id": "2"})
book2 = Book(**{"name": "红楼梦", "category_id": "3"})
book3 = Book(**{"name": "三国演义", "category_id": "2"})
book4 = Book(**{"name": "昆仑", "category_id": "1"})

# 添加书
# session.add_all([category, category1, category2, category3,book,book1,book2,book3,book4])
# session.flush()
# session.commit()
results = session.query(Book).all()
print([i.to_dict() for i in results])
book_id = 1
# book_ = session.query(Book).get(book_id)
# book_ = session.query(Book).filter(Book.id == book_id).first()
# book_ = session.query(Book).filter(Book.id > book_id).first()
# print(book_ and book_.to_dict())
book_ = session.query(Book.id, Book.name).filter(Book.name.contains('水')).all()
print([dict(zip(v.keys(), v)) for v in book_])

# 内连接查询
# 如果 ORM 对象中定义有外键关系
# 那么 join() 中可以不指定关联关系
# 否则,必须要
books = session \
    .query(Book.id,
           Book.name.label('book_name'),
           Category.name.label('cat_name')) \
    .join(Category, Book.category_id == Category.id) \
    .filter(Category.name == '小说',
            Book.id > 1) \
    .all()

# 查看SQL语句时,将.all()注释掉,print(books)即可看到SQL
print(books)
print([dict(zip(v.keys(), v)) for v in books])

# 统计各个分类的图书的数量
from sqlalchemy import func
books = session \
    .query(Category.name.label('cat_name'),
           func.count(Book.id).label('book_num')) \
    .join(Book, Category.id == Book.category_id) \
    .group_by(Category.id) \
    # .all()
print(books)
print([dict(zip(v.keys(), v)) for v in books])


# outerjoin 默认是左连接
# 如果 ORM 对象中定义有外键关系
# 那么 outerjoin() 中可以不指定关联关系
# 否则,必须要
books = session \
    .query(Book.id.label('book_id'),
           Book.name.label('book_name'),
           Category.id.label('cat_id'),
           Category.name.label('cat_name')) \
    .outerjoin(Category, Book.category_id == Category.id) \
    .filter(Book.id >= 3) \
    .all()
print(books)
print([dict(zip(v.keys(), v)) for v in books])

扩展(Flask-SQLALchemy)

常用方法介绍

filter()    # 把过滤器添加到原查询上,返回一个新查询
filter_by()   # 把等值过滤器添加到原查询上,返回一个新查询
limit    # 使用指定的值限定原查询返回的结果
offset()    # 偏移原查询返回的结果,返回一个新查询
order_by()    # 根据指定条件对原查询结果进行排序,返回一个新查询
group_by()    # 根据指定条件对原查询结果进行分组,返回一个新查询
all()    # 以列表形式返回查询的所有结果
first()    # 返回查询的第一个结果,如果未查到,返回None
first_or_404()   # 返回查询的第一个结果,如果未查到,返回404
get()    # 返回指定主键对应的行,如不存在,返回None
get_or_404()   # 返回指定主键对应的行,如不存在,返回404
count()  #  返回查询结果的数量
paginate()  #  返回一个Paginate对象,它包含指定范围内的结果

常用方法举例

# 查询所有用户数据
User.query.all()
# 查询有多少个用户
User.query.count()
# 查询第1个用户
User.query.first()
User.query.get(1)   # 根据id查询
# 查询id为4的用户[3种方式]
User.query.get(4)
User.query.filter_by(id=4).all()   # 简单查询  使用关键字实参的形式来设置字段名
User.query.filter(User.id == 4).all()  # 复杂查询  使用恒等式等其他形式来设置条件
#查询名字结尾字符为g的所有用户[开始 / 包含]
User.query.filter(User.name.endswith("g")).all()
User.query.filter(User.name.startswith("w")).all()
User.query.filter(User.name.contains("n")).all()
User.query.filter(User.name.like("%n%g")).all()  # 模糊查询
# 查询名字和邮箱都以li开头的所有用户[2种方式]
User.query.filter(User.name.startswith("li"), User.email.startswith("li")).all()
from sqlalchemy import and_
User.query.filter(and_(User.name.startswith("li"), User.email.startswith("li"))).all()
# 查询age是25 或者 `email`以`itheima.com`结尾的所有用户
from sqlalchemy import or_
User.query.filter(or_(User.age == 25, User.email.endswith("itheima.com"))).all()
# 查询名字不等于wang的所有用户[2种方式]
from sqlalchemy import not_
User.query.filter(not_(User.name == "wang")).all()
User.query.filter(User.name != "wang").all()
# 查询id为[1, 3, 5, 7, 9]的用户
User.query.filter(User.id.in_([1, 3, 5, 7, 9])).all()
# 所有用户先按年龄从小到大, 再按id从大到小排序, 取前5个
User.query.order_by(User.age, User.id.desc()).limit(5).all()
# 分页查询, 每页3个, 查询第2页的数据
pn = User.query.paginate(2, 3)
# pn.items  获取该页的数据     pn.page   获取当前的页码     pn.pages  获取总页数

参考

中文

英文

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章