前言
在非django框架的ORM當(dāng)中,我們有很多選擇,包括大名鼎鼎的重量級選手sqlalchemy和頗受歡迎的輕量級明星peewee,這2者的的介紹和教程網(wǎng)上到處都是,我這里就不介紹了。因?yàn)橐粋€(gè)偶然的機(jī)會(huì),了解到還有一款輕量級的orm---ponyorm, 官網(wǎng)在此https://ponyorm.org。被它的低學(xué)習(xí)成本和高度抽象化所吸引,本著獨(dú)樂樂不如眾樂樂的原則,特別介紹給大家,??目的是為了大家在使用python的ORM時(shí)有更多的選擇。
首先,這是一款戰(zhàn)斗民族(俄羅斯)的作品,印象中,俄羅斯的東西都是自帶黑魔法屬性的,比如 Kaspersky,nginx之流??????
相對其他的ORM有以下幾個(gè)特點(diǎn):
- 學(xué)習(xí)成本低: 沒有復(fù)雜的聲明方式和眼花繚亂的查詢語法,使用python原生類型定義字段。入門很容易。
- 抽象程度高: 對數(shù)據(jù)庫方面的預(yù)備知識要求很少,使用起來有種黑魔法的感覺,所以也常被成為只有Python魔法少女才知道的ORM
- 使用便捷 相比其他的ORM,pony使用更少的代碼實(shí)現(xiàn)了同樣操作。代碼簡潔,大量的缺省值的設(shè)定非常合理,即使是新手,也能寫出可靠,簡潔的程序。
- 在線的模型編輯器很上手:在編輯上設(shè)計(jì)好模型,直接可以生成代碼和sql語句,對于小型團(tuán)隊(duì)開發(fā),這個(gè)非常提升效率。
好了,下面開始
以下示范以ubuntu 18.04 + python3.6為例,你的系統(tǒng)可能有所不同。請自行調(diào)整。
安裝
pip install pony
建立數(shù)據(jù)庫連接
新建一個(gè) pony_db.py 文件,輸入如下代碼
# -*- coding: utf-8 -*-
from pony.orm import * # 引入
from datetime import date
from datetime import datetime
setting = {
"provider": "mysql", # 聲明數(shù)據(jù)庫種類
"host": "127.0.0.1", # 數(shù)據(jù)庫主機(jī)地址,也可以是域名
"port": 3306, # 端口
"database": "test_db", # 數(shù)據(jù)庫名
"user": "test_01", # 用戶名
"password": "123456", # 密碼
"charset": "utf8mb4", # 字符集
}
db = Database(**setting) # 生成數(shù)據(jù)庫引擎
class Employee(db.Entity):
"""員工類"""
_table_ = "employee"
name = Required(str, max_len=40, unique=False, nullable=False, default="無名氏") # 姓名
age = Optional(int, size=8, nullable=True, default=None) # 年齡
born = Required(date, nullable=False, column="born_date", default=date.today) # ??出生年月日
if __name__ == "__main__":
db.drop_table(table_name="employee", if_exists=True, with_all_data=True) # 刪除表,演示實(shí)體聲明時(shí)用于快速清除舊表
db.generate_mapping(create_tables=True) # 生成實(shí)體,表和映射關(guān)系
pass
setting 是數(shù)據(jù)庫的配置聲明,這點(diǎn)每什么好記說明的,天下sql幾乎都是這么配置的....
class Employee(db.Entity) 這是我們定義的實(shí)體類,這里有一個(gè)要求,db.Entity是實(shí)體模板類,你的實(shí)體類必須繼承db.Entity類。
實(shí)體聲明
下面是字段聲明:
- table : 定義表名
- 字段名: 等號的左邊是字段名,也是數(shù)據(jù)庫的表中對應(yīng)的列的名字,這沒啥好說的,當(dāng)然,如果希望重新定義表中對應(yīng)的列的名字,可以在后面的字段定義中使用 column="new_name"的方法來定義.
- 字段種類: Required和Optional是定義字段的種類的聲明,pony共有 Required,Optional,PrimaryKey ,Set,和Discriminator5種字段的聲明:
- Required 定義一個(gè)創(chuàng)建實(shí)例時(shí),必須提供的字段,注意,這里定義的不是數(shù)據(jù)庫的字段的not null選項(xiàng)
- Optional 定義一個(gè)創(chuàng)建實(shí)例時(shí),可選的字段,注意,這里定義的不是數(shù)據(jù)庫的字段的not null選項(xiàng)
- PrimaryKey 定義一個(gè)主鍵的,由于pony默認(rèn)會(huì)聲明一個(gè)int類型的自增主鍵,所以這個(gè)聲明很少用到
- Set 定義一個(gè)幾何類型的字段,一般用作一對多的多方和多對多情況的聲明。
- Discriminator 定義一個(gè)鑒別字段,用于區(qū)別父類和子類的表,這個(gè)字段在實(shí)體的繼承中我們會(huì)講到,現(xiàn)在請無視。
- 字段類型 字段聲明的第一個(gè)參數(shù)時(shí)字段類型,你可以看到,pony沒有額外定義字段(當(dāng)然也不需要你引入各種String,Integer之類的),直接使用python的原生的字段類型進(jìn)行聲明,這些字段類型包括: int, str, date, datetime等(需要數(shù)據(jù)庫支持),
- 聲明參數(shù) 字段聲明的除第一個(gè)參數(shù)外,都是對聲明的參數(shù)進(jìn)行定義的參數(shù),常用的定義如下:
- max_len: 字段長度, str 類型特有.
- size: 數(shù)字的大小范圍,int類型特有. 8,16,32,64 默認(rèn)32,對應(yīng)mysql定義的 INT(11)
- nullable: 字段的not null選項(xiàng), Optional聲明的字段,這里必須是True,
- default: 字段的默認(rèn)值, nullable=True的字段必須是提供默認(rèn)值,可以時(shí)函數(shù)的返回值
- unique: 是否唯一
生成映射
db.generate_mapping(create_tables=True) # 生成實(shí)體,表和映射關(guān)系
上面這行代碼的意思就是創(chuàng)建表,實(shí)體類的映射關(guān)系 ,這種映射關(guān)系非常重要,pony在啟動(dòng)項(xiàng)目時(shí)會(huì)檢查整個(gè)項(xiàng)目的所有實(shí)體類的映射關(guān)系是否正確。所以,隨著項(xiàng)目的實(shí)體類越來越多,這個(gè)檢查的過程會(huì)越來越漫長。這也是pony為數(shù)不多的缺陷之一吧。
增刪改查
with db_session:
emp = Employee(name="張三", age=12) # 創(chuàng)建一個(gè)實(shí)例
emp_dict = emp.to_dict() # 實(shí)例轉(zhuǎn)字典
print(emp_dict)
emp.set(age=14) # 修改字段
emp = Employee.get(name="張三") # 查找名字叫張三的員工
print(emp.to_dict())
emp.delete() # 刪除實(shí)例
emp = Employee.get(name="張三") # 查找名字叫張三的員工
print(emp)
- db_session: 這是數(shù)據(jù)庫會(huì)話的上下文管理器,操作者必須使用 with 關(guān)鍵字保證對數(shù)據(jù)庫的操作都位于db_session的上下文空間之內(nèi)(偷偷告訴你,更推薦你用@db_session這個(gè)裝飾器哦)
- to_dict: 實(shí)體類的實(shí)例使用此方法輸出dict格式的對象。
- get: 根據(jù)條件,查詢一個(gè)實(shí)例,如果給定的查詢條件返回的查詢結(jié)果不止一個(gè),會(huì)拋出 pony.orm.core.MultipleObjectsFoundError: Multiple objects were found. Use Employee.select(...) to retrieve them 的錯(cuò)誤提醒,如果你需要查詢多個(gè),請使用 select 方法。
- set: 修改實(shí)例的屬性,你可以使用 emp.set(**kwargs)的方法一次修改實(shí)例的多個(gè)屬性
- delete: 沒什么好說的,就是刪除實(shí)例
例子
查詢多個(gè)實(shí)例對象
修改Employee類的代碼,增加一個(gè)find_many的方法
@classmethod
@db_session
def find_many(cls, **kwargs) -> list:
"""
根據(jù)查詢條件查詢多個(gè)實(shí)例對象
:param kwargs: 查詢條件
:return:
"""
handler = select(x for x in cls)
"""注意handler的鏈?zhǔn)秸{(diào)用"""
for name, val in kwargs.items():
handler = handler.where(lambda x: getattr(x, name=name) == val)
result = [x.to_dict() for x in handler]
return result
表里有如下數(shù)據(jù):

查詢
print(Employee.find_many(age=15))
print(Employee.find_many(age=15, name='john'))
[{'id': 2, 'name': 'jack', 'age': 15, 'born': datetime.date(2019, 10, 9)}, {'id': 4, 'name': 'john', 'age': 15, 'born': datetime.date(2019, 10, 10)}]
[{'id': 4, 'name': 'john', 'age': 15, 'born': datetime.date(2019, 10, 10)}]
Process finished with exit code 0
說明:
- @classmethod 類方法的裝飾器。表明此方法可以直接被類對象調(diào)用
- @db_session 是數(shù)據(jù)庫會(huì)話的裝飾器,被此裝飾器裝飾的方法,內(nèi)部的代碼都運(yùn)行在是數(shù)據(jù)庫會(huì)話的上下文之間,這也是pony官方推薦的做法,和使用 with db_session 上下文管理器相比,前者支持事務(wù)的嵌套操作。
- select 查詢方法(最常用的查詢方法之一),一般用于指定條件查詢多個(gè)對象,條件一般用 x for x in cls 這樣的表達(dá)式來指定。有別于需要額外學(xué)習(xí)的查詢語法,這樣的表達(dá)式本身就是python的表達(dá)式,無需額外的學(xué)習(xí)成本,理解起來也很方表,使用表達(dá)式查詢是pony的的亮點(diǎn)之一,也是pony高級抽象化的特征.此函數(shù)返回一個(gè)Query對象,這個(gè)對象本身的絕大多數(shù)方法的執(zhí)行結(jié)果就是返回self。這樣很方便的讓用戶以鏈?zhǔn)秸{(diào)用的方式,拼接一個(gè)復(fù)雜的查詢。而Query對象本身就是一個(gè)可迭代的對象,可以很方便的用[x for x in handler]類似的方法取出結(jié)果集。