ORM:及Object-Relational Mapping,對象關係映射,把關係數據庫的表結構映射到對象上。
咱們先來可能一個例子:
若是咱們從數據庫查出來幾條數據,須要你在python中表示出來,若是你沒有接觸過ORM技術,你或許會使用下面的形式來存儲這個數據:node
[ (1, "yangjian"), (2, "chengdu"), (3, "hello"), ]
若是你想知道表結構是什麼樣的,是否是就費勁了,若是你想快速得出其中的元素,就須要聽聽ORM的思想了。python
數據庫中每次查出來的數據都用一個類表示,這個類的屬性和數據庫中表的字段一一對應。多條數據,就是一個list,每一行數據都是一個類來表示,以下所示:mysql
class User(object): def __init__(self, id, name): self.id = id self.name = name [ User(1, "yangjian"), User(2, "chengdu"), User(3, "hello"), ]
當咱們須要得到id,或者name的時候,只須要經過循環獲取到對象,直接經過user1.id或者user1.name就能夠獲取到id和name的屬性。而且使得數據的存取很是的規範,這樣ORM架構應用而生。sql
Python中最有名的ORM架構就是SQLAlchemy,咱們主要就是來學習SQLAlchemy的使用。數據庫
pip install SQLAlchemy
yum install mysql-server mysql
service mysqld restart
sysctmctl restart mysql.service
create database sqlalchemy;
GRANT ALL PRIVILEGES ON *.* TO 'yangjian'@'%' IDENTIFIED BY '123456';
from sqlalchemy import create_engine engine = create_engine('mysql+pymysql://yangjian:123456@192.168.48.131/sqlalchemy', echo=True)
echo參數爲True時,會顯示每條執行的SQL語句,能夠關閉。
create_engine()返回一個Engine的實例,而且它表示經過數據庫語法處理細節的核心接口,在這種狀況下,數據庫語法將會被解釋成python的類方法。
mysql://yangjian:123456@192.168.48.131/sqlalchemy
mysql+pymysql: 指定是哪一種數據庫鏈接,在python3中不寫成mysql+pymysql會報找不到MySQLdb模塊的錯誤
yangjina: 數據庫用戶名
123456: 數據庫用戶對應的密碼
192.168.48.131: 數據庫的ip
sqlalchemy: 數據庫須要鏈接哪一個庫的名字安全
有如下兩種方式建立數據庫表:session
from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker sql = '''create table student( id int not null primary key, name varchar(50), age int, address varchar(100)); ''' engine = create_engine('mysql://yangjian:123456@192.168.48.131/sqlalchemy') conn = engine.connect() conn.execute(sql) engine.connect() #表示獲取到數據庫鏈接。相似咱們在MySQLdb中游標cursor的做用。
from sqlalchemy import Column from sqlalchemy import Integer from sqlalchemy import MetaData from sqlalchemy import String from sqlalchemy import Table from sqlalchemy import create_engine from sqlalchemy.ext.declarative import declarative_base engine = create_engine('mysql://yangjian:123456@192.168.48.131/sqlalchemy') metadata = MetaData(engine) user = Table('user', metadata, Column('id', Integer, primary_key=True), Column('name', String(20)), Column('fullname', String(40)) ) metadata.create_all(engine) conn = engine.connect() print(conn)
MetaData類主要用於保存表結構,鏈接字符串等數據,是一個多表共享的對象
metadata = MetaData(engine) 綁定一個數據源的metadata
metadata.create_all(engine) 是來建立表,這個操做是安全的操做,會先判斷表是否存在。
Table類
構造函數:
Table.__init__(self, name, metadata,*args, **kwargs)
name 表名
metadata 共享的元數據
*args Column 是列定義架構
下面是可變參數 **kwargs 定義
schema 此表的結構名稱,默認None
autoload 自動從現有表中讀入表結構,默認False
autoload_with 從其餘engine讀取結構,默認Noneapp
Column.__init__(self, name, type_, *args, **kwargs)函數
1、name 列名 2、type_ 類型,更多類型 sqlalchemy.types 三、*args Constraint(約束), ForeignKey(外鍵), ColumnDefault(默認), Sequenceobjects(序列)定義 4、key 列名的別名,默認None 下面是可變參數 **kwargs 5、primary_key 若是爲True,則是主鍵 6、nullable 是否可爲Null,默認是True 7、default 默認值,默認是None 8、index 是不是索引,默認是True 9、unique 是否惟一鍵,默認是False 10、onupdate 指定一個更新時候的值,這個操做是定義在SQLAlchemy中,不是在數據庫裏的,當更新一條數據時設置,大部分用於updateTime這類字段 11、autoincrement 設置爲整型自動增加,只有沒有默認值,而且是Integer類型,默認是True 十二、quote 若是列明是關鍵字,則強制轉義,默認False
說到數據庫,就離不開Session。Session的主要目的是創建與數據庫的會話,它維護你加載和關聯的全部數據庫對象。它是數據庫查詢(Query)的一個入口。
在Sqlalchemy中,數據庫的查詢操做是經過Query對象來實現的。而Session提供了建立Query對象的接口。
Query對象返回的結果是一組同一映射(Identity Map)對象組成的集合。事實上,集合中的一個對象,對應於數據庫表中的一行(即一條記錄)。所謂同一映射,是指每一個對象有一個惟一的ID。若是兩個對象(的引用)ID相同,則認爲它們對應的是相同的對象。
要完成數據庫查詢,就須要創建與數據庫的鏈接。這就須要用到Engine對象。一個Engine多是關聯一個Session對象,也可能關聯一個數據庫表。
固然Session最重要的功能仍是實現原子操做。
ORM經過session與數據庫創建鏈接進行通訊,以下所示:
from sqlalchemy.orm import sessionmaker DBSession = sessionmaker(bind=engine) session = DBSession() # 經過sessionmake方法建立一個Session工廠,而後在調用工廠的方法來實例化一個Session對象。
from sqlalchemy import Column from sqlalchemy import Integer from sqlalchemy import String from sqlalchemy import create_engine from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker Base = declarative_base() class Student(Base): __tablename__ = 'student' id = Column(Integer, primary_key=True) name = Column(String(50)) age = Column(Integer) address = Column(String(100)) engine = create_engine('mysql+pymysql://yangjian:123456@192.168.48.131/sqlalchemy') DBSession = sessionmaker(bind=engine) session = DBSession() new_student = Student(id=10001, name="yangjian", age=18, address="chengdu") new_student2 = Student(id=10002, name="yangjian1", age=181, address="chengdu") new_student3 = Student(id=10003, name="yangjian2", age=182, address="chengdu") session.add(new_student) session.add_all([new_student1, new_student2]) session.commit() session.close()
查詢是這個裏面最爲複雜,最爲繁瑣的一個步驟。
經過Session的query()方法建立一個查詢對象。這個函數的參數數量是可變的,參數能夠是任何類或者是類的描述的集合。下面來看一個例子:
my_stdent = session.query(Student).filter_by(name="yangjian").first() print(my_stdent) 結果: <__main__.Student object at 0x032745F0>
前面咱們在賦值的時候,咱們能夠經過實例化一個對象,而後直接映射到數據庫中,那咱們在查詢出來的數據sqlalchemy直接給映射成一個對象了(或者是每一個元素爲這種對象的列表),對象和咱們建立表時候的class是一致的,咱們就也能夠直接經過對象的屬性就能夠直接調用就能夠了。
print(my_student.id, my_student.name, my_student.age, my_student.address) 結果: (10003L, 'yangjian', 182L, 'chengdu')
filter() 過濾表的條件
my_stdent = session.query(Student).filter(Student.name.like("%yang%")) print(my_stdent) 結果: SELECT student.id AS student_id, student.name AS student_name, student.age AS student_age, student.address AS student_address FROM student WHERE student.name LIKE %s
根據結果,咱們能夠看出來,filter_by最後的結果就是一個sql語句,咱們排錯的時候就能夠經過這個來排查咱們sql是否正確。
如下的這些過濾操做均可以在filter函數中使用:
equals: query(Student).filter(Student.id == 10001) not equals: query(Student).filter(Student.id != 100) LIKE: query(Student).filter(Student.name.like(「%yang%」))
IN:
query(Student).filter(Student.name.in_(['yang', 'jian', 'cheng']))
not in
query(Student).filter(~Student.name.in_(['yang', 'jian', 'cheng']))
AND:
from sqlalchemy import and_
query(Student).filter(and_(Student.name == 'yang', Student.id ==10001))
或者
query(Student).filter(Student.name == 'edfadfj').filter(Student.address == 'beijing')
OR:
from sqlalchemy import or_
query.filter(or_(Student.name == 'fdedsfd', Student.age ==18))
返回列表(List)和單項(Scalar)
all() 返回一個列表
my_stdent = session.query(Student).filter(Student.name.like("%ling%")).all() print(my_stdent) 結果: [<__main__.Student object at 0x031405B0>, <__main__.Student object at 0x030FCA70>, <__main__.Student object at 0x031405F0>]
能夠經過遍歷列表來獲取每一個對象。
one() 返回且僅返回一個查詢結果。當結果的數量不足一個或者多於一個時會報錯。
把上面的all改爲one就報錯了。
first() 返回至多一個結果,並且以單項形式,而不是隻有一個元素的tuple形式返回這個結果.
my_stdent = session.query(Student).filter(Student.name.like("%yang%")).first() print(my_stdent) 結果: <__main__.Student object at 0x030A3610>
filter()和filter_by()的區別:
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()
filter不支持組合查詢,只能連續調用filter來變相實現。
而filter_by的參數是**kwargs,直接支持組合查詢。
好比:
q = sess.query(IS).filter(IS.node == node and IS.password == password).all()
更新就是查出來,直接更改就能夠了
my_stdent = session.query(Student).filter(Student.id == 10001).first() my_stdent.name = "hello" my_stdent.address = "beijing" session.commit() student1 = session.query(Student).filter(Student.id == 10001).first() print(student1.name, student1.address) 結果: ('hello', 'beijing')
刪除其實也是跟查詢相關的,直接查出來,調用delete()方法直接就能夠刪除掉。
engine = create_engine('mysql+pymysql://yangjian:123456@192.168.48.131/sqlalchemy') DBSession = sessionmaker(bind=engine) session = DBSession() session.query(Student).filter(Student.id == 10001).delete() session.commit() session.close()
count()
print(session.query(Student).filter(Student.name.like("%ng%")).count())
group_by()
std_group_by = session.query(Student).group_by(Student.age) print(std_group_by) 結果的sql語句以下: SELECT student.id AS student_id, student.name AS student_name, student.age AS student_age, student.address AS student_address FROM student GROUP BY student.age
order_by() 反序在order_by裏面用desc()方法
std_ord_desc = session.query(Student).filter(Student.name.like("%yang%")).order_by(Student.id.desc()).all() for i in std_ord_desc: print(i.id)