python轻量级ORM---peewee
版权声明:本文为博主原创文章,未经博主同意不得转载。 https://blog.csdn.net/q454684431/article/details/31742367
peewee是一个轻量级的ORM。用的是大名鼎鼎的sqlalchemy内核,採用纯python编写,显得十分轻便。为了兴许方便查看,在这里简单记录下~~
peewee不仅轻量级。还提供了多种数据库的訪问,如SqliteDatabase(file
or memory)、MYSQLDatabase、PostgresqlDatabase;
接下来就从API上路吧~~~
1.
class fn---To express functions in peewee, use the fn object。
For example:
| Peewee expression | Equivalent SQL |
|---|---|
| fn.Count(Tweet.id).alias('count') | Count(t1."id") AS count |
| fn.Lower(fn.Substr(User.username, 1, 1)) | Lower(Substr(t1."username", 1, 1)) |
| fn.Rand().alias('random') | Rand() AS random |
| fn.Stddev(Employee.salary).alias('sdv') | Stddev(t1."salary") AS sdv |
Functions can be used as any part of a query:
select
where
group_by
order_by
having
update query
insert query
# user's username starts with a 'g' or a 'G':
fn.Lower(fn.Substr(User.username, 1, 1)) == 'g'
2.表达式支持的操作符
a:
| Comparison | Meaning |
|---|---|
| == | x equals y |
| < | x is less than y |
| <= | x is less than or equal to y |
| > | x is greater than y |
| >= | x is greater than or equal to y |
| != | x is not equal to y |
| << | x IN y, where y is a list or query |
| >> | x IS y, where y is None/NULL |
| % | x LIKE y where y may contain wildcards |
| ** | x ILIKE y where y may contain wildcards |
b:
Employee.select().where(Employee.salary.between(50000, 60000))
note: 因为sqlite的like函数在默认下是大写和小写不敏感的。假设想实现大写和小写搜索,须要用’*‘做通配符。
3.实现用户自己定义的操作
Here is how you might add support for modulo and regexp in SQLite:
from peewee import *
from peewee import Expression # the building block for expressions
OP_MOD = 'mod'
OP_REGEXP = 'regexp'
def mod(lhs, rhs):
return Expression(lhs, OP_MOD, rhs)
def regexp(lhs, rhs):
return Expression(lhs, OP_REGEXP, rhs)
SqliteDatabase.register_ops({OP_MOD: '%', OP_REGEXP: 'REGEXP'}) #加入 %、regexp操作
Now you can use these custom operators to build richer queries:
# users with even ids
User.select().where(mod(User.id, 2) == 0)
# users whose username starts with a number
User.select().where(regexp(User.username, '[0-9].*'))
4.Joining tables
There are three types of joins by default:
JOIN_INNER (default)
JOIN_LEFT_OUTER
JOIN_FULL
Here are some examples:
User.select().join(Blog).where(
(User.is_staff == True) & (Blog.status == LIVE))
Blog.select().join(User).where(
(User.is_staff == True) & (Blog.status == LIVE))
subquery:
staff = User.select().where(User.is_staff == True)
Blog.select().where(
(Blog.status == LIVE) & (Blog.user << staff))
补充:在没有通过ForeignKeyField产生外键的多个models中,也能够做join操作。如:
# No explicit foreign key between these models.
OutboundShipment.select().join(InboundShipment, on=(
OutboundShipment.barcode == InboundShipment.barcode))
5.Performing advanced queries
To create arbitrarily complex queries, simply use python’s bitwise “and” and “or” operators:
sq = User.select().where(
(User.is_staff == True) |
(User.is_superuser == True))
The WHERE clause will look something like:
WHERE (is_staff = ? OR is_superuser = ?)
In order to negate an expression, use the bitwise “invert” operator:
staff_users = User.select().where(User.is_staff == True)
Tweet.select().where(
~(Tweet.user << staff_users))
This query generates roughly the following SQL:
SELECT t1.* FROM blog AS t1
WHERE
NOT t1.user_id IN (
SELECT t2.id FROM user AS t2 WHERE t2.is_staff = ?)
Rather complex lookups are possible:
sq = User.select().where(
((User.is_staff == True) | (User.is_superuser == True)) &
(User.join_date >= datetime(2009, 1, 1))
This generates roughly the following SQL:
SELECT * FROM user
WHERE (
(is_staff = ? OR is_superuser = ?) AND
(join_date >= ?
))
6.Aggregating records
#Suppose you have some users and want to get a list of them along with the count of tweets each has made. First I will show y#ou the shortcut:
query = User.select().annotate(Tweet)
This is equivalent to the following:
query = User.select(
User, fn.Count(Tweet.id).alias('count')
).join(Tweet).group_by(User)
#You can also specify a custom aggregator. In the following query we will annotate the users with the date of their most rece#nt tweet:
query = User.select().annotate(
Tweet, fn.Max(Tweet.created_date).alias('latest'))
#Conversely, sometimes you want to perform an aggregate query that returns a scalar value, like the “max id”. Queries like #this can be executed by using the aggregate() method:
most_recent_tweet = Tweet.select().aggregate(fn.Max(Tweet.created_date))
7.Window functions
#peewee comes with basic support for SQL window functions, which can be created by calling fn.over() and passing in your parti#tioning or ordering parameters.
# Get the list of employees and the average salary for their dept.
query = (Employee
.select(
Employee.name,
Employee.department,
Employee.salary,
fn.Avg(Employee.salary).over(
partition_by=[Employee.department]))
.order_by(Employee.name))
# Rank employees by salary.
query = (Employee
.select(
Employee.name,
Employee.salary,
fn.rank().over(
order_by=[Employee.salary])))
有待继续考究啊~~ click me:<a target=_blank href="http://www.postgresql.org/docs/9.1/static/tutorial-window.html">postgresql docs.</a>
8.How to optimize a query?
#We can do this pretty easily:
for tweet in Tweet.select().order_by(Tweet.created_date.desc()).limit(10):
print '%s, posted on %s' % (tweet.message, tweet.user.username)
#Looking at the query log, though, this will cause 11 queries:
#1 query for the tweets
#1 query for every related user (10 total)
#This can be optimized into one query very easily, though:
tweets = Tweet.select(Tweet, User).join(User)
for tweet in tweets.order_by(Tweet.created_date.desc()).limit(10):
print '%s, posted on %s' % (tweet.message, tweet.user.username)
#Will cause only one query that looks something like this:
SELECT t1.id, t1.message, t1.user_id, t1.created_date, t2.id, t2.username
FROM tweet AS t1
INNER JOIN user AS t2
ON t1.user_id = t2.id
ORDER BY t1.created_date desc
LIMIT 10
<span style="font-family: Consolas, 'Andale Mono WT', 'Andale Mono', 'Lucida Console', 'Lucida Sans Typewriter', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Liberation Mono', 'Nimbus Mono L', Monaco, 'Courier New', Courier, monospace; font-size: 18px; line-height: 1.5; background-color: rgb(255, 255, 255);"></span><h3 style="box-sizing: border-box; margin-top: 0px; font-family: 'Roboto Slab', ff-tisa-web-pro, Georgia, Arial, sans-serif; font-size: 20px; color: rgb(64, 64, 64); background-color: rgb(252, 252, 252);">Speeding up simple select queries---naive</h3><p style="box-sizing: border-box; line-height: 24px; margin-top: 0px; margin-bottom: 24px; font-size: 16px; color: rgb(64, 64, 64); font-family: Lato, proxima-nova, 'Helvetica Neue', Arial, sans-serif; background-color: rgb(252, 252, 252);">Complex select queries can get a performance boost (especially when iterating over large result sets) by calling <a target=_blank class="reference internal" href="http://peewee.readthedocs.org/en/latest/peewee/api.html#SelectQuery.naive" title="SelectQuery.naive" style="box-sizing: border-box; color: rgb(155, 89, 182); text-decoration: none;"><tt class="xref py py-meth docutils literal" style="box-sizing: border-box; font-family: Consolas, 'Andale Mono WT', 'Andale Mono', 'Lucida Console', 'Lucida Sans Typewriter', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Liberation Mono', 'Nimbus Mono L', Monaco, 'Courier New', Courier, monospace; font-size: 12px; white-space: nowrap; max-width: 100%; background-color: rgb(255, 255, 255); border: 1px solid rgb(225, 228, 229); padding: 0px 5px; color: rgb(41, 128, 185); overflow-x: auto; background-position: initial initial; background-repeat: initial initial;"><span class="pre" style="box-sizing: border-box;"><strong>naive()</strong></span></tt></a>. This method simply patches all attributes directly from the cursor onto the model. For simple queries this will have no noticeable impact. The <span style="box-sizing: border-box;">only</span> difference is when multiple tables are queried, as in the previous example:</p><div class="highlight-python" style="box-sizing: border-box; border: 1px solid rgb(225, 228, 229); padding: 0px; overflow-x: auto; margin: 1px 0px 24px; color: rgb(64, 64, 64); font-family: Lato, proxima-nova, 'Helvetica Neue', Arial, sans-serif; font-size: 16px;"><div class="highlight" style="box-sizing: border-box; border: none; padding: 0px; overflow-x: auto; background-image: none; margin: 0px; background-position: initial initial; background-repeat: initial initial;"><pre style="box-sizing: border-box; font-family: Consolas, 'Andale Mono WT', 'Andale Mono', 'Lucida Console', 'Lucida Sans Typewriter', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Liberation Mono', 'Nimbus Mono L', Monaco, 'Courier New', Courier, monospace; font-size: 12px; margin-top: 0px; margin-bottom: 0px; padding: 12px; line-height: 1.5; overflow: auto;"><span class="c" style="box-sizing: border-box; color: rgb(153, 153, 136); font-style: italic;"># above example</span>
<span class="n" style="box-sizing: border-box; color: rgb(51, 51, 51);">tweets</span> <span class="o" style="box-sizing: border-box; font-weight: bold;">=</span> <span class="n" style="box-sizing: border-box; color: rgb(51, 51, 51);">Tweet</span><span class="o" style="box-sizing: border-box; font-weight: bold;">.</span><span class="n" style="box-sizing: border-box; color: rgb(51, 51, 51);">select</span><span class="p" style="box-sizing: border-box;">(</span><span class="n" style="box-sizing: border-box; color: rgb(51, 51, 51);">Tweet</span><span class="p" style="box-sizing: border-box;">,</span> <span class="n" style="box-sizing: border-box; color: rgb(51, 51, 51);">User</span><span class="p" style="box-sizing: border-box;">)</span><span class="o" style="box-sizing: border-box; font-weight: bold;">.</span><span class="n" style="box-sizing: border-box; color: rgb(51, 51, 51);">join</span><span class="p" style="box-sizing: border-box;">(</span><span class="n" style="box-sizing: border-box; color: rgb(51, 51, 51);">User</span><span class="p" style="box-sizing: border-box;">)</span>
<span class="k" style="box-sizing: border-box; font-weight: bold;">for</span> <span class="n" style="box-sizing: border-box; color: rgb(51, 51, 51);">tweet</span> <span class="ow" style="box-sizing: border-box; font-weight: bold;">in</span> <span class="n" style="box-sizing: border-box; color: rgb(51, 51, 51);">tweets</span><span class="o" style="box-sizing: border-box; font-weight: bold;">.</span><span class="n" style="box-sizing: border-box; color: rgb(51, 51, 51);">order_by</span><span class="p" style="box-sizing: border-box;">(</span><span class="n" style="box-sizing: border-box; color: rgb(51, 51, 51);">Tweet</span><span class="o" style="box-sizing: border-box; font-weight: bold;">.</span><span class="n" style="box-sizing: border-box; color: rgb(51, 51, 51);">created_date</span><span class="o" style="box-sizing: border-box; font-weight: bold;">.</span><span class="n" style="box-sizing: border-box; color: rgb(51, 51, 51);">desc</span><span class="p" style="box-sizing: border-box;">())</span><span class="o" style="box-sizing: border-box; font-weight: bold;">.</span><span class="n" style="box-sizing: border-box; color: rgb(51, 51, 51);">limit</span><span class="p" style="box-sizing: border-box;">(</span><span class="mi" style="box-sizing: border-box; color: rgb(0, 153, 153);">10</span><span class="p" style="box-sizing: border-box;">):</span>
<span class="k" style="box-sizing: border-box; font-weight: bold;">print</span> <span class="s" style="box-sizing: border-box; color: rgb(221, 17, 68);">'</span><span class="si" style="box-sizing: border-box; color: rgb(221, 17, 68);">%s</span><span class="s" style="box-sizing: border-box; color: rgb(221, 17, 68);">, posted on </span><span class="si" style="box-sizing: border-box; color: rgb(221, 17, 68);">%s</span><span class="s" style="box-sizing: border-box; color: rgb(221, 17, 68);">'</span> <span class="o" style="box-sizing: border-box; font-weight: bold;">%</span> <span class="p" style="box-sizing: border-box;">(</span><span class="n" style="box-sizing: border-box; color: rgb(51, 51, 51);">tweet</span><span class="o" style="box-sizing: border-box; font-weight: bold;">.</span><span class="n" style="box-sizing: border-box; color: rgb(51, 51, 51);">message</span><span class="p" style="box-sizing: border-box;">,</span> <span class="n" style="box-sizing: border-box; color: rgb(51, 51, 51);">tweet</span><span class="o" style="box-sizing: border-box; font-weight: bold;">.</span><span class="n" style="box-sizing: border-box; color: rgb(51, 51, 51);">user</span><span class="o" style="box-sizing: border-box; font-weight: bold;">.</span><span class="n" style="box-sizing: border-box; color: rgb(51, 51, 51);">username</span><span class="p" style="box-sizing: border-box;">)</span>
And here is how you would do the same if using a naive query:
# very similar query to the above -- main difference is we're
# aliasing the blog title to "blog_title"
tweets = Tweet.select(Tweet, User.username).join(User).naive()
for tweet in tweets.order_by(Tweet.created_date.desc()).limit(10):
print '%s, posted on %s' % (tweet.message, tweet.username)
To iterate over raw tuples, use the tuples() method:
stats = Stat.select(Stat.url, fn.Count(Stat.url)).group_by(Stat.url).tuples()
for stat_url, count in stats:
print stat_url, count
To iterate over dictionaries, use the dicts() method:
stats = Stat.select(Stat.url, fn.Count(Stat.url).alias('ct')).group_by(Stat.url).dicts()
for stat in stats:
print stat['url'], stat['ct']
<span style="font-family: Consolas, 'Andale Mono WT', 'Andale Mono', 'Lucida Console', 'Lucida Sans Typewriter', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Liberation Mono', 'Nimbus Mono L', Monaco, 'Courier New', Courier, monospace; font-size: 18px; line-height: 1.5; background-color: rgb(255, 255, 255);">9.</span><span style="font-family: Consolas, 'Andale Mono WT', 'Andale Mono', 'Lucida Console', 'Lucida Sans Typewriter', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Liberation Mono', 'Nimbus Mono L', Monaco, 'Courier New', Courier, monospace; font-size: 18px; line-height: 1.5; background-color: rgb(255, 255, 255);">Pre-fetching related instances</span>
As a corollary to the previous section in which we selected models going “up” the chain, in this section I will show you to select models going “down” the chain in a 1 -> many relationship. For example, selecting users and all of their tweets.
Assume you want to display a list of users and all of their tweets:
for user in User.select():
print user.username
for tweet in user.tweets:
print tweet.message
This will generate N queries, however - 1 for the users, and then N for each user’s tweets. Instead of doing N queries, we can do 2 instead:
- One for all the users
- One for all the tweets for the users selected in (1)
-- first query --
SELECT t1.id, t1.username FROM users AS t1;
-- second query --
SELECT t1.id, t1.message, t1.user_id
FROM tweet AS t1
WHERE t1.user_id IN (
SELECT t2.id FROM users AS t2)
Peewee can evaluate both queries and “prefetch” the tweets for each user, storing them in
an attribute on the user model. To do this, use the prefetch() function:
users = User.select()
tweets = Tweet.select()
users_prefetch = prefetch(users, tweets)
for user in users_prefetch:
print user.username
# note we are using a different attr -- it is the "related name" + "_prefetch"
for tweet in user.tweets_prefetch:
print tweet.message
will result in 2 queries – one for the users and one for the tweets. Either query can have restrictions, such as a WHERE clause,
and the queries can follow relationships arbitrarily deep:
# let's say we have users -> photos -> comments / tags
# such that a user posts photos, assigns tags to those photos, and all those
# photos can be commented on
users = User.select().where(User.active == True)
photos = Photo.select().where(Photo.published == True)
tags = Tag.select()
comments = Comment.select().where(Comment.is_spam == False, Comment.flags < 3)
# this will execute 4 queries, one for each model
users_prefetch = prefetch(users, photos, tags, comments)
for user in users_prefetch:
print user.username
for photo in user.photo_set_prefetch:
print 'photo: ', photo.filename
for tag in photo.tag_set_prefetch:
print 'tagged with:', tag.tag
for comment in photo.comment_set_prefetch:
print 'comment:', comment.comment
Note:当我们使用prefetch时,它能够保存queries到内存中。从而降低訪问数据的次数,从而提高查询效率。
可是我最好使用limit函数去做点事情,你懂得。
10.Query evaluation
In order to execute a query, it is always necessary to call the execute() method.
To get a better idea of how querying works let’s look at some example queries and their return values:
>>> dq = User.delete().where(User.active == False) # <-- returns a DeleteQuery
>>> dq
<peewee.DeleteQuery object at 0x7fc866ada4d0>
>>> dq.execute() # <-- executes the query and returns number of rows deleted
3
>>> uq = User.update(active=True).where(User.id > 3) # <-- returns an UpdateQuery
>>> uq
<peewee.UpdateQuery object at 0x7fc865beff50>
>>> uq.execute() # <-- executes the query and returns number of rows updated
2
>>> iq = User.insert(username='new user') # <-- returns an InsertQuery
>>> iq
<peewee.InsertQuery object at 0x7fc865beff10>
>>> iq.execute() # <-- executes query and returns the new row's PK
8
python轻量级ORM---peewee的更多相关文章
- python轻量级orm框架 peewee常用功能速查
peewee常用功能速查 peewee 简介 Peewee是一种简单而小的ORM.它有很少的(但富有表现力的)概念,使它易于学习和直观的使用. 常见orm数据库框架 Django ORM peewee ...
- python轻量级orm
python下的orm使用SQLAlchemy比较多,用了一段时间感觉不顺手,主要问题是SQLAlchemy太重,所以自己写了一个orm,实现方式和netsharp类似,oql部分因为代码比较多,没有 ...
- 连表查询都用Left Join吧 以Windows服务方式运行.NET Core程序 HTTP和HTTPS的区别 ASP.NET SignalR介绍 asp.net—WebApi跨域 asp.net—自定义轻量级ORM C#之23中设计模式
连表查询都用Left Join吧 最近看同事的代码,SQL连表查询的时候很多时候用的是Inner Join,而我觉得对我们的业务而言,99.9%都应该使用Left Join(还有0.1%我不知道在 ...
- 轻量级ORM框架初探-Dapper与PetaPoco的基本使用
一.EntityFramework EF是传统的ORM框架,也是一个比较重量级的ORM框架.这里仍然使用EF的原因在于为了突出轻量级ORM框架的性能,所谓有对比才有更优的选择. 1.1 准备一张数据库 ...
- Python MySQL ORM QuickORM hacking
# coding: utf-8 # # Python MySQL ORM QuickORM hacking # 说明: # 以前仅仅是知道有ORM的存在,但是对ORM这个东西内部工作原理不是很清楚, ...
- c# 轻量级ORM框架 实现(一)
发布一个自己写的一个轻量级ORM框架,本框架设计期初基于三层架构.所以从命名上来看,了解三层的朋友会很好理解. 设计该框架的目的:不想重复的写增删改查,把精力放到功能实现上. 发布改框架的原因:希望给 ...
- 自己开发轻量级ORM(二)
上一篇简单的对轻量级ORM开发开了个头.这篇主要聊下ORM框架的设计思路. ORM本质上是对数据库操作的抽象.大体上我将其分为对数据结构的抽象和对执行方法的抽象. 我的ORM设计图: ORM框架需要完 ...
- 自己开发轻量级ORM(一)
在开发ORM之前,先简单的介绍下ORM的基本概念. 对象关系映射(Object Relational Mapping,简称ORM)是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术. 简单的 ...
- 轻量级ORM框架 QX_Frame.Bantina(二、框架使用方式介绍)
轻量级ORM框架QX_Frame.Bantina系列讲解(开源) 一.框架简介 http://www.cnblogs.com/qixiaoyizhan/p/7417467.html 二.框架使用方式介 ...
- 轻量级ORM框架 QX_Frame.Bantina(一、框架简介)
轻量级ORM框架QX_Frame.Bantina系列讲解(开源) 一.框架简介 http://www.cnblogs.com/qixiaoyizhan/p/7417467.html 二.框架使用方式介 ...
随机推荐
- 什么是ASCII码文本文件
标准ASCII码方式(也称文本方式)存储的文件,更确切地说,英文.数字等字符存储的是ASCII码.文本文件中除了存储文件有效字符信息(包括能用ASCII码字符表示的回车.换行等信息)外,不能存储其他任 ...
- linux及安全《Linux内核设计与实现》第二章——20135227黄晓妍
第二章:从内核出发 2.1获取源代码 2.1.1使用git Git:内核开发者们用来管理Linux内核源代码的控制系统. 我们使用git来下载和管理Linux源代码. 2.1.2安装内核源代码(如果使 ...
- 参考sectools,每个人至少查找5种安全工具、库等信息并深入研究至少两种并写出使用教程
1.Nessus Nessus是免费网络漏洞扫描器,它可以运行于几乎所有的UNIX平台之上.它不仅能永久升级,还免费提供多达11000种插件(但需要注册并接受EULA-acceptance--终端用户 ...
- Java Mail 邮件发送简单封装
上一篇文章我们用写了一个Java Mail 的Demo,相信你已经可以用那个例子来发送邮件了.但是Demo 有很多的问题. 首先每次发送需要配置的东西很多,包括发件人的邮箱和密码.smtp服务器和SM ...
- ubuntu 18.04 64bit没有声音如何解决
一.背景 1.1 笔者的机器有两张声卡,使用aplay -l可以列举出来,一张是内置声卡,另一张是显卡自带的声卡,说明声卡驱动是ok的 1.2 笔者是在浏览器中播放视频无声音 二.尝试 2.1 尝试使 ...
- 解决com.mongodb.MongoException$CursorNotFound: cursor 0 not found on server
背景 经常需要执行脚本调用Java程序读取mongodb中数据,本来是转为后台进程.偶尔看看日志的简单任务.今天发现程序抛出异常“com.mongodb.MongoException$CursorNo ...
- Tomcat灵活配置多项目,多端口,多域名,多虚拟目录
Tomcat的配置都在Tomcat的安装目录的conf文件夹下的server.xml文件 最初内容:(去掉所有注释) <?xml version="1.0" encoding ...
- POJ 3259 Wormholes(最短路&spfa正权回路)题解
题意:给你m条路花费时间(双向正权路径),w个虫洞返回时间(单向负权路径),问你他能不能走一圈回到原点之后,时间倒流. 思路:题意有点难看懂,我们建完边之后找一下是否存在负权回路,存在则能,反之不能. ...
- HDU 2457 DNA repair(AC自动机+DP)题解
题意:给你几个模式串,问你主串最少改几个字符能够使主串不包含模式串 思路:从昨天中午开始研究,研究到现在终于看懂了.既然是多模匹配,我们是要用到AC自动机的.我们把主串放到AC自动机上跑,并保证不出现 ...
- python 将一个列表乱序
import random nums = [, , , , , , ] random.shuffle(nums) print(nums)