peewee:如何向任何 select 添加 where 子句?
peewee: How to add where clause to any select?
我有这样的模型:
class AbstractBaseModel(peewee.Model):
uuid = peewee.UUIDField(default=uuid4)
is_active = peewee.BooleanField(default=False)
is_deleted = peewee.BooleanField(default=False)
created_at = peewee.DateTimeField(default=datetime.now)
updated_at = peewee.DateTimeField(default=datetime.now)
deleted_at = peewee.DateTimeField(null=True)
class Meta:
abstract = True
indexes = (
(('is_active', 'is_deleted'), False),
)
我愿意:
- (默认)能够 select 行
is_active == True
和 is_deleted == False
或
- select 所有行,但只是跳过
is_active
和 is_deleted
标志
这里有一个不是 peewee 特有的答案。
假设你上面的(未命名的)table 是 "thing",那么基本上你的模型擅长像 select * from thing
.
这样的查询
现在定义一个相关视图来挑选出某些东西,挑选出你最喜欢的行子集:
sqlite> create view thing_v as
...> select uuid, created_at, updated_at, deleted_at
...> from thing
...> where is_active == True and is_deleted == False;
将您的模型指向 那个 关系,它恰好是一个视图(命名查询)而不是 table。
它只是 Python...向您的模型添加一个辅助方法 class。例如,如果我的博客文章有 Post
class,我可能会写:
class Post(Model):
status = IntegerField() # 1=live, 2=draft, 3=deleted, e.g.
@classmethod
def visible(cls):
return cls.select().where(cls.status == 1)
然后,我可能会有所有已发布帖子的列表视图:
@app.route('/')
def post_index():
query = Post.visible().order_by(Post.timestamp.desc())
return render_template('post_index.html', query=query)
我想扩展 答案。
对于连接和更复杂的查询,我们可以使用 PeeWee CTE 功能,如下所示:
class BaseModel(peewee.Model):
is_deleted = peewee.BooleanField(default=False, index=True)
@classmethod
def visible_where_clause(cls):
return cls.is_deleted == False
@classmethod
def visible(cls):
return cls.select().where(cls.visible_where_clause())
@classmethod
def cte(cls, name=None):
if name is None:
name = 'CTE_{}'.format(cls.__name__)
return cls.visible().cte(name)
class Meta:
abstract = True
class User(BaseModel):
username = peewee.CharField(max_length=255, unique=True)
is_active = peewee.BooleanField(default=True, index=True)
@classmethod
def visible_where_clause(cls):
return (
(super().visible_where_clause()) & (cls.is_active == True)
)
UserCTE = User.cte()
class Post(BaseModel):
status = peewee.IntegerField() # 1=live, 2=draft, 3=deleted, e.g.
user = peewee.ForeignKeyField(User)
title = peewee.CharField(max_length=255)
@classmethod
def visible_where_clause(cls):
return (
(super().visible_where_clause()) & (cls.status == 1)
)
PostCTE = Post.cte()
然后当我们只想要活跃用户的活跃帖子时,我们可以这样做:
posts = (
Post
.visible()
.select(Post.title)
.join(UserCTE, on=Post.user == UserCTE.c.id)
.with_cte(UserCTE)
)
for post in posts:
print(post.title)
记住
您必须通过添加 .c.<column_name>
来引用 CTE
对象,并通过添加 .with_cte(<list of all used CTEs>)
在查询末尾添加此 cte
我有这样的模型:
class AbstractBaseModel(peewee.Model):
uuid = peewee.UUIDField(default=uuid4)
is_active = peewee.BooleanField(default=False)
is_deleted = peewee.BooleanField(default=False)
created_at = peewee.DateTimeField(default=datetime.now)
updated_at = peewee.DateTimeField(default=datetime.now)
deleted_at = peewee.DateTimeField(null=True)
class Meta:
abstract = True
indexes = (
(('is_active', 'is_deleted'), False),
)
我愿意:
- (默认)能够 select 行
is_active == True
和is_deleted == False
或
- select 所有行,但只是跳过
is_active
和is_deleted
标志
这里有一个不是 peewee 特有的答案。
假设你上面的(未命名的)table 是 "thing",那么基本上你的模型擅长像 select * from thing
.
现在定义一个相关视图来挑选出某些东西,挑选出你最喜欢的行子集:
sqlite> create view thing_v as
...> select uuid, created_at, updated_at, deleted_at
...> from thing
...> where is_active == True and is_deleted == False;
将您的模型指向 那个 关系,它恰好是一个视图(命名查询)而不是 table。
它只是 Python...向您的模型添加一个辅助方法 class。例如,如果我的博客文章有 Post
class,我可能会写:
class Post(Model):
status = IntegerField() # 1=live, 2=draft, 3=deleted, e.g.
@classmethod
def visible(cls):
return cls.select().where(cls.status == 1)
然后,我可能会有所有已发布帖子的列表视图:
@app.route('/')
def post_index():
query = Post.visible().order_by(Post.timestamp.desc())
return render_template('post_index.html', query=query)
我想扩展
对于连接和更复杂的查询,我们可以使用 PeeWee CTE 功能,如下所示:
class BaseModel(peewee.Model):
is_deleted = peewee.BooleanField(default=False, index=True)
@classmethod
def visible_where_clause(cls):
return cls.is_deleted == False
@classmethod
def visible(cls):
return cls.select().where(cls.visible_where_clause())
@classmethod
def cte(cls, name=None):
if name is None:
name = 'CTE_{}'.format(cls.__name__)
return cls.visible().cte(name)
class Meta:
abstract = True
class User(BaseModel):
username = peewee.CharField(max_length=255, unique=True)
is_active = peewee.BooleanField(default=True, index=True)
@classmethod
def visible_where_clause(cls):
return (
(super().visible_where_clause()) & (cls.is_active == True)
)
UserCTE = User.cte()
class Post(BaseModel):
status = peewee.IntegerField() # 1=live, 2=draft, 3=deleted, e.g.
user = peewee.ForeignKeyField(User)
title = peewee.CharField(max_length=255)
@classmethod
def visible_where_clause(cls):
return (
(super().visible_where_clause()) & (cls.status == 1)
)
PostCTE = Post.cte()
然后当我们只想要活跃用户的活跃帖子时,我们可以这样做:
posts = (
Post
.visible()
.select(Post.title)
.join(UserCTE, on=Post.user == UserCTE.c.id)
.with_cte(UserCTE)
)
for post in posts:
print(post.title)
记住
您必须通过添加 .c.<column_name>
来引用 CTE
对象,并通过添加 .with_cte(<list of all used CTEs>)
cte