Python:Peewee实践记录

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: Python:Peewee实践记录

安装

$ pip install peewee

将已有数据表转为Model

# 导出数据表为Model
$ python -m pwiz -e mysql -H localhost -p 3306 -u root -P -o -i -t user data > user.py

打印执行SQL


import logging
# 打印日志
logger = logging.getLogger('peewee')
logger.addHandler(logging.StreamHandler())
logger.setLevel(logging.DEBUG)
logger.propagate = False  # 不向上传播

modle和dict转换

from playhouse.shortcuts import model_to_dict, dict_to_model
# 快捷方式类
class ShortcutModel(object):
    @classmethod
    def from_dict(cls, data, ignore_unknown=False):
        return dict_to_model(cls, data=data, ignore_unknown=ignore_unknown)
    def to_dict(self,
                recurse=True,
                backrefs=False,
                only=None,
                exclude=None,
                seen=None,
                extra_attrs=None,
                fields_from_query=None,
                max_depth=None,
                manytomany=False):
        return model_to_dict(
            self,
            recurse=recurse,
            backrefs=backrefs,
            only=only,
            exclude=exclude,
            seen=seen,
            extra_attrs=extra_attrs,
            fields_from_query=fields_from_query,
            max_depth=max_depth,
            manytomany=manytomany
        )

示例


class BaseModel(Model, ShortcutModel):
    class Meta:
        database = db

外键关联操作

1、建表


from datetime import datetime
from peewee import *
db = SqliteDatabase('people.db')
class BaseModel(Model):
    class Meta:
        database = db 
class Person(BaseModel):
    id = IntegerField(primary_key=True)
    name = CharField()
    birthday = DateField()
    class Meta:
        table_name = 'person'
class Pet(BaseModel):
    id = IntegerField(primary_key=True)
    # 一对多: 一个Person -> 多个Pet
    owner = ForeignKeyField(Person, backref='pets')
    name = CharField()
    create_time = DateTimeField(default=datetime.now)
    update_time = DateTimeField(default=datetime.now)
    class Meta:
        table_name = 'pet'
# 创建表
db.create_tables([Person, Pet])

2、初始化数据


def init_data():
    person1 = Person.create(name='Tom', birthday='2020-01-01')
    Pet.create(owner=person1, name='Dog')
    Pet.create(owner=person1, name='Cat')
    person2 = Person.create(name='Jack', birthday='2020-01-02')
    Pet.create(owner=person2, name='Dog')
    Pet.create(owner=person2, name='Cat')
init_data()
"""
sqlite> select * from person;
id          name        birthday  
----------  ----------  ----------
1           Tom         2020-01-01
2           Jack        2020-01-02
sqlite> select * from pet;
id          owner_id    name        create_time          update_time               
----------  ----------  ----------  -------------------  -------------------
1           1           Dog         2021-03-02 10:16:07  2021-03-02 10:16:07
2           1           Cat         2021-03-02 10:16:07  2021-03-02 10:16:07
3           2           Dog         2021-03-02 10:36:01  2021-03-02 10:36:01
4           2           Cat         2021-03-02 10:36:01  2021-03-02 10:36:01

3、N+1问题


3-1、一对多,取列表

for row in Person.select():
   print(row.name)
    for pet in row.pets:
        print(pet.name)
"""
取N+1次 : 先取一次person列表;然后一个Person对象,取一次pets列表
('SELECT "t1"."id", "t1"."name", "t1"."birthday" FROM "person" AS "t1"', [])
('SELECT "t1"."id", "t1"."owner_id", "t1"."name", "t1"."create_time", "t1"."update_time" FROM "pet" AS "t1" WHERE ("t1"."owner_id" = ?)', [1])
('SELECT "t1"."id", "t1"."owner_id", "t1"."name", "t1"."create_time", "t1"."update_time" FROM "pet" AS "t1" WHERE ("t1"."owner_id" = ?)', [2])
"""
# 优化后方法
users = Person.select()
pets = Pet.select()
users_with_pets = prefetch(users, pets)
for row in users_with_pets:
    print(row.name)
    for pet in row.pets:
        print(pet.name)
"""
固定取两次:一次person列表;一次pet列表
('SELECT "t1"."id", "t1"."owner_id", "t1"."name", "t1"."create_time", "t1"."update_time" FROM "pet" AS "t1" WHERE ("t1"."owner_id" IN (SELECT "t2"."id" FROM "person" AS "t2"))', [])
('SELECT "t1"."id", "t1"."name", "t1"."birthday" FROM "person" AS "t1"', [])
"""

3-2、一对一查询,取列表

pets = Pet.select()
for pet in pets:
    print(pet.name, pet.owner.name)
"""
N+1次查询:首先取pet列表;逐个取pet对应的person
('SELECT "t1"."id", "t1"."owner_id", "t1"."name", "t1"."create_time", "t1"."update_time" FROM "pet" AS "t1"', [])
('SELECT "t1"."id", "t1"."name", "t1"."birthday" FROM "person" AS "t1" WHERE ("t1"."id" = ?) LIMIT ? OFFSET ?', [1, 1, 0])
('SELECT "t1"."id", "t1"."name", "t1"."birthday" FROM "person" AS "t1" WHERE ("t1"."id" = ?) LIMIT ? OFFSET ?', [1, 1, 0])
('SELECT "t1"."id", "t1"."name", "t1"."birthday" FROM "person" AS "t1" WHERE ("t1"."id" = ?) LIMIT ? OFFSET ?', [2, 1, 0])
('SELECT "t1"."id", "t1"."name", "t1"."birthday" FROM "person" AS "t1" WHERE ("t1"."id" = ?) LIMIT ? OFFSET ?', [2, 1, 0])
"""
# 优化方法
pets = Pet.select(Pet, Person).join(Person)
for pet in pets:
    print(pet.name, pet.owner.name)
"""
固定取1次
('SELECT 
"t1"."id", "t1"."owner_id", "t1"."name", "t1"."create_time", "t1"."update_time", 
"t2"."id", "t2"."name", "t2"."birthday" 
FROM "pet" AS "t1" INNER JOIN "person" AS "t2" 
ON ("t1"."owner_id" = "t2"."id")', [])
"""

打印SQL执行耗时

from functools import wraps
import time
import logging
from peewee import MySQLDatabase, SENTINEL, Model
logger = logging.getLogger('peewee')
# 计时器
def timer(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        start_time = time.time()
        ret = func(*args, **kwargs)
        end_time = time.time()
        logger.debug("time: %.2f s" % (end_time - start_time))
        return ret
    return wrapper
class CustomMySQLDatabase(MySQLDatabase):
    """
    打印sql执行时间
    see: https://github.com/coleifer/peewee/issues/2370
    """
    @timer
    def execute_sql(self, sql, params=None, commit=SENTINEL):
        return super().execute_sql(sql, params, commit)

支持原样查询返回dict字典对象

使用cator 模块


pip install cator

doc: https://github.com/mouday/cator

from peewee import MySQLDatabase
from cator import DatabaseProxy
db = MySQLDatabase(**config)
db_proxy = DatabaseProxy(db)

单个模型数据转dict字典

from copy import deepcopy
class BaseModel(Model):
    def to_dict(self):
        """model to dict"""
        return deepcopy(self.__data__)
    class Meta:
        database = db
相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
19天前
|
人工智能 数据可视化 数据挖掘
Python:编程语言的魅力与实践
Python:编程语言的魅力与实践
|
24天前
|
机器学习/深度学习 数据采集 Python
Python机器学习面试:Scikit-learn基础与实践
【4月更文挑战第16天】本文探讨了Python机器学习面试中Scikit-learn的相关重点,包括数据预处理(特征缩放、缺失值处理、特征选择)、模型训练与评估、超参数调优(网格搜索、随机搜索)以及集成学习(Bagging、Boosting、Stacking)。同时,指出了常见错误及避免策略,如忽视数据预处理、盲目追求高精度、滥用集成学习等。掌握这些知识点和代码示例,能帮助你在面试中展现优秀的Scikit-learn技能。
34 5
|
7天前
|
Python
在Python中快捷引入缺失包的技巧和实践
在Python中快捷引入缺失包的技巧和实践
11 0
|
7天前
|
人工智能 Python
Python中的反对称矩阵:理论、应用与代码实践
Python中的反对称矩阵:理论、应用与代码实践
24 1
|
8天前
|
机器学习/深度学习 数据采集 数据可视化
利用Python进行历史数据预测:从入门到实践的两个案例分析
利用Python进行历史数据预测:从入门到实践的两个案例分析
21 1
|
8天前
|
测试技术 Python
Python模块化方式编程实践
【5月更文挑战第5天】Python模块化编程提升代码质量,包括:定义专注单一任务的模块;使用`import`导入模块;封装函数和类,明确命名便于重用;避免全局变量降低耦合;使用文档字符串增强可读性;为每个模块写单元测试确保正确性;重用模块作为库;定期维护更新以适应Python新版本。遵循这些实践,可提高代码可读性、重用性和可维护性。
35 2
|
13天前
|
机器学习/深度学习 人工智能 算法
【Python 机器学习专栏】强化学习在游戏 AI 中的实践
【4月更文挑战第30天】强化学习在游戏AI中展现巨大潜力,通过与环境交互和奖励信号学习最优策略。适应性强,能自主探索,挖掘出惊人策略。应用包括策略、动作和竞速游戏,如AlphaGo。Python是实现强化学习的常用工具。尽管面临训练时间长和环境复杂性等挑战,但未来强化学习将与其他技术融合,推动游戏AI发展,创造更智能的游戏体验。
|
13天前
|
机器学习/深度学习 运维 算法
【Python机器学习专栏】异常检测算法在Python中的实践
【4月更文挑战第30天】本文介绍了异常检测的重要性和在不同领域的应用,如欺诈检测和网络安全。文章概述了四种常见异常检测算法:基于统计、距离、密度和模型的方法。在Python实践中,使用scikit-learn库展示了如何实现这些算法,包括正态分布拟合、K-means聚类、局部异常因子(LOF)和孤立森林(Isolation Forest)。通过计算概率密度、距离、LOF值和数据点的平均路径长度来识别异常值。
|
13天前
|
机器学习/深度学习 数据采集 算法
【Python机器学习专栏】支持向量机(SVM)在Python中的实践
【4月更文挑战第30天】SVM是一种高效的监督学习算法,适用于分类和回归,尤其擅长处理高维和非线性问题。通过寻找最大边际超平面来分隔数据,SVM具有高效性、鲁棒性、灵活性和稀疏性等特点。
|
13天前
|
机器学习/深度学习 数据采集 算法
【Python机器学习专栏】自动化特征选择与优化的实践
【4月更文挑战第30天】特征选择在机器学习中至关重要,能降低模型复杂度,提高泛化能力和避免过拟合。本文介绍了自动化特征选择的三种方法:过滤法(如SelectKBest)、包装法(如RFE)和嵌入法(如随机森林)。通过结合这些方法,可实现特征优化,包括数据预处理、初步筛选、模型训练与评估、特征优化和结果验证。自动化特征选择能提升模型性能,适应不同数据集和任务需求,为机器学习项目提供坚实基础。