当前位置:   article > 正文

python轻量级ORM---peewee

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
  1. Functions can be used as any part of a query:
  2. select
  3. where
  4. group_by
  5. order_by
  6. having
  7. update query
  8. insert query


# user's username starts with a 'g' or a 'G':
fn.Lower(fn.Substr(User.username, 1, 1)) == 'g'
2.表达式支持的操作符
a:
ComparisonMeaning
==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.实现用户自己定义的操作
 
   
  1. Here is how you might add support for modulo and regexp in SQLite:
  2. from peewee import *
  3. from peewee import Expression # the building block for expressions
  4. OP_MOD = 'mod'
  5. OP_REGEXP = 'regexp'
  6. def mod(lhs, rhs):
  7. return Expression(lhs, OP_MOD, rhs)
  8. def regexp(lhs, rhs):
  9. return Expression(lhs, OP_REGEXP, rhs)
  10. SqliteDatabase.register_ops({OP_MOD: '%', OP_REGEXP: 'REGEXP'}) #加入 %、regexp操作
  11. Now you can use these custom operators to build richer queries:
  12. # users with even ids
  13. User.select().where(mod(User.id, 2) == 0)
  14. # users whose username starts with a number
  15. User.select().where(regexp(User.username, '[0-9].*'))
4.Joining tables
 
   
  1. There are three types of joins by default:
  2. JOIN_INNER (default)
  3. JOIN_LEFT_OUTER
  4. JOIN_FULL
  5. Here are some examples:
  6. User.select().join(Blog).where(
  7. (User.is_staff == True) & (Blog.status == LIVE))
  8. Blog.select().join(User).where(
  9. (User.is_staff == True) & (Blog.status == LIVE))
  10. subquery:
  11. staff = User.select().where(User.is_staff == True)
  12. Blog.select().where(
  13. (Blog.status == LIVE) & (Blog.user << staff))

补充:在没有通过ForeignKeyField产生外键的多个models中,也能够做join操作。如:
 
   
  1. # No explicit foreign key between these models.
  2. OutboundShipment.select().join(InboundShipment, on=(
  3. OutboundShipment.barcode == InboundShipment.barcode))

5.Performing advanced queries
 
   
  1. To create arbitrarily complex queries, simply use python’s bitwise “andandor” operators:
  2. sq = User.select().where(
  3. (User.is_staff == True) |
  4. (User.is_superuser == True))
  5. The WHERE clause will look something like:
  6. WHERE (is_staff = ? OR is_superuser = ?)
  7. In order to negate an expression, use the bitwise “invert” operator:
  8. staff_users = User.select().where(User.is_staff == True)
  9. Tweet.select().where(
  10. ~(Tweet.user << staff_users))
  11. This query generates roughly the following SQL:
  12. SELECT t1.* FROM blog AS t1
  13. WHERE
  14. NOT t1.user_id IN (
  15. SELECT t2.id FROM user AS t2 WHERE t2.is_staff = ?)
  16. Rather complex lookups are possible:
  17. sq = User.select().where(
  18. ((User.is_staff == True) | (User.is_superuser == True)) &
  19. (User.join_date >= datetime(2009, 1, 1))
  20. This generates roughly the following SQL:
  21. SELECT * FROM user
  22. WHERE (
  23. (is_staff = ? OR is_superuser = ?) AND
  24. (join_date >= ?

))



 
   

6.Aggregating records

  1. #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:
  2. query = User.select().annotate(Tweet)
  3. This is equivalent to the following:
  4. query = User.select(
  5. User, fn.Count(Tweet.id).alias('count')
  6. ).join(Tweet).group_by(User)
  7. #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:
  8. query = User.select().annotate(
  9. Tweet, fn.Max(Tweet.created_date).alias('latest'))
  10. #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:
  11. most_recent_tweet = Tweet.select().aggregate(fn.Max(Tweet.created_date))

7. Window functions
  1. #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.
  2. # Get the list of employees and the average salary for their dept.
  3. query = (Employee
  4. .select(
  5. Employee.name,
  6. Employee.department,
  7. Employee.salary,
  8. fn.Avg(Employee.salary).over(
  9. partition_by=[Employee.department]))
  10. .order_by(Employee.name))
  11. # Rank employees by salary.
  12. query = (Employee
  13. .select(
  14. Employee.name,
  15. Employee.salary,
  16. fn.rank().over(
  17. 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?
  1. #We can do this pretty easily:
  2. for tweet in Tweet.select().order_by(Tweet.created_date.desc()).limit(10):
  3. print '%s, posted on %s' % (tweet.message, tweet.user.username)
  4. #Looking at the query log, though, this will cause 11 queries:
  5. #1 query for the tweets
  6. #1 query for every related user (10 total)
  7. #This can be optimized into one query very easily, though:
  8. tweets = Tweet.select(Tweet, User).join(User)
  9. for tweet in tweets.order_by(Tweet.created_date.desc()).limit(10):
  10. print '%s, posted on %s' % (tweet.message, tweet.user.username)
  11. #Will cause only one query that looks something like this:
  12. SELECT t1.id, t1.message, t1.user_id, t1.created_date, t2.id, t2.username
  13. FROM tweet AS t1
  14. INNER JOIN user AS t2
  15. ON t1.user_id = t2.id
  16. ORDER BY t1.created_date desc
  17. LIMIT 10
  1. <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>
  2. <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>
  3. <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>
  4. <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:

  1. for user in User.select():
  2. print user.username
  3. for tweet in user.tweets:
  4. 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:

  1. One for all the users
  2. One for all the tweets for the users selected in (1)

  1. -- first query --
  2. SELECT t1.id, t1.username FROM users AS t1;
  3. -- second query --
  4. SELECT t1.id, t1.message, t1.user_id
  5. FROM tweet AS t1
  6. WHERE t1.user_id IN (
  7. 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:
  1. users = User.select()
  2. tweets = Tweet.select()
  3. users_prefetch = prefetch(users, tweets)
  4. for user in users_prefetch:
  5. print user.username
  6. # note we are using a different attr -- it is the "related name" + "_prefetch"
  7. for tweet in user.tweets_prefetch:
  8. print tweet.message


This 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:
  1. # let's say we have users -> photos -> comments / tags
  2. # such that a user posts photos, assigns tags to those photos, and all those
  3. # photos can be commented on
  4. users = User.select().where(User.active == True)
  5. photos = Photo.select().where(Photo.published == True)
  6. tags = Tag.select()
  7. comments = Comment.select().where(Comment.is_spam == False, Comment.flags < 3)
  8. # this will execute 4 queries, one for each model
  9. users_prefetch = prefetch(users, photos, tags, comments)
  10. for user in users_prefetch:
  11. print user.username
  12. for photo in user.photo_set_prefetch:
  13. print 'photo: ', photo.filename
  14. for tag in photo.tag_set_prefetch:
  15. print 'tagged with:', tag.tag
  16. for comment in photo.comment_set_prefetch:
  17. 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:

  1. >>> dq = User.delete().where(User.active == False) # <-- returns a DeleteQuery
  2. >>> dq
  3. <peewee.DeleteQuery object at 0x7fc866ada4d0>
  4. >>> dq.execute() # <-- executes the query and returns number of rows deleted
  5. 3
  6. >>> uq = User.update(active=True).where(User.id > 3) # <-- returns an UpdateQuery
  7. >>> uq
  8. <peewee.UpdateQuery object at 0x7fc865beff50>
  9. >>> uq.execute() # <-- executes the query and returns number of rows updated
  10. 2
  11. >>> iq = User.insert(username='new user') # <-- returns an InsertQuery
  12. >>> iq
  13. <peewee.InsertQuery object at 0x7fc865beff10>
  14. >>> iq.execute() # <-- executes query and returns the new row's PK
  15. 8




 
   

转载于:https://www.cnblogs.com/xfgnongmin/p/10706971.html

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/172827
推荐阅读
相关标签
  

闽ICP备14008679号