【问题标题】:SQLAlchemy: retrieve all episodes from favorite_series of specific userSQLAlchemy:从特定用户的喜爱系列中检索所有剧集
【发布时间】:2012-05-20 17:41:07
【问题描述】:

我有用户可以拥有他最喜欢的系列,并且有些剧集具有系列作为外键,我正在尝试从用户最喜欢的系列中检索所有剧集。 我正在使用 Flask-SQLAlchemy。

数据库:

db = SQLAlchemy(app)

# cross table for user-series
favorite_series = db.Table('favorite_series',
    db.Column('user_id', db.Integer, db.ForeignKey('user.id')),
    db.Column('series_id', db.Integer, db.ForeignKey('series.id'))
)

# user
class User(db.Model):
    __tablename__ = 'user'
    id = db.Column(db.Integer, primary_key=True)
    favorite_series = db.relationship('Series', secondary=favorite_series,
        backref=db.backref('users', lazy='dynamic'))

# series
class Series(db.Model):
     __tablename__ = 'series'
    id = db.Column(db.Integer, primary_key=True)

# episode
class Episode(db.Model):
    __tablename__ = 'episode'
    id = db.Column(db.Integer, primary_key=True)
    series_id = db.Column(db.Integer, db.ForeignKey('series.id'))
    series = db.relationship('Series',
        backref=db.backref('episodes', lazy='dynamic'))

朋友帮我处理 SQL

select user_id,series.name,episode.name from (favorite_series left join series on favorite_series.series_id = series.id) left join episode on episode.series_id = series.id where user_id=1;

尽管如此,我想在 SQLAlchemy API 中使用它,但无法让它工作。

编辑

我的最终工作结果:

episodes = Episode.query.filter(Episode.series_id.in_(x.id for x in g.user.favorite_series)).filter(Episode.air_time!=None).order_by(Episode.air_time)

【问题讨论】:

  • 你在使用 SQLAlchemy ORM 吗?我认为烧瓶-sqlalchemy...
  • 我在这方面真的很新 :) 你告诉我 :) >>> s = Series.query.get(1) >>> s.episodes <sqlalchemy.orm.dynamic.AppenderBaseQuery object at 0x9d0254c>

标签: python database many-to-many sqlalchemy flask


【解决方案1】:

首先,您似乎没有声明您的表名? 此外,使用 orm 的全部意义在于,您永远不必编写 sql 查询:

from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import orm
import sqlalchemy as db
Base = declarative_base()

favorite_series = db.Table('favorite_series', Base.metadata,
    db.Column('user_id', db.Integer, db.ForeignKey('User.id')),
    db.Column('series_id', db.Integer, db.ForeignKey('Series.id'))
)
class Episode(Base):
    __tablename__ = 'Episode'
    id = db.Column(db.Integer, primary_key=True)
    season = db.Column(db.Integer)
    episode_num = db.Column(db.Integer)
    series_id = db.Column(db.Integer, db.ForeignKey('Series.id'))

    def __init__(self, season, episode_num, series_id):
        self.season = season
        self.episode_num = episode_num
        self.series_id = series_id

    def __repr__(self):
        return self.series.title + \
               ' S' + str(self.season) + \
               'E' + str(self.episode_num)

class Series(Base):
    __tablename__ = 'Series'
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String)
    episodes = orm.relationship('Episode', backref='series')

    def __init__(self, title):
        self.title = title

    def __repr__(self):
        return self.title

class User(Base):
    __tablename__ = 'User'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String)
    favorite_series = orm.relationship('Series', 
        secondary=favorite_series, backref='users')

    def __init__(self, name):
        self.name = name

    def __repr__(self):
        return self.name

现在您可以访问对象的属性,让 sql alchemy 处理让您的数据库保持同步并发出查询。

engine = db.create_engine('sqlite:///:memory:')
session = orm.sessionmaker(bind=engine)()
Base.metadata.create_all(engine)

lt = User('Ludovic Tiako')
the_wire = Series('The Wire')
friends = Series('Friends')
session.add_all([lt, the_wire, friends])
session.commit() # need to commit here to generate the id fields

tw_s01e01 = Episode(1,1,the_wire.id)
tw_s01e02 = Episode(1,2,the_wire.id)
f_s01e01 = Episode(1,1,friends.id)
f_s01e02 = Episode(1,2,friends.id)
f_s01e03 = Episode(1,3,friends.id)

session.add_all([tw_s01e01, tw_s01e02, 
                f_s01e01, f_s01e02, f_s01e03])
session.commit()


the_wire.episodes # > [The Wire S1E1, The Wire S1E2]
friends.episodes # > [Friends S1E1, Friends S1E2, Friends S1E3]

最后,回答你的问题:

lt.favorite_series.append(the_wire)
session.commit()
lt.favorite_series # > [The Wire]
[s.episodes for s in lt.favorite_series] # >> [[The Wire S1E1, The Wire S1E2]]

【讨论】:

  • 但是我需要应用一些我没有提到的其他过滤器。当我不关心用户时,我会使用它:episodes = Episode.query.filter(Episode.air_time>=t.strftime('%Y%m%d')).order_by(Episode.air_time)
  • 我想对特定用户的剧集使用相同的过滤器和顺序。
  • 一旦你有了fav_episodes = [s.episodes.id for s in lt.favorite_series],只需将query.filter(Episode.id.in_(fav_episodes))添加到您的查询中
  • + 正如我在第一篇文章中所指的那样,我使用 Flak-SQLAlchemy,所以我不需要定义表名等。很多东西都为我处理好了,因为这适用于用 Flask 你制作的网站在您的示例中似乎没有使用 Flask-SQLAlchemy 做任何事情
  • 您应该使用db.Model 而不是Basedb.session 而不是创建一个,以及引擎等等。Flask-SQLAlchemy 为您提供了这些。而且你这样做的方式会产生多个查询,而不是一个,但它确实有效。
【解决方案2】:

我不了解 Flask,但从 Flask-SQLAlchemy 的文档来看,它似乎使用了声明性,所以是 ORM。所以,你应该有一个会话。我认为您可以通过db.session 访问它。

无论如何,如果这些假设是正确的,那么你应该这样做:

query = db.session.query(User.id, Series.name, Episode.name).filter((Episode.series_id == Series.id) & \
    (User.id == favorite_series.c.user_id) & (Series.id == favorite_series.c.id) & \
    (User.id == 1))
results = query.all();

它可能不是您提供的确切查询,但应该是一样的。

更新:我刚刚检查了github 上的Flask-SQLALchemy 代码,似乎dbSQLAlchemy 的一个实例,它有一个session 属性,由@987654327 创建@ 它返回一个会话对象。所以这应该可行。

另外,并不是说这样做,你就不会使用他们的 BaseQuery,虽然我不知道这意味着什么......

查看文档以了解具体操作。

【讨论】:

  • db 似乎是元数据,因此会话不会在那里。会话对象由sessionmaker创建。
  • @wberry dbSQLAlchemy 的一个实例。查看代码。我添加了一个链接,我认为这是访问会话的方式。
  • 这会抛出:AttributeError: 'Table' object has no attribute 'user_id'
  • @OndrejFabry 对,我的错。它是 favorite_series.c.user_id.c 代表“列”),因为 favorite_series 是 Table 而其他是 Model,它派生自 SQLAlchemy 的声明性基础。
猜你喜欢
  • 2016-09-30
  • 2012-10-18
  • 1970-01-01
  • 2019-11-16
  • 2022-01-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-23
相关资源
最近更新 更多