Python操作MySQL之SQLAlchemy

概述

SQLAlchemy是Python編程語言下的一款ORM框架,該框架建立在數據庫API之上,使用關係對象映射進行數據庫操作,簡言之便是:將對象轉換成SQL,然後使用數據API執行SQL並獲取執行結果。

 

ORM技術

數據庫表是一個二維表,包含多行多列。把一個表的內容用Python的數據結構表示出來的話,可以用一個list表示多行,list的每一個元素是tuple,表示一行記錄。比如,包含id和name的user表:

[
    ('1', 'Michael'),
    ('2', 'Bob'),
    ('3', 'Adam')
]

Python的DB-API返回的數據結構就是像上面這樣表示的。

但是用tuple表示一行很難看出表的結構。如果把一個tuple用class實例來表示,就可以更容易地看出表的結構來:

class User(object):
    def __init__(self, id, name):
        self.id = id
        self.name = name

[
    User('1', 'Michael'),
    User('2', 'Bob'),
    User('3', 'Adam')
]

上述就是ORM技術:Object-Relational Mapping,把關係數據庫的表結構映射到對象上。

SQLAlchemy

SQLAlchemy-初始化連接

SQLAlchemy本身無法操作數據庫,其必須依賴pymsql等第三方插件,Dialect用於和數據API進行交流,根據配置文件的不同調用不同的數據庫API,從而實現對數據庫的操作。

# pymysql
DB_CONNECT_STRING = 'mysql+pymysql://root:[email protected]:3306/db_stable'

# MySQL-Python
DB_CONNECT_STRING = 'mysql+mysqldb://root:[email protected]:3306/db_stable'

# MySQL-Connector
DB_CONNECT_STRING = 'mysql+mysqlconnector://root:[email protected]:3306/db_stable'
  

create_engine()返回一個Engine的實例,並且它表示通過數據庫語法處理細節的核心接口,在這種情況下,數據庫語法將會被解釋成python的類方法。

echo參數爲True時,會顯示每條執行的SQL語句,可以關閉。

from sqlalchemy import create_engine

# 初始化數據庫連接
DB_CONNECT_STRING = 'mysql+pymysql://root:[email protected]:3306/db_stable'
Engine = create_engine(DB_CONNECT_STRING, echo=True, pool_recycle=3600)

 

SQLAlchemy-創建表

__tablename__ 屬性:數據庫中該表的名稱

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

# 創建對象的基類,declarative_base() 創建了一個 Base類,這個類的子類可以自動與一個表關聯。
Base = declarative_base()

# 創建單表
class Params(Base):
    __tablename__ = "t_params"
    __table_arge__ = {"extend_existing": True, "useexisting": True}
    id = Column(Integer, primary_key=True, autoincrement=True)
    package = Column(CHAR(255), nullable=False)
    project = Column(CHAR(255), nullable=False)
    platform = Column(CHAR(255), nullable=False)
    prefix = Column(CHAR(255))
    activity = Column(CHAR(255))
    
# 一對多,外鍵ForeignKey
class Devices(Base):
    __tablename__ = "t_devices"
    __table_arge__ = {"extend_existing": True, "useexisting": True}
    id = Column(Integer, primary_key=True, autoincrement=True)
    sn = Column(CHAR(255), nullable=False)
    platform = Column(CHAR(50), nullable=False)
    idfa = Column(CHAR(255))
    uuid = Column(CHAR(255))
    unionid = Column(CHAR(255))
    product = Column(CHAR(255))
    os_version = Column(CHAR(255))
    
class Jobs(Base):
    __tablename__ = "t_jobs"
    __table_arge__ = {"extend_existing": True, "useexisting": True}
    id = Column(Integer, autoincrement=True, primary_key=True)
    device_id = Column(Integer, ForeignKey("t_devices.id"))
    user_name = Column(CHAR(255))
    business = Column(CHAR(255))
    version = Column(CHAR(50))
    job_type = Column(CHAR(50))
    submit_time = Column(DATETIME)
    end_time = Column(DATETIME)
    job_status = Column(Integer)
    config_name = Column(CHAR(255))
    
# 多對多
class ServerToGroup(Base):
    __tablename__ = 'servertogroup'
    nid = Column(Integer, primary_key=True, autoincrement=True)
    server_id = Column(Integer, ForeignKey('server.id'))
    group_id = Column(Integer, ForeignKey('group.id'))

class Group(Base):
    __tablename__ = 'group'
    id = Column(Integer, primary_key=True)
    name = Column(String(64), unique=True, nullable=False)


class Server(Base):
    __tablename__ = 'server'
    id = Column(Integer, primary_key=True, autoincrement=True)
    hostname = Column(String(64), unique=True, nullable=False)
    port = Column(Integer, default=22)

多對多關係:需要轉換成1對多關係,需要一張中間表來轉換,這張中間表裏面需要存放學生表裏面的主鍵和課程表裏面的主鍵,此時學生與中間表示1對多關係,課程與中間表是1對多關係,學生與課程是多對多關係。

 

SQLAlchemy-創建會話(操作表)

sessionmaker() 會生成一個數據庫會話類。這個類的實例可以當成一個數據庫連接,它同時還記錄了一些查詢的數據,並決定什麼時候執行 SQL 語句。

from sqlalchemy.orm import sessionmaker
# 創建Session對象(mysql操作對象)
Session = sessionmaker(bind=Engine, autoflush=True, expire_on_commit=True)

SQLAlchemy-增、刪、改、查

新增:

@auto_close
def insert_job(body, session=None):
    item = Jobs(**body)
    session.add(item)
    session.flush()

刪除:

@auto_close
def delete_job(data, jobId, session=None):
    session.query(Jobs).filter(Jobs.id == jobId).delete

更新:

@auto_close
def update_job(data, jobId, session=None):
    session.query(Jobs).filter(Jobs.id == jobId).update(data)

查詢

@auto_close
def get_jobId(sub_time, session=None):
    item = session.query(Jobs).filter(Jobs.submit_time == sub_time).first()
    jobId = item.id
    return jobId

注意:

1.通過Session的query()方法創建一個查詢對象。這個函數的參數數量是可變的,參數可以是任何類或者是類的描述的集合。

2.查詢出來的數據sqlalchemy直接給映射成一個對象(或者是每個元素爲這種對象的列表),對象和創建表時候的class是一致的,可以直接通過對象的屬性直接調用。如:item.id

3.first():返回查詢的第一個結果,如果沒有結果,則返回None

   all():以列表形式返回查詢的所有結果

   count():返回查詢結果的數量

 

SQLAlchemy-查詢

查詢過濾器

使用舉例:

filter():過濾表的條件

filter: 可以像寫 sql 的 where 條件那樣寫 > < 等條件,但引用列名時,需要通過"類名.屬性名"的方式。

filter_by: 可以使用 python 的正常參數傳遞方法傳遞條件,指定列名時,不需要額外指定類名。參數名對應類中的屬性名,但似乎不能使用 > < 等條件。

當使用filter的時候條件之間是使用“==",fitler_by使用的是"="。

user1 = session.query(User).filter_by(id=1).first()

user1 = session.query(User).filter(User.id==1).first()

# 條件:== 、!=、like、in、非、>、between
ret = session.query(Users).filter(Users.name =='alex').all()
ret = session.query(Users).filter(Users.name !='alex').all()
ret = session.query(Users).filter(Users.name.like("%alex%")).all()
ret = session.query(Users).filter(Users.id.in_([1,3,4])).all()  
ret = session.query(Users).filter(~Users.id.in_([1,3,4])).all()    # not in   ~爲通配符非
ret = session.query(Users).filter(~Users.name.like('e%')).all()
ret = session.query(Users).filter(Users.id > 1, Users.name == 'eric').all()
ret = session.query(Users).filter(Users.id.between(1, 3), Users.name == 'eric').all()

# AND  以下兩個功能一致
ret = session.query(Users).filter(and_(Users.name == 'fengxiaoqing', Users.id ==10001)).all()
ret = session.query(Users).filter(Users.name == 'fengxiaoqing').filter(Users.address == 'chengde').all()

# OR 
ret = session.query(Users).filter(or_(Users.name == 'fengxiaoqing', Users.age ==18)).all()
ret = session.query(Users).filter(
    or_(
        Users.id < 2,
        and_(Users.name == 'eric', Users.id > 3),
        Users.extra != ""
    )).all()

其餘函數:

# order_by:排序  limit:指定行數
item = session.query(Jobs).order_by(Jobs.id).limit(4)

# desc:倒序顯示   asc:升序
item = session.query(Jobs).order_by(Jobs.id.desc(),Jobs.device_id.asc())

# group_by
ret = session.query(Users).group_by(Users.extra).all()
# func
ret = session.query(
    func.max(Users.id),
    func.sum(Users.id),
    func.min(Users.id)).group_by(Users.name).all()
ret = session.query(
    func.max(Users.id),
    func.sum(Users.id),
    func.min(Users.id)).group_by(Users.name).having(func.min(Users.id) >2).all()

連接查詢join

ret = session.query(Users, Favor).filter(Users.id == Favor.nid).all()

ret = session.query(Person).join(Favor).all()

ret = session.query(Person).join(Favor, isouter=True).all()

子查詢

ret = session.query(Users).filter(Users.id.in_(session.query(Users.id).filter_by(name='eric'))).all()

聯合查詢union

q1 = session.query(Users.name).filter(Users.id > 2)
q2 = session.query(Favor.caption).filter(Favor.nid < 2)
ret = q1.union(q2).all()

q1 = session.query(Users.name).filter(Users.id > 2)
q2 = session.query(Favor.caption).filter(Favor.nid < 2)
ret = q1.union_all(q2).all()

 

參考

https://www.cnblogs.com/ccorz/p/5711955.html

https://blog.csdn.net/wuqing942274053/article/details/72571650

https://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/0014021031294178f993c85204e4d1b81ab032070641ce5000

mysql查詢操作:

https://blog.csdn.net/u012867040/article/details/54380900

https://blog.csdn.net/u012867040/article/details/59115271

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