SQLAlchemy-ORM

 

ORM技術簡介

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

 

SQLAlchemy

Python中最有名的ORM架構就是SQLAlchemy,咱們主要就是來學習SQLAlchemy的使用。數據庫

安裝環境

pip install SQLAlchemy

安裝mysql

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

1. 主要是經過sql語句來建立表格

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的做用。

 

2. 經過ORM方式建立表格

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類

構造函數

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)
相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息