PY => Python-ORM之peewee:模型-字段-索引-約束-事務(一)

前言

去github搜 "python orm",最高star竟然不是sqlalchemy,而是peewee
後來得知peewee,比sqlalchemy簡單好用。值得一學哦!!
我整體感受(peewee像 Django-ORM的分離版,,但比Django-ORM和SqlAlchemy 小巧,簡單,文檔也友好)html

還有一個更重要的感受就是, peewee 的 API方法名 和 SQL語句 的 單詞 基本類似。
例如對比一下(關鍵詞語法都是 update 和 where):python

SQL語句:update Lang set name='Python' where name='Java';
Peewee:Lang.update(name='Python').where(Lang.name == 'Java')

這種良心的API,能夠大大下降咱們的學習成本,還能夠鞏固咱們對SQL的記憶!!!!!!
總官檔地址:http://docs.peewee-orm.com/en...
官方Github地址:https://github.com/coleifer/p...mysql

安裝和導入

pip install peewee
from peewee import *
# peewee的模塊很結構化,都在peewee中,若是懶就都導入進來。 固然你也能夠熟了,按需導入
# 後面無特殊狀況,就都是這樣導入的。我就不提了。

數據庫

postgresql 和 sqlite

peewee 只支持 sqlite, mysql 和 postgresql 數據庫, 若是你有需求用oracle等,請繞行。。。
如需sqlite 和 postgresql,配置請參考 http://docs.peewee-orm.com/en...git

mysql

固然我常常用MySQL,之後的全部都圍繞mysql來說,以下是基本配置github

mysql_db = MySQLDatabase(
    'lin',                 # 數據庫
    user='root',           # 用戶名
    password='123',        # 密碼
    host='IP',             # IP
    port=3306,             # 端口
    charset='utf8mb4'      # 字符集類型, utf8mb4 是 utf8的大哥
)

peewee的mysql引擎默認優先使用pymysql。
若是你沒安裝pymysql, 他就會去尋找 MySQLdb。 都沒有就會報錯。
嗯,都啥年代了,python3的時代,因此咱們用 pymysql模塊便可,若沒安裝,跳出來安裝下便可web

pip install pymysql

既然用的pymysql驅動,MySQLDatabase() 裏面的寫法 和 pymysql對象實例化的參數配置是同樣的。
若是我給的例子的參數不夠用,你能夠來下面的連接本身選吧:https://github.com/PyMySQL/Py...sql

創建數據庫鏈接數據庫

print(mysql_db.connect())

關閉數據庫鏈接segmentfault

print(mysql_db.close())

測試數據庫鏈接是否關閉oracle

mysql_db.is_closed()

列出數據庫的全部表:

mysql_db.get_tables()

列出全部字段的詳細信息:

print(db.get_columns('owner'))    # 假設 owner是表名,下面同理

列出全部主鍵的字段:

print(db.get_primary_keys('owner'))

列出全部索引字段的詳細信息:

print(db.get_indexes('owner'))

列出全部外鍵的字段:

print(db.get_foreign_keys('owner'))

Python 各類 web框架嵌入使用 peewee 案例傳送門:
官檔-Web案例:http://docs.peewee-orm.com/en...

表-記錄-字段

ORM語法 和 數據庫的 (表-記錄-字段)對應關係以下:

ORM結構 數據庫
實例(對象) 記錄
類屬性

默認自增主鍵ID

定義一個類,繼承了peewee模塊的Model類,這個類就能夠看成Model來用了
首先創建一張"空表"

mysql_db = MySQLDatabase('lin_test', user='root', password='123',
                     host='ip', port=3306, charset='utf8mb4')
class Owner(Model):
    class Meta:             
        database=mysql_db   # 這裏是"必須" 要指定的, 指定哪一數據庫
mysql_db.create_tables([Owner])    # 注意,源碼是取出參數遍歷,因此這裏參數用列表

上述代碼就能夠創建一張"空表"。 爲何"空表" 用引號括起來呢??

這是關於peewee orm的機制,"你若不指定(primary key)",它就會"自動"爲你建立一個
"名爲 id", "類型爲 int", 並設置爲 "primary" 的 "自增(auto_increment)" 的字段

但 一旦你把一個自定義的字段,設爲主鍵,默認的id字段就會被覆蓋:

name = CharField(primary_key=True)   # name設爲了主鍵, 原有的默認id就沒了

官檔也說明:若是你想本身創建一個自增主鍵,並覆蓋默認id。你能夠用AutoField字段:

new_id = AutoField()    # 這句話直接就爲你 設置爲 int型 和 主鍵 和自增。 
"這是官檔最推薦覆蓋id的方法,  而不是本身弄一個 Integer,再設主鍵"

自增id就講完了, 不過你是否發現每一個 類下都有

class Meta:
    database= xxx   # 這是爲每張表指定數據庫,必需要指定的。否則它不知道你這個表在哪一個數據庫

既然這樣,若咱們要在一個數據庫中建立不少不少表,那豈不是每次都須要給每張表指定一個數據庫??
就像這樣:

class User(Model):
    class Meta:
        database = mysql_db

class Owner(Model):
    class Meta:
        database = mysql_db

這樣有點煩,但咱們能夠定義一個基類指定好數據庫, 而後其餘子類模型繼承它就行了。

class BaseModel(Model):
    name = CharField(max_length=10)    # 定義一個 name 字段
    class Meta:
        database = mysql_db
        
class User(BaseModel):    # 繼承基類
    pass
class Owner(BaseModel):   # 繼承基類
    pass
    
mysql_db.create_tables([User, Owner])    # 正式建立表, 基類不須要,能夠不放進來

像上述代碼CharField, 更多類型字段定義,官檔給的很詳細了,我再也不贅述了。
官檔-字段-參數:http://docs.peewee-orm.com/en...
但下面我還會挑一些主要經常使用(有一點點點難特別)的說一下。。。

外鍵字段(ForeignKeyField)

普通外鍵

class BaseModel(Model):    # 基類
    name = CharField(max_length=10)
    class Meta:
        database = mysql_db

class Owner(BaseModel):   # 主人類
    pass

class Pet(BaseModel):     # 寵物類
    owner = ForeignKeyField(
        Owner, 
        backref='owner_conn',  # 經過引用名獲取對象。"主人,你能夠經過這個名字調用我"
        on_delete='Cascade',   # 級聯刪除
            # 默認爲None, 這時,你想刪主人是刪不掉的。會報錯。 必須先刪寵物再刪主人。
            # 設爲 Cascade後, 你能夠直接刪主人。 他的寵物也會隨之自動刪除。 這就是級聯刪除
        on_update=Cascade,     # 級聯更新,原理同 on_delete
    )

層級外鍵(一般用於層級分類,自關聯查詢):

class Category(BaseModel):
    name = CharField()
    parent = ForeignKeyField('self', null=True, backref='children') 
    注: "self" 字符串是固定語法, 下一篇還會將,自關聯查詢

日期字段(DateTimeField)

import datetime
......
date_time= DateTimeField(default=datetime.datetime.now)

表屬性(Meta)

表屬性就是能夠 改表名,設置主鍵,聯合主鍵,設置索引,聯合索引等操做。再也不贅述,見官檔。
官檔 Meta: http://docs.peewee-orm.com/en...

索引 和 約束

設置索引有3種方法:

  1. 經過定義字段的參數:
    普通索引

    name = CharField(index=True)

    惟一索引

    name = CharField(unique=True)
  2. 經過定義表屬性Meta:
    聯合惟一索引

    class Meta:
        indexes = (
            (('字段1', '字段2'), True),    # 字段1與字段2總體做爲索引,True 表明惟一索引
            (('字段1', '字段2'), False),   # 字段1與字段2總體做爲索引,False 表明普通索引
        )
    須要注意的是,上面語法,三層元組嵌套, 元組你懂得, 一個元素時須要加個 , 逗號。 別忘了。
  3. 索引API:
    官檔:http://docs.peewee-orm.com/en...

設置約束有2種方法:

  1. 經過定義字段的參數:
    -------一般用來單一字段主鍵:

    name = CharField(primary_key=True)
  2. 經過定義表屬性Meta
    -------一般用做聯合主鍵:

    class Meta:
        primary_key = CompositeKey('字段1', '字段2')
        # primary_key = False      # 也能夠不使用主鍵(不覆蓋,也 取消 建立默認id字段)

事務

支持with上下文語法,支持事務嵌套,注意嵌套事務 只會回滾 離它最近 的一層之間的代碼。
包裹在with語句中的代碼,只要存在異常,就會回滾。嵌套的事務,也是有一處異常,全部層事務都會回滾。
固然你也能夠手動 rollback()來回滾。
嵌套事務示例以下:

with mysql_db.atomic() as transaction1:    # 第一層事務。  atomic(), 固定語法就不說了。 
    User.create(username='Tom')
    with mysql_db.atomic() as transaction2: # 第二層事務
        User.create(username='Jerry')
        User.create(username='Spike')
        transaction2.rollback()            # 就近原則, 第二層的rollback()回滾
    User.create(username='Butch')
    
# 若是真的出現回滾,那麼 從 第二層的 with() 開始算 事務內容, 到 rollback() 結束
#     形象例子: 頂部 麪包片從 第二層的with()開始夾,  底部 麪包片 夾到 rollback()

# 注意一點,雖然是嵌套事務,可是每層with事務都有對應的名字(就是with as 以後變量)。 
# 因此回滾寫在哪層事務裏面, 就要用哪層事務的名字(就近原則)。 否則會報錯的。
# 錯誤實例: 倒數第二行的: transaction2.rollback()  寫成 transaction1.rollback()。 錯誤!

帶有commit()的嵌套事務示例以下:(縮小事務的代碼範圍, 就像 "麪包裏夾的東西變少了" 的意思)

with mysql_db.atomic() as transaction1:      # 第一層事務
    User.create(username='Tom')
    with mysql_db.atomic() as transaction2:  # 第二層事務
        User.create(username='Jerry')
        transaction2.commit()                # 就這裏變了, 插入了一行 commit
        User.create(username='Spike')
        transaction2.rollback()  # rollback()回滾
    User.create(username='Butch')

# commit(),加入了這一行,就意味着 從 這行開始算 回滾內容,到 rollback() 結束
#     形象例子: (頂部 麪包片 從commit() 這裏開始夾, 底部 麪包片 夾到 rollback() )

上面不管哪一個事務例子, 都必須注意:

  1. 每層事務,只管本身層內的 rollback(),纔有效, 不能管其餘層的。
  2. 就算你用 commit() 夾, 若是本身層內沒有 rollback(), 那麼你的 commit()是無效的(夾不住)

事務就差很少這些,官檔還有一些用法和語法,但最終功能結果都是同樣的。選一種(個人例子)就行。
官檔-事務: http://docs.peewee-orm.com/en...

閒雜用法

查看ORM對應的原生SQL語句:

.....ORM語句.sql()       # 後綴 .sql() 打印對應原生sql

執行原生SQL:

# 注意,傳數據用參數,不要用字符串拼接(防SQL注入)
for owner in Owner.raw('select * from owner where name=%s', 'Alice'):
    print(owner.name)

更原生的執行原生SQL:

print(mysql_db.execute_sql('select * from user').fetchall())
# sql,能夠傳位置參數(防注入),就像使用 pymysql同樣。

表更名:

注:我說的更名只是查詢時的臨時名

下一篇文章查詢,會提到 字段更名, 格式:  字段.alias('新字段名')
那表更名也差很少,有2種方式:
    方式1:
        格式: 表類.alias('新表名')
    方式2:
        格式: 新表名 = 表類.alias()

未結束語

本篇寫了一些入門性的模型的創建,數據庫,事務,索引,算是比較基本的。
固然還有更經常使用,更重要的CRUD等,會在下一篇介紹。
下一篇傳送門:https://segmentfault.com/a/11...

相關文章
相關標籤/搜索