【问题标题】:How to map a view and a table to one model using SQLAlchemy?如何使用 SQLAlchemy 将视图和表映射到一个模型?
【发布时间】:2020-02-02 13:25:42
【问题描述】:

我第一次使用 SQLAlchemy 和 Flask 创建 API,我正在尝试使用 Entity Framework 做一些我之前在 .NET 中做过很多次的事情,即为我创建一个模型将视图和表中的列组合在一起的 CRUD 操作。我想知道是否可以这样做,或者我想要做的不是在 Flask/SQLAlchemy 中执行此操作的“正确”方法。我也在使用 flask-sqlalchemy 库。

这里有两个模型:

class PigeonView(db.Model):
    __table_args__ = {'info': dict(is_view=True)}
    id = db.Column(db.Integer, db.ForeignKey('pigeon.id')
    kick_events = db.Column(db.Integer)

class PigeonBase(db.Model):
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    name = db.Column(db.String(255), nullable=False)
    date_created = db.Column(db.DateTime, nullable=False)

Pigeon 映射到表,PigeonView 映射到视图(DB 是 mySQL)。

这是视图:

CREATE VIEW pigeon_view AS 
    SELECT 
        p.id AS id, 
        COALESCE(SUM(k.pigeon_id), 0) AS kick_events 
    FROM pigeon p 
    LEFT JOIN kick_event k 
    ON p.Id = k.pigeon_id GROUP BY p.Id

基本上,只有鸽子 ID 和鸽子被踢了多少次的整数。

(还有另一个名为 Kick Events 的模型/表格,此信息来自该模型/表格,如下所示)

class KickEvent(db.Model):
    __tablename__ = "kick_event"

    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), primary_key=True)
    pigeon_id = db.Column(db.Integer, db.ForeignKey('pigeon.id'), primary_key=True)
    date = db.Column(db.DateTime)

我想要的最终结果是一个鸽子模型,它包含 Pigeon 表中的所有内容以及 Pigeon 视图中的 kick_events 列。 (以及可能添加到鸽子视图中的任何其他变量)。

类似这样的:

class Pigeon(db.Model):
    id = db.Column(db.Integer, primary_key=True, autoincrement=True) #from pigeon table
    name = db.Column(db.String(255), nullable=False) #from pigeon table
    date_created = db.Column(db.DateTime, nullable=False) #from pigeon table
    kick_events = db.Column(db.Integer) #from pigeon view

在 .NET / Entity Framework 中,我会做这样的事情来将这些属性映射到我的最终目标 Pigeon 类:

this.HasKey((x => x.Id));

this.Property(x => x.Name).HasColumnName("Name");
this.Property(x => x.DateCreated).HasColumnName("DateCreated");
this.Property(x => x.KickEvents).HasColumnName("KickEvents");

Map(m =>
{
    m.Properties(p => new
    {
        p.Id,
        p.Name,
        p.DateCreated
    });
    m.ToTable("Pigeon");
});

Map(m =>
{
    m.Properties(p => new
    {
        p.Id,
        p.KickEvents
    });
    m.ToTable("PigeonView");
});

但我不确定如何使用 Python/SQLAlchemy 到达那里,因为整个过程显然与实体框架非常不同。

【问题讨论】:

    标签: python flask sqlalchemy flask-sqlalchemy


    【解决方案1】:

    在进一步挖掘之后,我决定完全放弃视图,将 Pigeons 附加到具有关系的 KickEvents,并添加一个列属性来对 kicks 求和。

    class Pigeon(db.Model):
        id = db.Column(db.Integer, primary_key=True, autoincrement=True)
        name = db.Column(db.String(255), nullable=False)
        date_created = db.Column(db.DateTime, nullable=False)
        kick_events = db.Column(db.Integer)
        kick_events = relationship("KickEvent"),
        kick_count = column_property(
            select([func.count(KickEvent.id)]).\
                where(KickEvent.pigeon_id==id).\
                correlate_except(KickEvent))
    

    (与解决方案不是超级相关,但我还修改了 KickEvents 以具有用作主键的 Id,因为我决定我希望用户能够多次踢同一只鸽子,所以这就是我为什么能够依靠 KickEvent.Id 这是我原始代码中没有的列)

    我想这并不能真正回答我提出的问题,因为我没有将表格和视图组合在一起,但是完全摆脱了视图之后,我仍然得到了我想要的最终结果,它是一个包含Pigeon 表和基于与 Pigeon (KickEvent) 相关的表计算的值。

    从这里收集所有这些:https://docs.sqlalchemy.org/en/13/orm/mapped_sql_expr.html

    我希望这可以帮助任何研究相同问题的人。另外,如果我完全走错了路,请告诉我。我很想知道是否有更好的方法。

    【讨论】:

      猜你喜欢
      • 2010-11-20
      • 1970-01-01
      • 1970-01-01
      • 2013-04-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多