使用 ChoiceType 计算 sqlalchemy 模型中的相关项目

Posted

技术标签:

【中文标题】使用 ChoiceType 计算 sqlalchemy 模型中的相关项目【英文标题】:Count related items in a sqlalchemy model using ChoiceType 【发布时间】:2019-09-09 04:02:15 【问题描述】:

这是对上一个问题here 的跟进。我想计算每个类别offers的数量,并以我可以在Jinja中迭代的格式输出它们。

新的,3 二手, 7 破碎,5

这是我现在得到的:

class Offer(Base):
    CATEGORIES = [
        (u'new', u'New'),
        (u'used', u'Used'),
        (u'broken', u'Broken')
    ]

    __tablename__ = 'offers'
    id = sa.Column(sa.Integer, primary_key=True)
    summary = sa.Column(sa.Unicode(255))
    category = sa.Column(ChoiceType(CATEGORIES))

按照上一个答案,我尝试了这样的事情:

count_categories = db.session.query(
        CATEGORIES.value, func.count(Offer.id)).outerjoin(
        Offer).group_by(CATEGORIES.key).all()

这显然行不通,因为CATEGORIES.value 没有定义;如何将CATEGORIES 传递给此查询以产生所需的结果? “设置”似乎相当普遍,直接取自SQLAlchemy-Utils Data types page

非常感谢您的帮助(已经长出白头发了)!


一个可怕但有效的临时解决方法:

result = []
for category in Offer.CATEGORIES:
    count = db.session.query(func.count(Offer.id)).filter_by(category=category[0]).all()
    result.append((category[0], category[1], count[0][0]))

【问题讨论】:

您已经非常接近自己解决了这个问题。您知道您需要在类别和商品之间进行外连接,并且您在应用程序代码中有效执行的外连接是丑陋的。允许数据库通过将类别移动到其自己的表中来为您完成繁重的工作,该表由外键连接到 offer 表。您现在可以执行所需的外部连接,并且如果需要,将来还可以轻松添加新类别。 @EAW 感谢您的反馈!你说得对;这可能是将其卸载到数据库的唯一方法。我真的希望我能以某种方式将它与db.session.query 合并;可能作为虚拟表。如果我找到解决方案,我会在这里发帖。 【参考方案1】:

要计算每个类别的商品数量,您需要在类别和商品之间进行外部连接。鉴于您没有将类别存储为数据库表,您必须在不理想的应用程序代码中执行此操作。您只需要创建一个新的类别表并将用户表中的类别字段替换为连接到新类别表的外键。下面的代码演示了这一点。

class Offer(Base):
    __tablename__ = 'offers'
    id = sa.Column(sa.Integer, primary_key=True)
    summary = sa.Column(sa.Unicode(255))
    category_id = sa.Column(sa.Integer, sa.ForeignKey("categories.id"))
    category = sa.orm.relationship("Category", back_populates="offers")

class Category(Base):    
    __tablename__ = 'categories'
    id = sa.Column(sa.Integer, primary_key=True)
    name = sa.Column(sa.Unicode(6), unique=True)
    offers = sa.orm.relationship("Offer", back_populates="category")

# populate categories with the same values as your original enumeration
session.add(Category(name="New"))
session.add(Category(name="Used"))
session.add(Category(name="Broken"))

count_categories = session.query(Category.name, func.count(Offer.id)). \
    select_from(Category).outerjoin(Offer).group_by(Category.name).all()

【讨论】:

感谢您的反馈,但这并不能回答我的问题。我特别指出,这是another question 的后续行动。我可能同意,这并不理想,但是,我在官方文档中发现了这一点,并且由于此设置更容易处理 for now 并支持 easy gettext风格翻译,我想看看它是否可能 - 至少对于开发来说 - 如果可能 在回答您的问题“如何将 CATEGORIES 传递给此查询以产生所需的结果?”时,唯一的方法是将其放入数据库表中。如果您坚持将其保存在 python 变量中,则数据库无法知道这些值是什么,因此无法在查询中使用它。有关使用枚举与表 ***.com/q/433490/10548137 的更多信息,请参阅此问题

以上是关于使用 ChoiceType 计算 sqlalchemy 模型中的相关项目的主要内容,如果未能解决你的问题,请参考以下文章

Symfony 表单 - Choicetype - 错误“数组到字符串转换”

Symfony 5 - 带有 TextType 的自定义 ChoiceType

Symfony 2.8 动态 ChoiceType 选项

Jackson 2.11.4:为缺少的 JSON 字段设置默认值

sqlalchemy 简单使用

奏鸣曲一对多关系