【问题标题】:SQLAlchemy: foreignKeys from multiple Tables (Many-to-Many)SQLAlchemy:来自多个表的外键(多对多)
【发布时间】:2021-06-15 05:31:56
【问题描述】:

我在我的烧瓶应用程序中使用 flask-sqlalchemy orm,它是关于智能家居传感器和演员的(为了简单起见,我们称它们为 Nodes

现在我想存储一个绑定到NodesEvent,以检查它们的状态其他或相同的Nodes,如果状态,则应使用给定值设置第一个已经达到阈值。

此外,可以从GroupsScenes 检查或设置状态。所以我有三个不同的外键要检查,另外三个要设置。每个类型都可以有多个类型,每个Event 可以有多个类型。

这是一个带有db.Models 的示例代码和我希望存储在Event 中的伪代码:

db = SQLAlchemy()

class Node(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    value = db.Column(db.String(20))
    # columns snipped out

class Group(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    value = db.Column(db.String(20))
    # columns snipped out

class Scene(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    value = db.Column(db.String(20))
    # columns snipped out


class Event(db.Model):
    id = db.Column(db.Integer, primary_key=True)

    # The following columns may be in a intermediate table
    # but I have no clue how to design that under these conditions

    constraints = # list of foreignkeys from diffrent tables (Node/Group/Scene)
                  # with threshold per key

    target = # list of foreignkeys from diffrent tables (Node/Group/Scene)
             # with target values per key

最后我希望能够检查我的任何Events 是否为真,以相应地设置绑定Node/Group/Scene

这可能是数据库设计问题(而不是sqlalchemy)但我想在这里利用sqla orm的优势。

thisthat 答案的启发,我试图深入挖掘,但关于 SO 的其他问题是关于更具体的问题或一对多关系。

非常感谢任何提示或设计技巧。谢谢!

【问题讨论】:

    标签: database sqlalchemy flask-sqlalchemy


    【解决方案1】:

    我最终在用法和代码行之间进行了权衡。我的第一个想法是尽可能多地保存代码(DRY)并尽可能少地定义表。

    正如 SQLAlchemy 本身在他们的 examples 之一中指出的那样,“通用外键” 之所以受到支持,是因为它经常被请求,而不是因为它是一个好的解决方案。使用较少的数据库功能,应用程序必须注意键约束。

    另一方面,他们说,数据库中有更多表不会影响数据库性能。

    所以我尝试了一些方法并找到了适合我用例的好方法。我使用另一个 SQLAlchemy 类代替了用于多对多关系的 “普通” 中间表,该类在两侧都有两个一对多关系来连接两个表。

    class Event(db.Model):
        id = db.Column(db.Integer, primary_key=True)
        noodles = db.relationship('NoodleEvent', back_populates='events')
        # columns snipped out
    
        def get_as_dict(self):
            return {
                "id": self.id,
                "nodes": [n.get_as_dict() for n in self.nodes]
            }
    
    
    class Node(db.Model):
        id = db.Column(db.Integer, primary_key=True)
        value = db.Column(db.String(20))
        events = db.relationship('NodeEvent', back_populates='node')
        # columns snipped out
    
    
    class NodeEvent(db.Model):
        ev_id = db.Column('ev_id', db.Integer, db.ForeignKey('event.id'), primary_key=True)
        n_id = db.Column('n_id', db.Integer, db.ForeignKey('node.id'), primary_key=True)
        value = db.Column('value', db.String(200), nullable=False)
        compare = db.Column('compare', db.String(20), nullable=True)
        node = db.relationship('Node', back_populates="events")
        events = db.relationship('Event', back_populates="nodes")
    
        def get_as_dict(self):
            return {
                "trigger_value": self.value,
                "actual_value": self.node.status,
                "compare": self.compare
            }
    

    权衡是每次我在该关系上绑定一个新表时,我都必须定义一个新类。但是使用 "通用外键" 方法,我还必须检查 ForeignKey 的来源。一天结束时做同样的工作。

    使用我的get_as_dict() 函数,我可以非常方便地访问相关数据。

    【讨论】:

    • 也许有人可以在使用继承的情况下使用GroupEvent(db.Model) 等改进这个答案(其中只有n_id 字段被覆盖)
    猜你喜欢
    • 1970-01-01
    • 2019-11-24
    • 2020-12-30
    • 2019-02-18
    • 2012-12-19
    • 2020-08-16
    • 2013-06-03
    • 2020-07-24
    • 1970-01-01
    相关资源
    最近更新 更多