用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如果使用的是单个连接在多进程使用中会锁表,上面案列连接方式都是连接池的方式,可以避免在多进程中锁表。