Python操作MySQL之原生pymysql模塊和orm框架SQLAchemy

1、原生模塊pymysql

1.下載安裝

pip3 install pymysql

2.使用操作

執行sql

# Author: 73

import pymysql

# 創建連接
conn = pymysql.connect(host='127.0.0.1', port=3306, user='seth', passwd='123456', db='test')
# 創建遊標
cursor = conn.cursor()

# # 執行SQL,並返回收影響行數
# effect_row = cursor.execute("select * from stu")

#effect_row = cursor.execute("update study_record set status='YES' where id=%s", (1,))

# # 執行SQL,並返回收影響行數
#effect_row = cursor.execute("insert into study_record(day, status, stu_id) values(%s, %s, %s)", ((2,"YES",1,)))

#一次插入多條數據
data = [
    (2,"NO",2),
    (3,"YES",3),
    (4,"NO",1),

]
effect_row = cursor.executemany("insert into study_record(day, status, stu_id) values(%s, %s, %s)", data)

# 提交,不然無法保存新建或者修改的數據
conn.commit()

# 關閉遊標
cursor.close()
# 關閉連接
conn.close()

獲取查詢數據

# Author: 73

import pymysql

# 創建連接
conn = pymysql.connect(host='127.0.0.1', port=3306, user='seth', passwd='123456', db='test')
# 創建遊標
cursor = conn.cursor()

# # 執行SQL,並返回收影響行數
effect_row = cursor.execute("select * from stu")

# row1 = cursor.fetchone() # 取一條結果
# row2 = cursor.fetchmany(3) # 取多條數據
# row3 = cursor.fetchall() # 取所有結果,如果執行這條語句之前,執行了fetchone語句,那麼只會得到剩餘的結果

# 提交,不然無法保存新建或者修改的數據
conn.commit()

# 關閉遊標
cursor.close()
# 關閉連接
conn.close()

注:在fetch數據時按照順序進行,可以使用cursor.scroll(num,mode)來移動遊標位置,如:

  • cursor.scroll(1,mode=‘relative’) # 相對當前位置移動, 光標往後移一個
  • cursor.scroll(2,mode=‘absolute’) # 相對絕對位置移動, 光標往前移兩個

fetch數據類型
默認獲取的數據是元祖類型,如果想要獲取字典類型的數據,需要在創建遊標時設置爲字典類型

# Author: 73

import pymysql

# 創建連接
conn = pymysql.connect(host='127.0.0.1', port=3306, user='seth', passwd='123456', db='test')
# 遊標設置爲字典類型
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)

# # 執行SQL,並返回收影響行數
effect_row = cursor.execute("select * from stu")

row1 = cursor.fetchone() # 取一條結果
print(row1)
# 提交,不然無法保存新建或者修改的數據
conn.commit()

# 關閉遊標
cursor.close()
# 關閉連接
conn.close()

2、ORM框架SQLAchemy

1.ORM介紹

orm英文全稱object relational mapping,就是對象映射關係程序,簡單來說我們類似python這種面向對象的程序來說一切皆對象,但是我們使用的數據庫卻都是關係型的,爲了保證一致的使用習慣,通過orm將編程語言的對象模型和數據庫的關係模型建立映射關係,這樣我們在使用編程語言對數據庫進行操作的時候可以直接使用編程語言的對象模型進行操作就可以了,而不用直接使用sql語言。
在這裏插入圖片描述
優點:

  • 隱藏了數據訪問細節,“封閉”的通用數據庫交互,ORM的核心。他使得我們的通用數據庫交互變得簡單易行,並且完全不用考慮該死的SQL語句.
  • ORM使我們構造固化數據結構變得簡單易行.

缺點:

  • 自動化意味着映射和關聯管理,代價是犧牲性能。現在的各種ORM框架都在嘗試使用各種方法來減輕這塊(LazyLoad,Cache),效果還是很顯著的。

2.sqlalchemy安裝

pip3 install SQLAlchemy

3.sqlalchemy基本使用

根據配置文件的不同調用不同的數據庫API,從而實現對數據庫的操作,如:

MySQL-Python
    mysql+mysqldb://<user>:<password>@<host>[:<port>]/<dbname>
   
pymysql
    mysql+pymysql://<username>:<password>@<host>/<dbname>[?<options>]
   
MySQL-Connector
    mysql+mysqlconnector://<user>:<password>@<host>[:<port>]/<dbname>
   
cx_Oracle
    oracle+cx_oracle://user:pass@host:port/dbname[?key=value&key=value...]
   
更多詳見:http://docs.sqlalchemy.org/en/latest/dialects/index.html

創建表

# Author: 73

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

engine = create_engine("mysql+pymysql://seth:123456@localhost/test", encoding="utf-8", echo=True) # echo是否打印運行過程

Base = declarative_base() # 生成orm基類

class User(Base):
    __tablename__ = 'user' # 表名
    id = Column(Integer, primary_key=True)
    name = Column(String(32))
    password = Column(String(32))

Base.metadata.create_all(engine) # 創建表結構

創建一條數據

from sqlalchemy.orm import sessionmaker

Session_class = sessionmaker(bind=engine) #創建與數據庫的會話session class ,注意,這裏返回給session的是個class,不是實例
Session = Session_class() #生成session實例

user_obj = User(name="bob", password="123") #生成你要創建的數據對象
print(user_obj.name, user_obj.id) #此時還沒創建對象呢,不信你打印一下id發現還是None

Session.add(user_obj) #把要創建的數據對象添加到這個session裏, 一會統一創建
Session.commit() #現此才統一提交,創建數據

創建多條數據

Session.add_all([user1,user2...])

查詢

data = Session.query(User).filter_by(name="bob").first()
print(data.name)

#data = Session.query(User).filter_by(name="bob").all()
#print(data[0].name)

#data = Session.query(User).filter(User.id>1).all()
#print(data.name)

返回的data是一個對象,通過data.name就可以看到數據了

如果想打印data時看到數據信息,可以在定義表的類下面加上這樣的代碼:

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

常用查詢語法

equals:
     query.filter(User.name == 'ed')

not equals:
     query.filter(User.name != 'ed')

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

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

多條件查詢

# 下面2個filter的關係相當於 user.id >1 AND user.id <7 的效果
data = Session.query(User).filter(User.id>2).filter(User.id<4).all()
print(data)

修改

data = Session.query(User).filter(User.id>2).filter(User.id<4).first()
print(data)
data.name = "RAIN"

刪除

data = Session.query(User).filter_by(id=6).first()
print(data)
Session.delete(data)

Session.query(User).filter_by(id=6).delete()

回滾

user = User(name="fish", password="123")
Session.add(user)

print(Session.query(User).filter(User.name.in_(['jack','fish'])).all()) # 這時看session有你剛剛添加和修改的數據
Session.rollback()
print(Session.query(User).filter(User.name.in_(['jack', 'fish'])).all()) # 再查就發現剛纔添加的數據沒了

獲取所有數據

print(Session.query(User.name,User.password).all())

統計分組

統計

print(Session.query(User.name,User.password).count())

print(Session.query(User).filter(User.name.like("Ra%")).count())

分組

print(Session.query(func.count(User.name),User.name).group_by(User.name).all())
'''
相當於原生sql
SELECT count(name) AS count_1, name AS user_name FROM user GROUP BY name;
'''

外鍵關聯

創建一張study_record表和stu關聯

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

engine = create_engine("mysql+pymysql://seth:123456@localhost/test", encoding="utf-8", echo=False) # echo是否打印運行過程

Base = declarative_base() # 生成orm基類

class StudyRecord(Base):
    __tablename__ = 'study_record' # 表名
    id = Column(Integer, primary_key=True, autoincrement=True)
    day = Column(Integer, nullable=False)
    status = Column(String(32), nullable=False)
    stu_id = Column(Integer, ForeignKey("stu.id"),nullable=False) # 外鍵

    # 這個nb,允許你在stu表裏通過backref字段反向查出所有它在study_record表裏的關聯項
    # 同時,study_record表可以通過syudent這個字段查詢stu表的關聯項
    student = relationship("Stu", backref="my_study_record")

    def __repr__(self):
        return "<%s day: %s status:%s>" % (self.student.name, self.day, self.status)

class Stu(Base):
    __tablename__ = 'stu'
    id = Column(Integer, primary_key=True, autoincrement=True, nullable=False)
    name = Column(String(32), nullable=False)
    age = Column(Integer, nullable=False)
    register_date = Column(DATE,nullable=True)
    gender = Column(Enum('M','F'), default='M', nullable=True)

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

Base.metadata.create_all(engine) # 創建表結構

通過stu表反查study_record表

Session_class = sessionmaker(bind=engine) #創建與數據庫的會話session class ,注意,這裏返回給session的是個class,不是實例
Session = Session_class() #生成session實例

ret = Session.query(StudyRecord).filter(Stu).all()
print(ret.my_study_record)

多外鍵關聯

Customer表有2個字段都關聯了Address表

# Author: 73

from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, DATE, Enum, ForeignKey
from sqlalchemy.orm import relationship

engine = create_engine("mysql+pymysql://seth:123456@localhost/test", encoding="utf-8", echo=False) # echo是否打印運行過程

Base = declarative_base() # 生成orm基類

class Customer(Base):
    __tablename__ = 'customer'
    id = Column(Integer, primary_key=True)
    name = Column(String(64))

    billing_address_id = Column(Integer, ForeignKey("address.id"))
    shipping_address_id = Column(Integer, ForeignKey("address.id"))


    billing_address = relationship("Address")
    shipping_address = relationship("Address")


class Address(Base):
    __tablename__ = 'address'
    id = Column(Integer, primary_key=True)
    street = Column(String(64))
    city = Column(String(64))
    state = Column(String(64))

Base.metadata.create_all(engine)  # 創建表結構

創建表結構是沒有問題的,但向Address表中插入數據時會報錯,原因是沒有說明哪個外鍵對應哪個字段,修改如下即可:

billing_address = relationship("Address", foreign_keys=[billing_address_id])
    shipping_address = relationship("Address", foreign_keys=[shipping_address_id])

測試代碼:

# Author: 73

from day12 import orm_many_fk
from sqlalchemy.orm import sessionmaker

Session_class = sessionmaker(bind=orm_many_fk.engine) #創建與數據庫的會話session class ,注意,這裏返回給session的是個class,不是實例
Session = Session_class() #生成session實例

# 插入數據
# addr1 = orm_many_fk.Address(street="yinzhou", city="ningbo", state="ZJ")
# addr2 = orm_many_fk.Address(street="zhenghai", city="ningbo", state="ZJ")
# addr3 = orm_many_fk.Address(street="yuhuan", city="taizhou", state="ZJ")
#
# Session.add_all([addr1, addr2, addr3])
#
# costomer1 = orm_many_fk.Customer(name='seth', billing_address_id=1, shipping_address_id=2)
# costomer2 = orm_many_fk.Customer(name='jack', billing_address_id=3, shipping_address_id=3)
#
# Session.add_all([costomer1, costomer2])

# 查詢
data = Session.query(orm_many_fk.Customer).filter(orm_many_fk.Customer.id==1).first()
print(data.name, data.billing_address,data.shipping_address)


Session.commit()

多對多關係

前面的例子都是一對多或者一對一的關係,那麼如果是多對多,那麼該怎麼存儲呢?

比如說一本書可以有很多個作者,一個作者也可以有很多本書。

book_m2m_author = Table('book_m2m_author', Base.metadata,
                        Column('book_id', Integer, ForeignKey('books.id')),
                        Column('author_id', Integer, ForeignKey('authors.id')))

class Book(Base):
    __tablename__ = "books"
    id = Column(Integer, primary_key=True)
    name = Column(String(64))
    pub_date = Column(DATE)
    authors = relationship("Author", secondary=book_m2m_author, backref="books") # 通過第三張表book_m2m_author實現多對多的關聯

    def __repr__(self):
        return self.name

class Author(Base):
    __tablename__ = "authors"
    id = Column(Integer, primary_key=True)
    name = Column(String(32))

    def __repr__(self):
        return self.name

創建數據

b1 = orm_m2m_fk.Book(name="python basic", pub_date="2020-01-11")
b2 = orm_m2m_fk.Book(name="linux basic", pub_date="2010-04-12")
b3 = orm_m2m_fk.Book(name="java basic", pub_date="2018-03-21")

author1 = orm_m2m_fk.Author(name="seth")
author2 = orm_m2m_fk.Author(name="jack")
author3 = orm_m2m_fk.Author(name="tom")

b1.authors = [author1, author2]
b2.authors = [author1, author3]
b3.authors = [author1, author2, author3]

Session.add_all([b1,b2,b3,author1,author2,author3])

插入結果
在這裏插入圖片描述

多對多查詢

print("通過書查作者")
book_obj = Session.query(orm_m2m_fk.Book).filter(orm_m2m_fk.Book.name=="python basic").first()
print(book_obj.name, book_obj.authors)

print("通過作者查書")
author_obj = Session.query(orm_m2m_fk.Author).filter(orm_m2m_fk.Author.name=="seth").first()
print(author_obj.name, author_obj.books)

result
在這裏插入圖片描述

多對多刪除
刪除數據時不用管book_m2m_author, sqlalchemy會自動幫你把對應的數據刪除

通過書刪除作者

book_obj = Session.query(orm_m2m_fk.Book).filter(orm_m2m_fk.Book.name=="python basic").first()
author_obj = Session.query(orm_m2m_fk.Author).filter(orm_m2m_fk.Author.name=="seth").first()
book_obj.authors.remove(author_obj) # #從一本書裏刪除一個作者

直接刪除作者

刪除作者時,會把這個作者跟所有書的關聯關係數據也自動刪除

author_obj = Session.query(orm_m2m_fk.Author).filter(orm_m2m_fk.Author.name=="seth").first()
Session.delete(author_obj)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章