我使用flask-sqlalchemy发表了这个声明,我选择将其保留为原始形式。 Post.query
相当于session.query(Post)
我尝试创建一个子查询,该子查询将过滤掉处于草稿状态但未由当前用户创建或修改的数据库中的所有帖子。我做了这个查询,
Post.query\
.filter(sqlalchemy.and_(
Post.post_status != Consts.PostStatuses["Draft"],
sqlalchemy.or_(
Post.modified_by_id == current_user.get_id(),
Post.created_by_id == current_user.get_id()))
创建了:
Where true AND ("Post".modified_by_id = :modified_by_id_1 OR
"Post".created_by_id = :created_by_id_1)
预期结果:
Where "Post".post_status != "Draft" AND (
"Post".modified_by_id = :modified_by_id_1 OR
"Post".created_by_id = :created_by_id_1)
我在想,为什么会这样?如何在SQLAlchemy中增加错误级别?我认为我的项目默默地失败了,我想证实我的猜测。
更新
我使用了错误的常量字典。一个字典包含整数,另一个包含字符串(一个用于数据库查询,一个用于打印)。
_post_status = db.Column(
db.SmallInteger,
default=Consts.post_status["Draft"])
post_status包含整数,Consts.PostStatuses包含字符串。在后面看来,真是个坏主意。我将创建一个返回元组而不是两个字典的字典。
@property
def post_status(self):
return Consts.post_status.get(getattr(self, "_post_status", None))
答案 0 :(得分:2)
问题是您的post_status
属性不能在ORM级别查询中使用,因为这是python descriptor,默认情况下在类级别返回自己:
from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class A(Base):
__tablename__ = 'a'
id = Column(Integer, primary_key=True)
_post_status = Column(String)
@property
def post_status(self):
return self._post_status
print (A.post_status)
print (A.post_status != 5678)
输出:
$ python test.py
<property object at 0x10165bd08>
True
您正在寻找的用法类型似乎是hybrid attribute的用法类型,它是SQLAlchemy包含的“常规”python描述符的扩展,它生成与核心SQL表达式兼容的类级别行为:
from sqlalchemy.ext.hybrid import hybrid_property
class A(Base):
__tablename__ = 'a'
id = Column(Integer, primary_key=True)
_post_status = Column(String)
@hybrid_property
def post_status(self):
return self._post_status
print (A.post_status)
print (A.post_status != 5678)
输出:
$ python test.py
A._post_status
a._post_status != :_post_status_1
请务必仔细阅读混合文档,包括how to establish the correct SQL expression behavior,在实例和类级别都有效的描述符是一种稍微高级的Python技术。