用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='123456!@#,.',
port=3306)
""""
http://docs.peewee-orm.com/en/latest/peewee/playhouse.html#PooledDatabase.manual_close
"""
# MYSQL_URL = \
# 'mysql://admin:6666666!@111.1111.111.111: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:123456lkj@localhost: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:6666666@111.111.111.111: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如果使用的是单个连接在多进程使用中会锁表,上面案列连接方式都是连接池的方式,可以避免在多进程中锁表。