Python 數(shù)據(jù)庫操作 SQLAlchemy的示例代碼
程序在運行過程中所有的的數(shù)據(jù)都存儲在內(nèi)存 (RAM) 中,「RAM 是易失性存儲器,系統(tǒng)掉電后 RAM 中的所有數(shù)據(jù)將全部丟失」。在大多數(shù)情況下我們希望程序運行中產(chǎn)生的數(shù)據(jù)能夠長久的保存,此時我們就需要將數(shù)據(jù)保存到磁盤上,無論是保存到本地磁盤,還是通過網(wǎng)絡(luò)保存到服務(wù)器上,最終都會將數(shù)據(jù)寫入磁盤文件。將數(shù)據(jù)保存在磁盤中我們需要面對一個數(shù)據(jù)格式的問題,此時就需要引入數(shù)據(jù)庫操作。
數(shù)據(jù)庫是專門用于數(shù)據(jù)的集中存儲和查詢的軟件,它便于程序保存和讀取數(shù)據(jù),且能夠通過特定的條件查詢指定的數(shù)據(jù)。
Python 的標準數(shù)據(jù)庫接口為 Python DB-API,它為編程人員提供了完善的數(shù)據(jù)庫應(yīng)用標稱接口。但是使用 Python DB-API 需要開發(fā)人員自行去拼接 SQL,并把 SQL 做成模板。此時全靠編程人員來保證系統(tǒng)的安全性,完全有人來保證系統(tǒng)的安全性,不可避免的會出現(xiàn)錯誤,為了減少人為原因產(chǎn)生的錯誤 ORM 框架應(yīng)運而生。
ORM 即 Object-Relational Mapping,把關(guān)系數(shù)據(jù)庫的表結(jié)構(gòu)映射到對象上面。負責這個轉(zhuǎn)換過程的就是 ORM 框架
Python 中的 ORM 框架主要有 SQLObject、Storm、Django's ORM、peewee、SQLALchemy。每種 ORM 框架都有各自的特點和相應(yīng)的應(yīng)用范圍,本文主要介紹 SALALchemy,若你對其他框架感興趣請自行搜索相關(guān)內(nèi)容。
SQLAlchemy 簡介
SQLAlchemy 是一個功能強大的開源 Python ORM 工具包。它提供了 “一個知名企業(yè)級的持久化模式的,專為高效率和高性能的數(shù)據(jù)庫訪問設(shè)計的,改編成一個簡單的 Python 域語言的完整套件”。它采用了數(shù)據(jù)映射模式(像 Java 中的 Hibernate)而不是 Active Record 模式(像Ruby on Rails 的 ORM)。
SQLAlchemy官網(wǎng)。
SQLAlchemy 的優(yōu)缺點:
優(yōu)點:
- 企業(yè)級 API,使得代碼有健壯性和適應(yīng)性。
- 靈活的設(shè)計,使得能輕松完成復(fù)雜的數(shù)據(jù)查詢。
缺點:
- 工作單元概念不常見。
- 重量級 API,導(dǎo)致長學習曲線。
SQLAlchemy 應(yīng)用
以下是一段使用 SQLAlchemy 操作 SQLite 數(shù)據(jù)庫的代碼
# -*- coding:utf-8 -*- from sqlalchemy import ( create_engine, Column, Integer, String, ) from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker engine = create_engine('sqlite:///./sqlalchemy.sqlite', echo=True) Base = declarative_base() class User(Base): __tablename__ = 'users' id = Column(Integer, primary_key=True, autoincrement=True) name = Column(String) fullname = Column(String) nickname = Column(String) def __repr__(self): return "<User(name='%s', fullname='%s', nickname='%s')>" % (self.name, self.fullname, self.nickname) db_session = sessionmaker(bind=engine) session = db_session() Base.metadata.create_all(engine) user1 = User(name='ed', fullname='Ed Jones', nickname='edsnickname') user2 = User(name='wendy', fullname='Wendy Williams', nickname='windy') user3 = User(name='mary', fullname='Mary Contrary', nickname='mary') session.add(user1) session.add(user2) session.add(user3) session.commit() user = session.query(User).filter(User.id<2).all() print(user) user = session.query(User).filter(User.id<=5).all() print(user) user1.name = 'admin' session.merge(user1) user4 = User(name='fred', fullname='Fred Flintstone', nickname='freddy') session.merge(user4) session.query(User).filter(User.id==2).update({'name':'test'}) user = session.query(User).filter(User.id<=5).all() print(user)
在以上代碼中我們完成了一下工作:
- 連接到數(shù)據(jù)庫「本次我們使用的是 SQLite 數(shù)據(jù)庫」。
- 創(chuàng)建數(shù)據(jù)庫表并將其映射到 Python 類上。
- 創(chuàng)建數(shù)據(jù)實例,并將其保存到數(shù)據(jù)庫中。
- 對保存在數(shù)據(jù)庫中的數(shù)據(jù)進行讀取和修改。
導(dǎo)入 SQLAlchemy 模塊并連接到 SQLite 數(shù)據(jù)庫
SQLAlchemy 通過 create_engine 函數(shù)來創(chuàng)建數(shù)據(jù)庫連接。create_engine 函數(shù)的第一個參數(shù)是數(shù)據(jù)了 URL,第二個參數(shù) echo 設(shè)置為 True 表示在程序的運行過程中我們可以在控制臺看到操作所涉及到的 SQL 語句。
在本次示例中我們使用的數(shù)據(jù)庫是 SQLite,你也可以使用其他數(shù)據(jù)庫。只有在調(diào)試狀態(tài)下將 echo 設(shè)置為 True,在生產(chǎn)環(huán)境請將 echo 設(shè)置為 false 或省略 echo 參數(shù)。
engine = create_engine('sqlite:///./sqlalchemy.sqlite', echo=True)
create_engine 返回的是一個 Engine 實例,它指向數(shù)據(jù)庫的一些核心接口。SQLAlchemy會根據(jù)你選擇的數(shù)據(jù)庫配置而調(diào)用對應(yīng)的 DB-API。
create_engine 函數(shù)并會不真正建立數(shù)據(jù)庫的 DB-API 連接,當調(diào)用 Engine.execute() 或 Engine.connect() 方法時才會建立連接。大多數(shù)情況下我們無需關(guān)注 Engine,SQLAlchemy 會幫我們處理。
創(chuàng)建數(shù)據(jù)庫表
將 python 類映射到數(shù)據(jù)庫表上,這個 Python 類需要時一個指定基類的子類,這個基類應(yīng)當含有ORM映射中相關(guān)的類和表的信息。這個基類可以通過 declarative_base 方法來創(chuàng)建。
Base = declarative_base()
在這個示例中使用 Base 基類創(chuàng)建了一個 User 的類來作為數(shù)據(jù)庫表。
class User(Base): __tablename__ = 'users' id = Column(Integer, primary_key=True, autoincrement=True) name = Column(String) fullname = Column(String) nickname = Column(String) def __repr__(self): return "<User(name='%s', fullname='%s', nickname='%s')>" % (self.name, self.fullname, self.nickname)
在 User 類中我們定義了需要映射到數(shù)據(jù)庫表上的屬性,主要包括表名稱、列的類型和名稱等。這個類至少應(yīng)包含一個名為 tablename 的屬性來給出數(shù)據(jù)庫表的名稱,及至少一個給出表的主鍵「primary key」的列。在 User 類中我們定義了表名稱為 users,定義了 id、name、fullname、nickname 四列數(shù)據(jù),并設(shè)置 id 為表的主鍵。
創(chuàng)建完成 User 類后,實際在 SQLite 數(shù)據(jù)庫中并不存在該表,此時需要使用 declarative 基類的 Metadata.create_all 在數(shù)據(jù)庫中創(chuàng)建 users 表,在 create_all 方法中我們需要傳入?yún)?shù) Engine。
通過 Metadata.create_all 傳入的 Engine 參數(shù),SQLAlchemy 自動實現(xiàn)對數(shù)據(jù)庫的連接。
Base.metadata.create_all(engine)
metadata.create_all 方法執(zhí)行完成后在 SQLite 數(shù)據(jù)庫即可查到名稱為 users 的數(shù)據(jù)表。
保存數(shù)據(jù)實例到數(shù)據(jù)庫中
將數(shù)據(jù)保存到數(shù)據(jù)庫中,我們需要 User 的實例和用于操作數(shù)據(jù)的 session。
session 是 ORM 數(shù)據(jù)的接口,可以通過 session 來操作數(shù)據(jù)庫中的數(shù)據(jù)。
使用已經(jīng)定義完成的 User 類將數(shù)據(jù)實例化。
user1 = User(name='ed', fullname='Ed Jones', nickname='edsnickname') user2 = User(name='wendy', fullname='Wendy Williams', nickname='windy') user3 = User(name='mary', fullname='Mary Contrary', nickname='mary')
獲取 session 首先需要使用 sessionmaker 來得到 session 的工廠類,然后通過工廠類來獲取 session。
db_session = sessionmaker(bind=engine) session = db_session()
session 通過 Engine 與數(shù)據(jù)庫進行關(guān)聯(lián)。session 創(chuàng)建完成后并不會立即打開與數(shù)據(jù)庫的連接,只有當我們第一使用 session 是,才會從 Engine 維護的連接池中取出一個連接來操作數(shù)據(jù)庫,這個連接在我們關(guān)閉 session 時會被釋放。
獲取 session 后可以通過 add 和 commit 方法將數(shù)據(jù)保存到數(shù)據(jù)庫中。
session.add(user1) session.add(user2) session.add(user3) session.commit()
對數(shù)據(jù)庫中的數(shù)據(jù)進行查詢和修改
SQLAlchemy 通過 query 來對數(shù)據(jù)進行查詢,可以通過 filter 方法對查詢結(jié)果進行篩選。
user = session.query(User).filter(User.id<2).all() print(user) user = session.query(User).filter(User.id<=5).all() print(user)
以上代碼通過 query 獲取數(shù)據(jù)庫中所有 User 數(shù)據(jù),然后通過 filter 方法篩選出 id 小于 2 和 id 小于等于 5 的數(shù)據(jù)。
數(shù)據(jù)庫的修改可以通過 merge 和 update 來實現(xiàn)
user1.name = 'admin' session.merge(user1) user4 = User(name='fred', fullname='Fred Flintstone', nickname='freddy') session.merge(user4) session.query(User).filter(User.id==2).update({'name':'test'}) user = session.query(User).filter(User.id<=5).all() print(user)
使用 merge 修改數(shù)據(jù),當數(shù)據(jù)中存在該數(shù)據(jù)時修改,不存在是將當前數(shù)據(jù)插入數(shù)據(jù)庫中。
代碼運行結(jié)果
以上示例代碼的運行結(jié)果如下
2019-02-16 21:45:23,919 INFO sqlalchemy.engine.base.Engine SELECT CAST('test plain returns' AS VARCHAR(60)) AS anon_1 2019-02-16 21:45:23,919 INFO sqlalchemy.engine.base.Engine () 2019-02-16 21:45:23,919 INFO sqlalchemy.engine.base.Engine SELECT CAST('test unicode returns' AS VARCHAR(60)) AS anon_1 2019-02-16 21:45:23,919 INFO sqlalchemy.engine.base.Engine () 2019-02-16 21:45:23,920 INFO sqlalchemy.engine.base.Engine PRAGMA table_info("users") 2019-02-16 21:45:23,920 INFO sqlalchemy.engine.base.Engine () 2019-02-16 21:45:23,921 INFO sqlalchemy.engine.base.Engine CREATE TABLE users ( id INTEGER NOT NULL, name VARCHAR, fullname VARCHAR, nickname VARCHAR, PRIMARY KEY (id) ) 2019-02-16 21:45:23,921 INFO sqlalchemy.engine.base.Engine () 2019-02-16 21:45:23,922 INFO sqlalchemy.engine.base.Engine COMMIT 2019-02-16 21:45:23,924 INFO sqlalchemy.engine.base.Engine BEGIN (implicit) 2019-02-16 21:45:23,925 INFO sqlalchemy.engine.base.Engine INSERT INTO users (name, fullname, nickname) VALUES (?, ?, ?) 2019-02-16 21:45:23,925 INFO sqlalchemy.engine.base.Engine ('ed', 'Ed Jones', 'edsnickname') 2019-02-16 21:45:23,926 INFO sqlalchemy.engine.base.Engine INSERT INTO users (name, fullname, nickname) VALUES (?, ?, ?) 2019-02-16 21:45:23,926 INFO sqlalchemy.engine.base.Engine ('wendy', 'Wendy Williams', 'windy') 2019-02-16 21:45:23,926 INFO sqlalchemy.engine.base.Engine INSERT INTO users (name, fullname, nickname) VALUES (?, ?, ?) 2019-02-16 21:45:23,926 INFO sqlalchemy.engine.base.Engine ('mary', 'Mary Contrary', 'mary') 2019-02-16 21:45:23,927 INFO sqlalchemy.engine.base.Engine COMMIT 2019-02-16 21:45:23,929 INFO sqlalchemy.engine.base.Engine BEGIN (implicit) 2019-02-16 21:45:23,929 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.nickname AS users_nickname FROM users WHERE users.id < ? 2019-02-16 21:45:23,929 INFO sqlalchemy.engine.base.Engine (2,) [<User(name='ed', fullname='Ed Jones', nickname='edsnickname')>] 2019-02-16 21:45:23,931 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.nickname AS users_nickname FROM users WHERE users.id <= ? 2019-02-16 21:45:23,931 INFO sqlalchemy.engine.base.Engine (5,) [<User(name='ed', fullname='Ed Jones', nickname='edsnickname')>, <User(name='wendy', fullname='Wendy Williams', nickname='windy')>, <User(name='mary', fullname='Mary Contrary', nickname='mary')>] 2019-02-16 21:45:23,932 INFO sqlalchemy.engine.base.Engine UPDATE users SET name=? WHERE users.id = ? 2019-02-16 21:45:23,932 INFO sqlalchemy.engine.base.Engine ('admin', 1) 2019-02-16 21:45:23,933 INFO sqlalchemy.engine.base.Engine INSERT INTO users (name, fullname, nickname) VALUES (?, ?, ?) 2019-02-16 21:45:23,933 INFO sqlalchemy.engine.base.Engine ('fred', 'Fred Flintstone', 'freddy') 2019-02-16 21:45:23,934 INFO sqlalchemy.engine.base.Engine UPDATE users SET name=? WHERE users.id = ? 2019-02-16 21:45:23,934 INFO sqlalchemy.engine.base.Engine ('test', 2) 2019-02-16 21:45:23,935 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.nickname AS users_nickname FROM users WHERE users.id <= ? 2019-02-16 21:45:23,935 INFO sqlalchemy.engine.base.Engine (5,) [<User(name='admin', fullname='Ed Jones', nickname='edsnickname')>, <User(name='test', fullname='Wendy Williams', nickname='windy')>, <User(name='mary', fullname='Mary Contrary', nickname='mary')>, <User(name='fred', fullname='Fred Flintstone', nickname='freddy')>]
由于我們設(shè)置 create_engine 中 echo 為 True,因此在執(zhí)行結(jié)果中包含了 SQLAlchemy 打印的 SQL 語句,我們可以取消 crete_engine 中的 echo
engine = create_engine('sqlite:///./sqlalchemy.sqlite')
此時的執(zhí)行結(jié)果如下:
[<User(name='ed', fullname='Ed Jones', nickname='edsnickname')>] [<User(name='ed', fullname='Ed Jones', nickname='edsnickname')>, <User(name='wendy', fullname='Wendy Williams', nickname='windy')>, <User(name='mary', fullname='Mary Contrary', nickname='mary')>] [<User(name='admin', fullname='Ed Jones', nickname='edsnickname')>, <User(name='test', fullname='Wendy Williams', nickname='windy')>, <User(name='mary', fullname='Mary Contrary', nickname='mary')>, <User(name='fred', fullname='Fred Flintstone', nickname='freddy')>]
當取消 echo 后,程序運行結(jié)果中原有的 SQL 語句消失。
本文只是對 SQLAlchemy 的使用進行簡單的介紹,SQLAlchemy 本身還有很多特性和運用方法我們可以共同探討。
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
- Python使用pyodbc訪問數(shù)據(jù)庫操作方法詳解
- Python實現(xiàn)的連接mssql數(shù)據(jù)庫操作示例
- Python編程實戰(zhàn)之Oracle數(shù)據(jù)庫操作示例
- Python使用sqlalchemy模塊連接數(shù)據(jù)庫操作示例
- Python MySQL數(shù)據(jù)庫連接池組件pymysqlpool詳解
- Python使用pymysql從MySQL數(shù)據(jù)庫中讀出數(shù)據(jù)的方法
- Python 3.x 連接數(shù)據(jù)庫示例(pymysql 方式)
- python3.6使用pymysql連接Mysql數(shù)據(jù)庫
- Python的Flask框架中使用Flask-SQLAlchemy管理數(shù)據(jù)庫的教程
- Python的Django框架中使用SQLAlchemy操作數(shù)據(jù)庫的教程
- Python使用Flask-SQLAlchemy連接數(shù)據(jù)庫操作示例
- python數(shù)據(jù)庫操作mysql:pymysql、sqlalchemy常見用法詳解
相關(guān)文章
Python?裝飾器常用的創(chuàng)建方式及源碼示例解析
裝飾器(decorator)是一種高級Python語法,可以對一個函數(shù)、方法或者類進行加工,這篇文章主要介紹了Python?裝飾器常用的創(chuàng)建方式及解析,需要的朋友可以參考下2022-04-04python調(diào)用dll出現(xiàn)精度問題解決
本文主要介紹了python調(diào)用dll出現(xiàn)精度問題解決,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2023-02-02解決Django Static內(nèi)容不能加載顯示的問題
今天小編就為大家分享一篇解決Django Static內(nèi)容不能加載顯示的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-07-07