在我的架构中,硬件项目可能记录了零个或多个 Mod。我正在尝试根据与 mod 列表的完全匹配来过滤查询。例如,我可能想过滤具有 mods [2,3,5] 的硬件,而没有其他的。
目前,我正在分组和计数以检查 mod 的数量是否正确,然后在 for 循环中添加一个过滤器以匹配确切的 mod 编号:
...
query = query.join(Hardware).join(Mod)
query = query.group_by(Tag.tag_id).having(len(v['m']) == func.count(Mod.mod_number))
for m in v['m']:
query = query.filter(Hardware.mods.any(mod_number=m))
...
有没有更好的方法来使用 SQLAlchemy 来表达这一点?特别是,文档建议不要使用func.count()
,因为它在某些极端情况下会失败..
我的架构如下所示:
Base = declarative_base()
class Tag(Base):
__tablename__ = 'tag'
tag_id = Column(Integer, primary_key=True)
order_code = Column(String, nullable=False)
version = Column(String, nullable=False)
status = Column(String, nullable=False)
comments = Column(String)
software = relationship(
"Software",
backref="tag",
collection_class=attribute_mapped_collection('artefact'),
)
hardware = relationship(
"Hardware",
backref="tag",
collection_class=attribute_mapped_collection('artefact'),
)
__table_args__ = (
UniqueConstraint('order_code', 'version'),
)
def as_dict(self):
d = as_dict_columns(self)
d['software'] = {s: as_dict_columns(self.software[s]) for s in self.software}
d['hardware'] = {h: self.hardware[h].as_dict() for h in self.hardware}
return d
class Software(Base):
__tablename__ = 'software'
software_id = Column(Integer, primary_key=True)
tag_id = Column(String, ForeignKey('tag.tag_id'))
artefact = Column(String, nullable=False)
version = Column(String, nullable=False)
__table_args__ = (
UniqueConstraint('tag_id', 'artefact'),
)
def __str__(self):
""" This is to deal with Jinja2/SQLAlchemy wackiness """
return self.version
class Hardware(Base):
__tablename__ = 'hardware'
hardware_id = Column(Integer, primary_key=True)
tag_id = Column(String, ForeignKey('tag.tag_id'))
product_id = Column(String, nullable=True)
artefact = Column(String, nullable=False)
version = Column(String, nullable=False)
mods = relationship("Mod", backref="hardware")
__table_args__ = (
UniqueConstraint('tag_id', 'product_id'),
)
def as_dict(self):
d = as_dict_columns(self)
d['mods'] = self.__list_mods__()
return d
class Mod(Base):
__tablename__ = 'mod'
hardware_id = Column(String, ForeignKey('hardware.hardware_id'), primary_key=True)
mod_number = Column('mod_number', Integer, primary_key=True, nullable=False)
__table_args__ = (
UniqueConstraint('hardware_id', 'mod_number'),
)