不寫一句mysql操作資料庫才是Python的風格!!3個ORM模型庫示範
阿新 • • 發佈:2019-01-03
用Python可以不用記住任何一句mysql,通過Python使用的ORM模型,簡單來說就是一個庫是一個物件,這個庫裡面的欄位是這個物件的屬性。
ORM解釋:物件關係對映(英語:(Object Relational Mapping,簡稱ORM,或O/RM,或O/R mapping),是一種程式技術,用於實現面向物件程式語言裡不同型別系統的資料之間的轉換 。從效果上說,它其實是建立了一個可在程式語言裡使用的–“虛擬物件資料庫”。簡單來說就是:一個庫是一個物件,這個庫裡面的欄位是這個物件的屬性。
所有mysql語句封裝在了這個物件的方法之中,直接使用相關方法。
介紹三款ORM模型:Peewee、Sqlalchemy、mongoengine以及其中遇到過的莫名問題
其中Peewee、Sqlalchemy是操作mysql和sqlite的,mongoengine是操作mongodb的,這三個庫均可在Python3環境下使用
示例簡介使用ORM模型實現資料庫的增刪改查,以及根據ORM模型對映建立資料庫
1.Peewee
from peewee import *
from playhouse.db_url import connect
from playhouse.pool import PooledMySQLDatabase, PooledDatabase
from playhouse.shortcuts import model_to_dict, dict_to_model
import datetime
"""peewee提供了一個數據庫的封裝模型,playhouse.db_url為其連線的一種方式通過資料庫的指定格式url連線
連線後建立完以後需要模型生成表使用db.connect(),db.create_tables([Person, Pet])"""
blog = PooledMySQLDatabase(
'peewee_test' ,
max_connections=8,
stale_timeout=300,
user='admin',
host='118.24.52.111',
password='[email protected]#,.',
port=3306)
""""
http://docs.peewee-orm.com/en/latest/peewee/playhouse.html#PooledDatabase.manual_close
"""
# MYSQL_URL = \
# 'mysql://admin:[email protected]:3306/peewee_test?charset=utf8'
# blog = connect(MYSQL_URL) # 連線方式一
# 連線方式二
# blog = MySQLDatabase('test', user='root', host='localhost', port=3306)
class BaseModel(Model):
"""基類"""
class Meta:
database = blog
class Test(BaseModel):
"""引數解釋 CharField:字串型別 IntegerField:整型 DateTimeField:時間型別 ForeignKeyField:外來鍵關聯 unique:是否唯一 max_lenth:最大長度 verbose_name:表頭名 null:是都為空 default:預設值"""
name = CharField(unique=True, max_length=50, verbose_name='使用者名稱', null=False, default='你哈')
number = IntegerField(default=0, verbose_name='數字')
update_date = DateTimeField(verbose_name='更新時間', default=datetime.datetime.now)
def close(self):
blog.close()
class Tests(BaseModel):
title = CharField(verbose_name='標題', max_length=64)
site = CharField(verbose_name='字首', max_length=32, unique=True)
article_type = ForeignKeyField(Test)
def create_tables():
"""生成資料表,在資料庫中生成模型對映的表"""
blog.connect()
blog.create_tables([Tests, Test])
blog.close()
def drop_tables():
"""刪除資料表"""
blog.connect()
blog.drop_tables([Tests, Test])
blog.close()
def insert(value):
"""插入資料,或者將屬性作為引數傳入Test(name='name',number=2222)"""
obj = Test()
obj.name = value
obj.number = 99
obj.save()
def updata():
""""更新資料"""
obj = Test.get(Test.name == '更新')
obj.name = '更新完畢'
obj.number = 100
obj.save()
def select_all():
"""查詢所有資料"""
ret = Test.select()
for obj in ret:
print(obj.name)
def select_test():
"""查詢條件資料"""
Test.select().where((Test.name.contains('測試'))) .count() # 包含指定內容返回集合
Test.select().where((Test.name == '測試') | (Test.number == 9999)).first() # 條件或
Test.select().where((Test.name == '測試'), (Test.number == 9999)).first() # 條件並
Test.select().join(Tests).where(Tests.title == 'title').execute() # 關聯查詢
obj = Test.get(Test.name == 'yang')
if obj:
print(obj.name)
else:
print('none have')
def delete_a(i):
"""刪除資料"""
obj = Test.get(Test.id == i)
obj.delete_instance()
def sort():
"""對返回結果列排序"""
set = Test.select().order_by(Test.name)
def to_dict():
"""把模型資料轉為字典物件"""
user = Test.create(username='jack')
u = model_to_dict(user)
return u
def to_model():
"""生成model物件"""
user_data = {'id': 2, 'username': 'charlie'}
user = dict_to_model(Test, user_data)
def close():
db.close()
2.Sqlalchemy
from sqlalchemy import Column, create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from sqlalchemy.types import CHAR, Integer, String, SMALLINT
"""
__tablename__:指定表名Column:行宣告,可指定主鍵Integer:int型別String:字串Float:浮點Boolean:布林DateTime:日期和時間Text:文字LongText:長文字
父類BaseModel會呼叫所有繼承他的子類來生成表結構primary_key:True/False 是否為主鍵unique:是否唯一nullable:是否為空default:預設值"""
MYSQL_SETTING = "mysql://lkj:[email protected]:3306/blog?charset=utf8"
engine = create_engine(
MYSQL_SETTING, pool_size=20, max_overflow=0, pool_recycle=3600)
DBSession = sessionmaker(bind=engine) # 建立DBSession型別:類似資料庫連線
BaseModel = declarative_base()
class Test(BaseModel):
__tablename__ = 'test_table'
id = Column(Integer, primary_key=True)
url = Column(String(128)) # 字串型別
update_time = Column(DateTime, default=datetime.datetime.now())
def to_dict(self): # 將讀取的資料和轉化成字典
return {c.name: getattr(self, c.name, None) for c in self.__table__.columns}
def init_db():
"""生成資料表"""
BaseModel.metadata.create_all(engine)
def drop_db():
"""刪除資料表"""
BaseModel.metadata.drop_all(engine)
if __name__ == '__main__':
init_db()
"""新增資料"""
session = DBSession()
new_data = Test(url='', update_time='')
session.add(new_data) # 新增
session.commit() # 提交
"""查詢資料"""
session = DBSession()
num = session.query(Test).filter(
Test.url == 'url', Test.id == '22').count() # 查詢多條件
session.commit()
session.close()
"""刪除資料"""
session = DBSession()
test = session.query(Test).filter(Test.url == "user1").first()
session.delete(test)
session.commit()
session.close()
"""更新資料"""
session = DBSession()
test = session.query(Test).filter(Test.url == "user1").first()
test.url = 'www.test.com'
session.commit()
session.close()
3.mongoengine
from mongoengine import connect, Document, EmbeddedDocument, DynamicDocument, \
StringField, IntField, FloatField, ListField, EmbeddedDocumentField, DictField
import datetime
connect(db='test',
host="mongodb://admin:[email protected]:27017/?authSource=admin")
if __name__ == '__main__':
"""
簡單使用說明-及其使用案例
Document #定義基本模式繼承該類——適用於儲存字典結構變化不定的資料 EmbeddedDocument #申明內嵌文件 EmbeddedDocumentField #嵌入文件的方法 DynamicDocument # 動態新增欄位方法--適用於儲存固定格式字典並要求驗證的
StringFiled(regex=None,max_length=None,min_lenght=None) #字串型別
IntField(min_value=None,max_value=None) #整數型別
FloatField(min_value=None,max_value=None) #字串型別
BooleanField() #布林型別
DateTimeField() #時間型別
listField() #可以插入列表的
DictField() #字典型別
ReferenceField() #參照型別
SequenceField() #自動產生一個數列、 遞增的
通用引數 default #預設值 也可以是一個函式 可呼叫型別
required #是否必須賦值 true false
primary_key #插入資料是否重複
null #賦值是否可以為空
choices #列表的範圍
unique #當前列只能是唯一的 """
SEX_CHICES = (
('male', '男'),
('female', '女')
)
class Grade(EmbeddedDocument):
"""成績"""
name = StringField(required=True)
score = FloatField(required=True)
class Student(DynamicDocument):
"""學生"""
name = StringField(max_length=32, required=True)
age = IntField(required=True)
sex = StringField(choices=SEX_CHICES, required=True)
grade = FloatField()
address = StringField()
grades = ListField(EmbeddedDocumentField(Grade))
meta = {
'collection': 'students',
# 排序功能,按照分數倒序
'ordering': ['-grade']
}
class TestMongoEngine(object):
def add_one(self):
"""新增一條資料到資料庫"""
yuwen = Grade(
name='語文',
score=90)
shuxue = Grade(
name='數學',
score=100)
stu_obj = Student(
name='張三丰',
age=15,
grades=[yuwen, shuxue],
sex='male'
)
# 直接新增remark欄位是無法新增成功的,需要引入動態新增欄位的方法DynamicDocument
stu_obj.remark = 'remark'
stu_obj.save()
return stu_obj
def get_one(self):
""" 獲取單條資料 """
return Student.objects.first()
def get_more(self):
""" 獲取多條資料 """
# return Student.objects
return Student.objects.all()
def get_one_from_oid(self, oid):
""" 查詢指定id的資料 """
return Student.objects.filter(id=oid).first()
def update(self):
""" 修改資料 """
# 修改一條資料
# res = Student.objects.filter(sex='male').update_one(inc__age=1)
# return res
# 修改多條資料
res = Student.objects.filter(sex='male').update(inc__age=10)
return res
def delete(self):
""" 刪除資料 """
# 刪除一條資料
# res = Student.objects.filter(sex='male').first().delete()
# return res
# 刪除多條資料
res = Student.objects.filter(gender='male').delete()
test = TestMongoEngine()
test.add_one()
注意:peewee和sqlalchemy如果使用的是單個連線在多程序使用中會鎖表,上面案列連線方式都是連線池的方式,可以避免在多程序中鎖表。
ID:Python之戰
|作|者|公(zhong)號:python之戰
專注Python,專注於網路爬蟲、RPA的學習-踐行-總結
喜歡研究和分享技術瓶頸,歡迎關注
獨學而無友,則孤陋而寡聞!