使用 PEEWEE 断断续续的差不多已经三个年头了,但是没有像这次使用这么多的特性和功能,所以这次一并记录一下,需要注意的地方和一些使用细节,之后使用起来可能会更方便。

因为是使用的 SQLAchedemy 的引擎,所以增删改查的语法也很像。

查找方法

cls 这里默认指类对象了

查找单个会使用:

cls.get_one(cls.user_id == user_id)

查找批量可以使用:

cls.select().where(cls.user_id == user_id)

批量查找会返回一个数组,可以使用 for in 语句迭代他们。另外需要注意的一点是,如果需要指定查询的内容可以使用:

cls.select(cls.user_id, cls.id).where(cls.user_id == user_id)

里面也可以使用一些聚合函数例如 count  sum 之类的

cls.select(cls.user_id, fn.COUNT(cls.id).alias('hahah')).where(xxxxx)

添加数据方法

User.create(username='Charlie')

类似使用这种语法,我们可以构造一个key: value 的字典,最后使用

User.create(**data)

一并写入即可。

注意,使用这种方法的返回值是有几条结果受到了影响。如果我们像知道添加了之后的主键 id 可以使用:

User.insert(username='Mickey').execute()

这种插入方法会返回 主键值。一般我们可以认为是 id 值。

批量插入方法

批量插入提供了很多种方法:

data_source = [
{'field1': 'val1-1', 'field2': 'val1-2'},
{'field1': 'val2-1', 'field2': 'val2-2'},
# ...
] for data_dict in data_source:
MyModel.create(**data_dict)

写到一个数组中,然后遍历一个一个插。。。亲测这是最慢的,如果另外几种行得通最好不要用。

with db.atomic():
for data_dict in data_source:
MyModel.create(**data_dict)

修改刚才那种方法的提交模式,让他们在同一个事务里面提交以此来提高速度。这次我的场景其实对插入速度要求很高,尝试了这种方法,但是我每次插入500条虽然速度是提高了不少,但是当我写到2000条的时候就报了一个事务的错误,在网上搜了一下也无果。所以对于量很大的插入,感觉这个方法也不是很好。。。或者欢迎来人指出的我使用姿势的问题。

另外的姿势:

# Fastest.
MyModel.insert_many(data_source).execute() # Fastest using tuples and specifying the fields being inserted.
fields = [MyModel.field1, MyModel.field2]
data = [('val1-1', 'val1-2'),
('val2-1', 'val2-2'),
('val3-1', 'val3-2')]
MyModel.insert_many(data, fields=fields).execute() # You can, of course, wrap this in a transaction as well:
with db.atomic():
MyModel.insert_many(data, fields=fields).execute()

第一种方法就是一个 list 然后里面是字典,只要你能保证这个结构,就可以进行批量插入。亲测速度不错,也没有遇到事务报错的问题。这次使用的就是这个方法,下面第二种第三种写法,感觉构造起来不是很友好。所以没有使用,有兴趣的朋友可以尝试。

修改数据方法

修改数据方法提供了普通的更新和原子更新方法。

普通的更新:

>>> today = datetime.today()
>>> query = Tweet.update(is_published=True).where(Tweet.creation_date < today)
>>> query.execute() # Returns the number of rows that were updated.
4

原子更新:

>>> query = Stat.update(counter=Stat.counter + 1).where(Stat.url == request.url)
>>> query.execute()
>>> subquery = Tweet.select(fn.COUNT(Tweet.id)).where(Tweet.user == User.id)
>>> update = User.update(num_tweets=subquery)
>>> update.execute()

还有一种 upsert 操作。如果指定键存在就执行更新操作,如果不存在执行插入操作。

下面提供了两种写法。

# Insert or update the user. The "last_login" value will be updated
# regardless of whether the user existed previously.
user_id = (User
.replace(username='the-user', last_login=datetime.now())
.execute()) # This query is equivalent:
user_id = (User
.insert(username='the-user', last_login=datetime.now())
.on_conflict_replace()
.execute())

另外 mysql 还提供了一种独有的语法 ON DUPLICATE KEY UPDATE 可以使用以下方法实现。

class User(Model):
username = TextField(unique=True)
last_login = DateTimeField(null=True)
login_count = IntegerField() # Insert a new user.
User.create(username='huey', login_count=0) # Simulate the user logging in. The login count and timestamp will be
# either created or updated correctly.
now = datetime.now()
rowid = (User
.insert(username='huey', last_login=now, login_count=1)
.on_conflict(
preserve=[User.last_login], # Use the value we would have inserted.
update={User.login_count: User.login_count + 1})
.execute())

上面的例子要注意 username 申明的 unique=true 如果模型上不申明可能会报错。

删除方法

删除方法跟普通的 orm 似乎设计得很像。要么获得一个 instance 然后调用 delete() 方法进行删除,要么就是直接条件查询直接删除,来看例子。

>>> user = User.get(User.id == 1)
>>> user.delete_instance() # Returns the number of rows deleted.

批量删除

>>> query = Tweet.delete().where(Tweet.creation_date < one_year_ago)
>>> query.execute() # Returns the number of rows deleted.
7

联表查询方法

query = (Tag
.select()
.join(PhotoTag)
.join(Photo)
.group_by(Tag)
.having(fn.Count(Photo.id) > 5))

其实 peewee 提供的方法就非常独立和干净。你可以按照自己的需求构造足够复杂的 sql ,语句也比较清晰。需要注意的是这几点,在联表查询的时候,select()函数里面需要写上自己需要的返回值,否则联表之后会发现竟然还是只有自己 cls 的字段,就会感觉到很疑惑。

query = User\
.select(User, UserDatum, Card7daysRecv)\
.join(UserDatum, JOIN.LEFT_OUTER, on=(User.uid == UserDatum.user_id))\
.join(Card7daysRecv, JOIN.LEFT_OUTER, on=(User.uid == Card7daysRecv.receive_uid)).order_by(User.create_time).limit(limit).offset(offset)

另外一些使用的时候需要注意的问题

在遇到复杂查询的时候有个不可缺少的工具就是打印以下自己的 orm 究竟构造了什么语句。可以使用 query.sql() 方便的看到。

谈下在 model 构造上的时候遇到的一些问题。

如果要往模型里面插数据,建议最好还是指定好 主键和默认值,以免读取模型的时候报错。需要的字段一定要在模型里面写上,否则拿的时候会发现没有这个字段。

class HdNewUserInfo(AliyunModel):
class Meta:
db_table = 'hd_new_user_info'
_version = 0 user_id = CharField(64, default='', primary_key=True)
phone = CharField(32, default='')
phone_province = CharField(64, default='')
phone_city = CharField(64, default='')
phone_community_id = CharField(32, default='')
name = CharField(64, default='')
head_img = CharField(1024, default='')
student_no = CharField(36, default='')

这里面其实还有个问题,我们在 mysql 5.6 5.7 还是会经常使用 timestamp 字段,并且使用它的默认当前时间字段。这在 peewee 里面的映射好像有点问题,如果我们使用 peewee 里面的 TimestampField 申明我们的字段,在读区和操作比较的时候可能会出现一些问题,会被调试需要的是 float 字段。但是 如果你使用 time.time() 类似的 float 去比较也会报出别的错误。但是使用 DateTimeField 却没有这个问题,所以我选择使用了 DateTimeField。

另外还有一个 database gone away 的问题。注意构造好自己的 db

class Off(Model):
class Meta:
database = db.offline_db_08_yanzhi @classmethod
def get_one(cls, *query, **kwargs):
try:
return cls.get(*query, **kwargs)
except DoesNotExist:
return None

初始化自己的 db。并且构造一个可以重连的 retrydb

class RetryOperationalError(object):

    def execute_sql(self, sql, params=None, commit=True):
try:
cursor = super(RetryOperationalError, self).execute_sql(
sql, params, commit)
except OperationalError:
if not self.is_closed():
self.close()
with __exception_wrapper__:
cursor = self.cursor()
cursor.execute(sql, params or ())
if commit and not self.in_transaction():
self.commit()
return cursor class MyRetryDB(RetryOperationalError, MySQLDatabase):
pass

这次玩数据暂时就遇到这些问题,以后再来补充。

Reference:

https://github.com/coleifer/peewee/issues/114  Print SQL queries

http://docs.peewee-orm.com/en/latest/peewee/query_examples.html#retrieve-the-start-times-of-members-bookings  联表查 example

https://stackoverflow.com/questions/15559468/why-is-peewee-including-the-id-column-into-the-mysql-select-query  column into id 1 报错解决

EXAMPLE FOR PEEWEE 多姿势使用 PEEWEE的更多相关文章

  1. Python’s SQLAlchemy vs Other ORMs[转发 4]peewee

    peewee peewee is a small, expressive ORM. Compared to other ORMs, peewee focuses on the principal of ...

  2. tornado+peewee-async+peewee+mysql(一)

    前言: 需要异步操作MySQL,又要用orm,使用sqlalchemy需要加celery,觉得比较麻烦,选择了peewee-async 开发环境 python3.6.8+peewee-async0.5 ...

  3. peewee的简单使用

    peewee的简单使用 peewee是一个轻量级的ORM框架,peewee完全可以应对个人或企业的中小型项目的Model层,上手容易,功能强大. 一.安装peewee模块 使用pip命令工具安装pee ...

  4. 'ModelOptions' object has no attribute 'get_field_names

    peewee安装时随意了点.装了2.8.0的. 倒回到2.6.0就好了. sudo pip uninstall peewee sudo pip install peewee==2.6.0

  5. [Python]Flask构建网站分析应用

    原文Saturday morning hacks: Building an Analytics App with Flask - 由orangleliu友情翻译 ,主要是通过埋点技术来实现web网页的 ...

  6. Python 操作 MySQL 的5种方式(转)

    Python 操作 MySQL 的5种方式 不管你是做数据分析,还是网络爬虫,Web 开发.亦或是机器学习,你都离不开要和数据库打交道,而 MySQL 又是最流行的一种数据库,这篇文章介绍 Pytho ...

  7. Python 程序员都会喜欢的 6 个库

    在编程时,小挫折可能与大难题一样令人痛苦.没人希望在费劲心思之后,只是做到弹出消息窗口或是快速写入数据库.因此,程序员都会喜欢那些能够快速处理这些问题,同时长远来看也很健壮的解决方案. 下面这6个Py ...

  8. python&mysql

    第一种方法,使用 pymysql库 import pymysql.cursors # Connect to the database connection = pymysql.connect(host ...

  9. Python 操作 MySQL 的5种方式

    不管你是做数据分析,还是网络爬虫,Web 开发.亦或是机器学习,你都离不开要和数据库打交道,而 MySQL 又是最流行的一种数据库,这篇文章介绍 Python 操作 MySQL 的5种方式,你可以在实 ...

随机推荐

  1. UVA1347-Tour(动态规划基础)

    Problem UVA1347-Tour Accept: 667  Submit: 3866Time Limit: 3000 mSec Problem Description John Doe, a ...

  2. 转://Oracle 复合压缩索引场景及性能对比

    摘要:今天为什么提到这个话题,出于一个偶然,一个同事在优化新开发的系统时向我请教如何添加复合压缩索引的问题.我总结了一下,问题有三. 第一:需不需要压缩 第二:对第几列压缩 第三:性能对比,选出最优 ...

  3. 转:// LINUX下为ORACLE数据库设置大页--hugepage

    一.在解释什么情况下需要开启大页和为啥需要开启大页前先了解下Linux下页的相关的知识:以下的内容是基于32位的系统,4K的内存页大小做出的计算1)目录表,用来存放页表的位置,共包含1024个目录en ...

  4. 【CTF杂项】常见文件文件头文件尾格式总结及各类文件头

    文件头文件尾总结 JPEG (jpg), 文件头:FFD8FF 文件尾:FF D9PNG (png), 文件头:89504E47 文件尾:AE 42 60 82GIF (gif), 文件头:47494 ...

  5. sklearn 模型选择和评估

    一.模型验证方法如下: 通过交叉验证得分:model_sleection.cross_val_score(estimator,X) 对每个输入数据点产生交叉验证估计:model_selection.c ...

  6. [MicroPython]TurniBit开发板DIY自动窗帘模拟系统

    一.准备工作 üTurnipBit 开发板 一块 ü下载数据线 一条 ü微型步进电机(28BYJ-48) 一个 ü步进电机驱动板(ULN2003APG) 一块 ü光敏传感器 一个 üTurnipBit ...

  7. face recognition[MobiFace]

    本文来自<MobiFace: A Lightweight Deep Learning Face Recognition on Mobile Devices>,时间线为2018年11月.是作 ...

  8. UITextFieldDelegate 说明

    - (BOOL)textFieldShouldBeginEditing:(UITextField *)textField  // 返回YES,允许进行编辑 - (void)textFieldDidBe ...

  9. git 的 cat-file 的命令用法

    命令选项 git cat-file 的命令显示版本库对象的内容.类型.及大小信息. -t  Instead of the content, show the object type identifie ...

  10. 《Spring Boot 入门及前后端分离项目实践》系列介绍

    课程计划 课程地址点这里 本课程是一个 Spring Boot 技术栈的实战类课程,课程共分为 3 个部分,前面两个部分为基础环境准备和相关概念介绍,第三个部分是 Spring Boot 项目实践开发 ...