Skip to content

Commit

Permalink
Adding notes to readme and a few tests for new python operator queries
Browse files Browse the repository at this point in the history
  • Loading branch information
coleifer committed Jun 12, 2012
1 parent 63c594d commit 31fa113
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 18 deletions.
43 changes: 29 additions & 14 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,22 @@ Examples::

# a simple query selecting a user
User.get(username='charles')

# get the staff and super users
editors = User.select().where(Q(is_staff=True) | Q(is_superuser=True))

# get tweets by editors
Tweet.select().where(user__in=editors)

# how many active users are there?
User.select().where(active=True).count()

# paginate the user table and show me page 3 (users 41-60)
User.select().order_by(('username', 'asc')).paginate(3, 20)

# order users by number of tweets
User.select().annotate(Tweet).order_by(('count', 'desc'))

# another way of expressing the same
User.select({
User: ['*'],
Expand All @@ -41,14 +41,29 @@ You can use django-style syntax to create select queries::

# how many active users are there?
User.filter(active=True).count()

# get tweets by a specific user
Tweet.filter(user__username='charlie')

# get tweets by editors
Tweet.filter(Q(user__is_staff=True) | Q(user__is_superuser=True))


You can use python operators to create select queries::

# how many active users are there?
User.select().where(User.active == True).count()

# get me all users in their thirties
User.select().where((User.age >= 30) & (User.age < 40))

# get me tweets from today by active users
Tweet.select().join(User).where(
(Tweet.pub_date >= today) &
(User.active == True)
)


Learning more
-------------

Expand Down Expand Up @@ -81,13 +96,13 @@ smells like django::


import peewee

class Blog(peewee.Model):
title = peewee.CharField()

def __unicode__(self):
return self.title

class Entry(peewee.Model):
title = peewee.CharField(max_length=50)
content = peewee.TextField()
Expand Down Expand Up @@ -120,7 +135,7 @@ foreign keys work like django's
<Blog: Peewee's Big Adventure>
>>> for e in b.entry_set:
... print e.title
...
...
Greatest movie ever?


Expand Down Expand Up @@ -167,7 +182,7 @@ query nesting using similar notation::
)

# generates something like:
# SELECT * FROM some_obj
# SELECT * FROM some_obj
# WHERE ((a = "A" OR b = "B") AND (c = "C" OR d = "D"))


Expand All @@ -187,7 +202,7 @@ using sqlite
class Blog(BaseModel):
creator = peewee.CharField()
name = peewee.CharField()

class Entry(BaseModel):
creator = peewee.CharField()
name = peewee.CharField()
Expand Down
6 changes: 3 additions & 3 deletions peewee.py
Original file line number Diff line number Diff line change
Expand Up @@ -2157,7 +2157,7 @@ def __set__(self, instance, value):

def qdict(op):
def fn(self, rhs):
return Q(**{'%s__%s' % (self.name, op): rhs})
return Q(self.model, **{'%s__%s' % (self.name, op): rhs})
return fn

class Field(object):
Expand Down Expand Up @@ -2220,9 +2220,9 @@ def class_prepared(self):
__eq__ = qdict('eq')
__ne__ = qdict('ne')
__lt__ = qdict('lt')
__lte__ = qdict('lte')
__le__ = qdict('lte')
__gt__ = qdict('gt')
__gte__ = qdict('gte')
__ge__ = qdict('gte')
__lshift__ = qdict('in')
__rshift__ = qdict('isnull')
__mul__ = qdict('contains')
Expand Down
44 changes: 43 additions & 1 deletion tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from peewee import *
from peewee import logger, VarCharColumn, SelectQuery, DeleteQuery, UpdateQuery, \
InsertQuery, RawQuery, parseq, Database, SqliteAdapter, \
create_model_tables, drop_model_tables, sort_models_topologically
create_model_tables, drop_model_tables, sort_models_topologically, Node


class QueryLogHandler(logging.Handler):
Expand Down Expand Up @@ -230,10 +230,13 @@ def assertSQL(self, query, expected_clauses):
self.assertEqual(sorted(clauses), sorted(expected_clauses))

def assertNodeEqual(self, lhs, rhs):
self.assertEqual(lhs.connector, rhs.connector)
self.assertEqual(lhs.negated, rhs.negated)
for i, lchild in enumerate(lhs.children):
rchild = rhs.children[i]
self.assertEqual(type(lchild), type(rchild))
if isinstance(lchild, Q):
self.assertEqual(lchild.model, rchild.model)
self.assertEqual(lchild.query, rchild.query)
elif isinstance(lchild, Node):
self.assertNodeEqual(lchild, rchild)
Expand Down Expand Up @@ -597,6 +600,23 @@ def test_delete(self):
dq = DeleteQuery(Blog).where(Q(title='b') | Q(title='a'))
self.assertSQLEqual(dq.sql(), ('DELETE FROM `blog` WHERE (`title` = ? OR `title` = ?)', ['b', 'a']))

def test_readme_example(self):
class U(TestModel):
active = BooleanField()

class Tweet(TestModel):
pub_date = DateTimeField()
u = ForeignKeyField(U)

today = datetime.datetime.today()
sq = Tweet.select().join(U).where(
(Tweet.pub_date >= today) &
(U.active == True)
)
self.assertSQLEqual(sq.sql(), (
'SELECT t1.`id`, t1.`pub_date`, t1.`u_id` FROM `tweet` AS t1 INNER JOIN `u` AS t2 ON t1.`u_id` = t2.`id` WHERE (t1.`pub_date` >= ? AND t2.`active` = ?)', [today, True]
))


class ModelTestCase(BaseModelTestCase):
def test_insert(self):
Expand Down Expand Up @@ -1248,6 +1268,23 @@ def test_node_and_q(self):
node = parseq(None, Q(c='C') & (Q(a='A') | Q(b='B')))
self.assertEqual(unicode(node), '((c = C) AND (a = A OR b = B))')

def test_field_q(self):
class FU(TestModel):
age = IntegerField()
username = CharField()

node = (FU.age >= 30) & (FU.age < 40)
self.assertNodeEqual(node, Node('AND', [Q(FU, age__gte=30), Q(FU, age__lt=40)]))

node = (FU.username != 'herp') | (FU.username << ['derp', 'fap'])
self.assertNodeEqual(node, Node('OR', [Q(FU, username__ne='herp'), Q(FU, username__in=['derp', 'fap'])]))

node = ((FU.username * 's') & (FU.username ** 'j')) | (FU.username ^ 'd')
self.assertNodeEqual(node, Node('OR', [
Node('AND', [Q(FU, username__contains='s'), Q(FU, username__icontains='j')]),
Q(FU, username__istartswith='d')
]))


class RelatedFieldTests(BaseModelTestCase):
def get_common_objects(self):
Expand Down Expand Up @@ -1441,6 +1478,11 @@ def test_querying_joins_mixed_q(self):
('(t1.`title` = ? OR t2.`title` = ?) AND (t2.`pk` = ? OR t3.`tag` = ? OR t3.`tag` = ?)', ['b', 'a2', 1, 't1', 't2']),
])

sq = Blog.select().join(Entry).where((Entry.title=='e1') | (Blog.id==99))
self.assertSQLEqual(sq.sql(), (
'SELECT t1.`id`, t1.`title` FROM `blog` AS t1 INNER JOIN `entry` AS t2 ON t1.`id` = t2.`blog_id` WHERE (t2.`title` = ? OR t1.`id` = ?)', ['e1', 99]
))

def test_filtering_across_joins(self):
a, a1, a2, b, b1, b2, t1, t2 = self.get_common_objects()

Expand Down

0 comments on commit 31fa113

Please sign in to comment.