版權聲明:本文為作者原創文章,可以隨意轉載,但必須在明確位置標明出處!!!
note:本基礎系列旨在以爬蟲帶大家入門Python語言
上一篇文章我們講了如何使用Python語言操作sqlite、mysql數據庫,當然前面講到的都是一些簡單的操作,復雜的數據庫操作并不在本系列考慮的范圍內,因為每一種數據庫語言都可以單獨的寫一本書了,所以本系類旨在帶大家入門,至于如何修行就要靠各位自己了。本篇的重點主要講對象關系映射(Object Relational Mapping,簡稱ORM)
什么是ORM
對象-映射是ORM的核心思想,什么意思呢,就是它把前端的數據對象映射成關系數據庫中的數據類型,所以有了ORM我們前端只需要使用一份代碼,后端的數據庫不論是sqlite、mysql、oracle等其它關系數據庫只要改變連接字符串我們就能做到將前端的數據寫到不同的關系數據庫中,是不是很酷。
安裝SQLAlchemy
目前比較流行的Python ORM庫就是SQLAlchemy,它是第三方庫,所以我們必須的先安裝它采用使用它,可以到關網http://www.sqlalchemy.org/download.html下載,當然你也可以私信我,安裝方式有兩種,一種是源碼安裝,一種是使用pip安裝,pip安裝最簡單在終端執行
sudo pip install SQLAlchemy
源碼安裝也很簡單,將在官網下載的安裝包加壓,然后執行安裝命令,曾哥過程如下:
tar -xvf SQLAlchemy-1.2.0b3.tar.gz
cd SQLAlchemy-1.2.0b3
sudo python setup.py install
如何沒有出現什么錯誤則則證明安裝成功了,如果驗證SQLAlchemy庫安裝好了這里就不在啰嗦了,前面的文章都有講到
SQLAlchemy的設計模型
SQLAlchemy有兩種設計模型,兩種設計模型可以組合起來用,也可以單獨使用,不管是組合使用還是單獨使用,它們最終調用的都是DPAPI,下圖給出了兩種設計模型的層次依賴圖,SQLAlchemy ORM模型抽象的層次更高一些。
SQLAlchemy操作數據庫流程
對于數據庫操作流程我們要有一個核心的思想,就是「萬變不離其中」,我們只需要知道操作數據庫的本質流程是什么就可以了,操作數據庫的本質流程是什么? 首先我們要知道數據庫是一個服務,它提供了數據庫服務接口也就是DBAPI,所以無論第三方庫是怎么設計的最終都需要調用數據庫服務接口,那么數據庫操作流程就分為以下幾步:
- 第一步: 連接數據庫,對于SQLAlchemy來說就是創建一個引擎
from sqlalchemy import create_engine
engine = create_engine('sqlite:///qiubai.db', convert_unicode=True, echo=True)
create_engine函數的第一個參數就是我們需要連接的數據庫地址,這個數據庫連接字符到那里去獲取呢,兩種途徑,一種是到官網http://docs.sqlalchemy.org/en/latest/dialects/index.html這里去找數據庫相應的連接字符串格式定義,另一種是在在你的Python安裝目錄里的lib目錄里去找,windows目錄如下,E:\Program Files\Python36\Lib\sqlalchemy\dialects,當然你的Python安裝木塊可能不在E盤,你可以看到這個目錄下有sqlite、mysql、oracle等關系數據庫,比如本章所用到的是sqlite,那么就雙擊sqlite這個目錄,進入到目錄后打個pysqlite.py這個文件,你會看到文件的開頭部分就有connectstring格式:
ubuntu在目錄「/usr/local/lib/python3.5/dist-packages/SQLAlchemy-1.2.0b3-py3.5-linux-x86_64.egg/sqlalchemy/dialects」下。
- 第二步: 獲取游標,在ORM里就是獲得一個session(會話)
from sqlalchemy import create_engine
engine = create_engine('sqlite:///qiubai.db', convert_unicode=True, echo=True)
db_session = sessionmaker(bind=engine, autocommit=False, autoflush=False)
- 第三步: 建立一個映射關系,文章的開頭部分就說了ORM的核心思想就是關系映射, 所以我們要把一個對象映射成關系數據庫表的字段,就像前一篇文章的CREATE TABLE語句一樣,需要給表指定字段及類型
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class Qiubai(Base):
__tablename__ = 'qiubai'
id = Column(Integer, sqlite_autoincrement=True, primary_key=True)
userid = Column(String(20), nullable=False)
username = Column(String(20), nullable=False)
funny_num = Column(Integer, nullable=False)
content = Column(String(1024), nullable=True)
url = Column(String(1024), nullable=True)
def __init__(self, userid, username, funny_num, content, url):
self.userid = userid
self.username = username
self.funny_num = funny_num
self.content = content
self.url = url
- 第四步: 創建元素信息,映射關系定義好了,但是還沒有映射到數據庫里,所以最后異步就是將所有元素映射到數據庫里
from sqlalchemy import create_engine
engine = create_engine('sqlite:///qiubai.db', convert_unicode=True, echo=True)
db_session = sessionmaker(bind=engine, autocommit=False, autoflush=False)
Base.metadata.create_all(engine)
插入數據
obj = Qiubai('userid', 'username', funny_num, 'content', 'url')
session.add(obj)
session.commit()
刪除數據
#刪除所有數據
session.delete(obj)
session.commit()
delete
###刪除指定數據
session.query(obj).filter(obj.userid == '1234').delete()
filter相當于where子句
查詢數據
# 查詢所有數據
session.query(Qiubai).all()
# 查詢指定數據
session.query(obj).filter(obj.userid == '1234').one()
更新數據
# 更新所有數據
session.query(Qiubai).update({Qiubai.funny_num:500})
session.commit()
# 更新指定數據
session.query(Qiubai).filter(Qiubai.userid=='/users/33096359/').update({Qiubai.funny_num:500})
session.commit()
實戰
在抓取糗百的項目的我又增加了兩個文件,一個是TableDef.py文件,該文件主要負責關系映射,所有的表定義都放在這個文件,另一個文件是SqlalchemyImpl.py,該文件主要負責執行數據庫操作,文件內容定義如下:
# TableDef.py
from sqlalchemy import create_engine
from sqlalchemy import Column, String, Integer
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class Qiubai(Base):
__tablename__ = 'qiubai'
id = Column(Integer, primary_key=True)
userid = Column(String(20), nullable=False)
username = Column(String(20), nullable=False)
funny_num = Column(Integer, nullable=False)
content = Column(String(1024), nullable=True)
url = Column(String(1024), nullable=True)
def __init__(self, userid, username, funny_num, content, url):
self.userid = userid
self.username = username
self.funny_num = funny_num
self.content = content
self.url = url
# SqlalchemyImpl.py
from sqlalchemy import create_engine
from sqlalchemy import Column, String, Integer
from sqlalchemy.orm import sessionmaker
from TableDef import Base, Qiubai
class SqlalchemyImpl(object):
"""docstring for SqlalchemyImpl"""
def __init__(self):
engine = create_engine('sqlite:///qiubai.db', convert_unicode=True, echo=True)
self.db_session = sessionmaker(bind=engine, autocommit=False, autoflush=False)
# Base.session = self.db_session
Base.metadata.create_all(engine)
def insert_record(self, items):
session = self.db_session()
try:
for item in items:
obj = Qiubai(item[0], item[1], item[2], item[3], item[4])
#list_record.append(obj)
session.add(obj)
session.commit()
except Exception as e:
session.rollback()
raise e
def delete_record(self):
try:
session = self.db_session()
session.delete(Qiubai)
session.commit()
except Exception as e:
raise e
def dump_record(self):
try:
session = self.db_session()
ret = session.query(Qiubai).all()
print(ret)
except Exception as e:
raise e
def update_reocrd(self):
try:
session = self.db_session()
session.query(Qiubai).filter(Qiubai.userid=='/users/33096359/').update({Qiubai.funny_num:500})
session.commit()
except Exception as e:
raise e
值得主要的是在ORM創建字段映射的時候必須要有一個字段為primary_key, 也就是TableDef.py文件里id的定義
執行結果
從終端打印出來的結果我們可以看到最終插入到數據庫的結構語言依然是INSERT INTO TABLE...,所以ORM只是把數據類型和結構抽象出來了,如果你不想在終端看出這些輸出信息,只需要將「engine = create_engine('sqlite:///qiubai.db', convert_unicode=True, echo=True) 」語句中的echo賦值為false就可以了。
本篇文章到這里就結束了,本文并沒有去驗證mysql數據庫,這個任務留給讀者自己去驗證,我將會把最終的代碼放到我的git上,地址https://github.com/Gavinxyj/Python/tree/master/python_study/Scrapy/modules歡迎大家fork、star。本文只講了SQLAlchemy最基本的用法,更多的用法,想join, 關聯查詢都可以訪問其官網文檔http://docs.sqlalchemy.org/en/latest/。
note: 這里需要提醒大家的是,新學習一個東西的時候,不要一來就想著把它吃透,這樣只會打消你的積極性,就像ORM一樣我本人對它也用的不是很熟悉,只會一些簡單的應用,那是因為我工作中用到它的地方不多,而且ORM有一定的限制性,沒有你直接寫SQL語言來的快和明了。ORM對于復雜的查詢就有些力不從心了。所以學習一個東西我們一定要搞清楚側重點,如果項目上一定要用到ORM那么我回過頭來在深入去學習就是了。