[英]SQLAlchemy union_all and all() returning incorrect number of items
For some reason when I'm using SQLAlchemy's union_all
and .all()
, it's returning the incorrect number of items. 由于某些原因,当我使用SQLAlchemy的
union_all
和union_all
.all()
,它返回的项目数不正确。
As you can see below, I broke each one down to see where the error was. 正如您在下面看到的那样,我将每个细分分解,以查看错误所在。 Does anyone have any idea why this would be happening?
有谁知道为什么会这样?
>>> pn = PostNotification.query.filter_by(notified_id=1)
>>> cn = CommentNotification.query.filter_by(notified_id=1)
>>> pn.count()
4
>>> cn.count()
2
>>> u = pn.union_all(cn)
>>> u.count()
6
>>> all = u.all()
>>> len(all)
5
Here are my two models: 这是我的两个模型:
class NotificationMixin:
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(150), nullable=False)
read = db.Column(db.Boolean, default=False)
created = db.Column(db.DateTime, index=True, default=datetime.utcnow)
@declared_attr
def notifier_id(cls):
return db.Column(db.Integer, db.ForeignKey('user.id'))
@declared_attr
def notified_id(cls):
return db.Column(db.Integer, db.ForeignKey('user.id'))
class PostNotification(db.Model, NotificationMixin):
post_id = db.Column(db.Integer, db.ForeignKey('post.id'))
comment_id = db.Column(db.Integer)
def __repr__(self):
return '<PostNotification {}>'.format(self.name)
class CommentNotification(db.Model, NotificationMixin):
post_id = db.Column(db.Integer, db.ForeignKey('post.id'))
comment_id = db.Column(db.Integer, db.ForeignKey('post_comment.id'))
def __repr__(self):
return '<CommentNotification {}>'.format(self.name)
UPDATE : 更新 :
Here is a screenshot of the data that represents the two models 这是代表两个模型的数据的屏幕截图
When I define the columns explicitly, there is no issue when I'm using union_all
. 当我显式定义列时,使用
union_all
不会有问题。 It only returns the incorrect amount of records when I db.session.query(PostNotification)
and db.session.query(CommentNotification)
. 仅在
db.session.query(PostNotification)
和db.session.query(CommentNotification)
时返回错误的记录量。
pn = db.session.query(
PostNotification.id,
PostNotification.name,
PostNotification.read,
PostNotification.created,
PostNotification.post_id,
PostNotification.comment_id,
PostNotification.notifier_id,
PostNotification.notified_id).filter_by(
notified_id=1)
cn = db.session.query(
CommentNotification.id,
CommentNotification.name,
CommentNotification.read,
CommentNotification.created,
CommentNotification.post_id,
CommentNotification.comment_id,
CommentNotification.notifier_id,
CommentNotification.notified_id).filter_by(
notified_id=1)
u = pn.union_all(cn).order_by(PostNotification.created.desc())
>>> pn.count()
4
>>> cn.count()
2
u.count()
6
>>> all = u.all()
>>> len(all)
6
The problem with this, is I lose the model, and my relationships are gone. 问题在于,我丢失了模型,而我的关系也消失了。 Therefore, I have to use this very ugly workaround.
因此,我必须使用此非常丑陋的解决方法。 This only makes sense if you see the data in https://i.stack.imgur.com/UHfo7.jpg .
仅当您在https://i.stack.imgur.com/UHfo7.jpg中看到数据时,这才有意义。
result = []
for row in u:
if 'post' in row.name.split('_'):
n = PostNotification.query.filter_by(id=row.id).first()
result.append(n)
if 'comment' in row.name.split('_'):
n = CommentNotification.query.filter_by(id=row.id).first()
result.append(n)
Now my result
is in descending order, both tables are combined via union_all
, and my relationships are back in tact. 现在,我的
result
按降序排列,两个表都通过union_all
合并union_all
,并且我的关系恢复了union_all
。 The problem now is, I obviously can't use result.paginate, because result
is now a list
. 现在的问题是,我显然不能使用result.paginate,因为
result
现在是一个list
。
The union u
is not polymorphic in the sense that it'd recognize which rows represent PostNotification
and which CommentNotification
entities – it simply treats all rows as representing the primary entity PostNotification
. 联合
u
在识别出哪些行代表PostNotification
和哪个CommentNotification
实体的意义上不是多态的,它只是将所有行都视为代表主要实体PostNotification
。
It also happens that you have 2 "identical" notifications in both tables, ie they have the same numeric value for primary key. 也可能在两个表中都有2个“相同”的通知,即它们的主键数值相同。 SQLAlchemy deduplicates model entities based on primary key when querying, as noted here by the author of SQLAlchemy , and so
len(u.all())
returns fewer results. SQLAlchemy在查询时会基于主键对模型实体进行重复数据删除, 正如SQLAlchemy的作者在此处指出的那样 ,因此
len(u.all())
返回的结果较少。 u.count()
on the other hand counts in the database and so counts all rows. u.count()
在数据库中计数,因此对所有行进行计数。 This deduplication does not take place if querying attributes or more than 1 entity. 如果查询属性或多于1个实体,则不会发生重复数据删除。
Looks like I figured it out. 好像我想通了。 I can now query
AbstractNotification
directly db.session.query(AbstractNotification).all()
我现在可以直接查询
AbstractNotification
db.session.query(AbstractNotification).all()
from sqlalchemy.ext.declarative import AbstractConcreteBase
class AbstractNotification(AbstractConcreteBase, db.Model):
__table__ = None
class NotificationBaseModel:
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(150), nullable=False)
read = db.Column(db.Boolean, default=False)
created = db.Column(db.DateTime, index=True, default=datetime.utcnow)
@declared_attr
def notifier_id(cls):
return db.Column(db.Integer, db.ForeignKey('user.id'))
@declared_attr
def notified_id(cls):
return db.Column(db.Integer, db.ForeignKey('user.id'))
class PostNotification(AbstractNotification, NotificationBaseModel):
post_id = db.Column(db.Integer, db.ForeignKey('post.id'))
comment_id = db.Column(db.Integer)
__mapper_args__ = {
'polymorphic_identity': 'post_notification',
'concrete': True
}
def __repr__(self):
return '<PostNotification {}>'.format(self.name)
class CommentNotification(AbstractNotification, NotificationBaseModel):
post_id = db.Column(db.Integer, db.ForeignKey('post.id'))
comment_id = db.Column(db.Integer, db.ForeignKey('post_comment.id'))
__mapper_args__ = {
'polymorphic_identity': 'comment_notification',
'concrete': True
}
def __repr__(self):
return '<CommentNotification {}>'.format(self.name)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.