使用 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. 【转】编写微信聊天机器人4《聊天精灵WeChatGenius》:实时获取到微信聊天消息,hook数据库插入操作。

    接上篇,使用Xposed来hook微信,找到微信进程:https://blog.csdn.net/weixin_42127613/article/details/81839537 既然已经找到了微信进 ...

  2. 20175310 MyCP(课下作业,必做)

    一.作业要求 编写MyCP.java 实现类似Linux下cp XXX1 XXX2的功能,要求MyCP支持两个参数: java MyCP -tx XXX1.txt XXX2.bin 用来把文本文件(内 ...

  3. CentOS下安装PHP

    今天終於進行了第三次的在linux下的php安裝,在安裝之前我進行了網站訪問測試. 第一步,先查看mysql.apache這兩項系統服務是否已經自動啟動了,chkconfig –list mysql. ...

  4. ML.NET 示例:回归之价格预测

    写在前面 准备近期将微软的machinelearning-samples翻译成中文,水平有限,如有错漏,请大家多多指正. 如果有朋友对此感兴趣,可以加入我:https://github.com/fei ...

  5. 漫画 | Redis常见面试问题(一)

    最近,阿音在为接下来的一场面试做准备,其中的内容包括redis,而且redis是重点内容. Redis是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value数 ...

  6. [C#]关于DataDirectory的一些思考

    笔者在使用Entity Framework中的Scaffolding机制自动创建拓展名为mdf的数据库及表单时,遇到如下的错误: A file activation error occurred. T ...

  7. Python-类的绑定方法与非绑定方法

    类中定义的函数分成两大类 一:绑定方法(绑定给谁,谁来调用就自动将它本身当作第一个参数传入): 绑定到类的方法:用classmethod装饰器装饰的方法. 为类量身定制 类.boud_method() ...

  8. LookupError: Resource averaged_perceptron_tagger not found. Please use the NLTK Downloader to obtain the resource:

    命令行执行 import nltk nltk.download('averaged_perceptron_tagger') 完事

  9. Vicious Keyboard CodeForces - 801A (暴力+模拟)

    题目链接 题意: 给定一个字符串,最多更改一个字符,问最多可以有多少个“VK”子串? 思路: 由于数据量很小,不妨尝试暴力写.首先算出不更改任何字符的情况下有多个VK字串,然后尝试每一次更改一个位置的 ...

  10. Echarts x轴文本内容太长的几种解决方案

    Echarts 标签中文本内容太长的时候怎么办 ? - 1对文本进行倾斜 在xAxis.axisLabe中修改rotate的值 xAxis: { data: ["衬衫11111", ...