I am learning pyramid and sqlalchemy and am struggling with how best to perform a query in the database without nested foreach loops. I am sure there is a more efficient way.
I have the following models:
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
username = Column(Text)
topicsfollowing = relationship('Topic', secondary=users_topics,
backref='followers')
class Article(Base):
__tablename__ = 'articles'
id = Column(Integer, primary_key=True)
name = Column(Text)
body = Column(Text)
datepublished = Column(DateTime)
focusid = Column(Integer, ForeignKey("topics.id"))
focus = relationship("Topic", backref=backref('articles', order_by=id))
class Topic(Base):
__tablename__ = 'topics'
id = Column(Integer, primary_key=True)
name = Column(Text)
And I also set up the M2M relationship between users and topics as follows:
users_topics = Table('users_topics', Base.metadata,
Column('userid', Integer, ForeignKey('users.id')),
Column('topicid', Integer, ForeignKey('topics.id')))
Essentially, my users can follow topics, and there are articles written about each of the topics (the focus). What I am trying to figure out is an efficient way to get a list of the 10 most recent articles written from the collection of all of the topics the user is following. For example, one particular topic could supply all 10 of the most recent, or there may be 10 topics, each supplying a single recent article.
The only way I can think to do it is something along the lines of:
user = DBSession.query(User).filter_by(id=logged_in).first()
for topic in user.topicsfollowing:
for article in topic.articles:
# from here assemble a list of all articles from all followed
# topics and then sort them descending by datepublished and take
# the first 10 in the list
But I know there has to be a much more efficient way to do this. Any help would be greatly appreciated.
You just need to do one query to get a list of the topic ids the user is following, then do something like:
I’m writing that more or less off the top of my head, so I’m not sure if it’s 100% right, but see the “IN” operator in the docs.