EXAMPLE FOR PEEWEE 多姿势使用 PEEWEE
使用 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的更多相关文章
- 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 ...
- tornado+peewee-async+peewee+mysql(一)
前言: 需要异步操作MySQL,又要用orm,使用sqlalchemy需要加celery,觉得比较麻烦,选择了peewee-async 开发环境 python3.6.8+peewee-async0.5 ...
- peewee的简单使用
peewee的简单使用 peewee是一个轻量级的ORM框架,peewee完全可以应对个人或企业的中小型项目的Model层,上手容易,功能强大. 一.安装peewee模块 使用pip命令工具安装pee ...
- '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
- [Python]Flask构建网站分析应用
原文Saturday morning hacks: Building an Analytics App with Flask - 由orangleliu友情翻译 ,主要是通过埋点技术来实现web网页的 ...
- Python 操作 MySQL 的5种方式(转)
Python 操作 MySQL 的5种方式 不管你是做数据分析,还是网络爬虫,Web 开发.亦或是机器学习,你都离不开要和数据库打交道,而 MySQL 又是最流行的一种数据库,这篇文章介绍 Pytho ...
- Python 程序员都会喜欢的 6 个库
在编程时,小挫折可能与大难题一样令人痛苦.没人希望在费劲心思之后,只是做到弹出消息窗口或是快速写入数据库.因此,程序员都会喜欢那些能够快速处理这些问题,同时长远来看也很健壮的解决方案. 下面这6个Py ...
- python&mysql
第一种方法,使用 pymysql库 import pymysql.cursors # Connect to the database connection = pymysql.connect(host ...
- Python 操作 MySQL 的5种方式
不管你是做数据分析,还是网络爬虫,Web 开发.亦或是机器学习,你都离不开要和数据库打交道,而 MySQL 又是最流行的一种数据库,这篇文章介绍 Python 操作 MySQL 的5种方式,你可以在实 ...
随机推荐
- 采用BitMap从20亿个int正整数中找出相同的数字
所谓的BitMap就是用一个bit位来标记某个元素所对应的value,而key即是该元素,由于BitMap使用了bit位来存储数据,因此可以大大节省存储空间. public class Test { ...
- IRT模型的参数估计方法(EM算法和MCMC算法)
1.IRT模型概述 IRT(item response theory 项目反映理论)模型.IRT模型用来描述被试者能力和项目特性之间的关系.在现实生活中,由于被试者的能力不能通过可观测的数据进行描述, ...
- BZOJ4327:[JSOI2012]玄武密码(SAM)
Description 在美丽的玄武湖畔,鸡鸣寺边,鸡笼山前,有一块富饶而秀美的土地,人们唤作进香河.相传一日,一缕紫气从天而至,只一瞬间便消失在了进香河中.老人们说,这是玄武神灵将天书藏匿在此. ...
- [HEOI2016/TJOI2016]求和
嘟嘟嘟 好多人(神仙)都说这是NTT例题,然后我就做了-- 做这题,需要一下前置技能: 1.第二类斯特林数 2.NTT 3.没有公式恐惧症 额--不会斯特林数的话(就像我),知道通项公式也行. 这个博 ...
- maven tomcat jstl 异常
在跑一个带jstl的例子的时候,遇到了这样一个错误: org.springframework.web.util.NestedServletException: Handler processing f ...
- Debug Hacks中文版——深入调试的技术和工具
关键词:gdb.strace.kprobe.uprobe.objdump.meminfo.valgrind.backtrace等. <Debugs Hacks中文版——深入调试的技术和工具> ...
- JavaScript输入表单数据正则验证规则
emailNameReg: /^(([a-zA-Z0-9]+\w*((\.\w+)|(-\w+))*[\.-]?[a-zA-Z0-9]+)|([a-zA-Z0-9]))$/, //匹配邮箱名称 ema ...
- Vue文件中引入img 路径写法
把图片路径写在data里面,然后渲染模板的两种方式 方案1.在data使用require将图片进入,写法如下 logo: require('../asset/admin/logo.png') 在模板 ...
- [C#]SQL Server Express LocalDb(SqlLocalDb)的一些体会
真觉得自己的知识面还是比较窄,在此之前,居然还不知道SqlLocalDb. SqlLocalDb是啥?其实就是简化SQL Server的本地数据库,可以这样子说,SQL Server既可以作为远程,也 ...
- Mac 小记 — iTerm2、Zsh、Homebrew
前言 写完 "Ubuntu 自动化配置" 这篇文章后,每次连服务器心情指数都上升好几个百分点,于是想着应该将 macOs 的开发环境也梳理梳理,应该会对开发效率有所增益. 1. i ...