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  獲取總頁數

參考

中文

英文

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