安裝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 獲取總頁數
參考
中文
- https://www.osgeo.cn/sqlalchemy/orm/tutorial.html#declare-a-mapping
- https://www.osgeo.cn/sqlalchemy/orm/basic_relationships.html
- https://www.osgeo.cn/sqlalchemy/core/tutorial.html
- https://golden-note.readthedocs.io/zh/latest/python/sqlalchemy/json_model.html
- http://www.pythondoc.com/flask-sqlalchemy/quickstart.html
- https://juejin.im/post/5bf741886fb9a049fa0f671e#heading-8
- http://einverne.github.io/post/2018/09/sqlalchemy-relationship.html
英文