gpt4 book ai didi

python - SQLAlchemy 查询查找按 parent 和祖 parent 过滤的孙子

转载 作者:行者123 更新时间:2023-12-01 05:28:23 26 4
gpt4 key购买 nike

我有一个 Flask 应用程序,其中包含项目、文章和标签。

缩写的 models.py 是:

project_articles = Table('project_articles',
Base.metadata,
Column('project_id', Integer, ForeignKey('project.id')),
Column('article_id', Integer, ForeignKey('article.id'))
)

article_tags = Table('article_tags',
Base.metadata,
Column('tag_id', Integer, ForeignKey('tag.id')),
Column('article_id', Integer, ForeignKey('article.id'))
)

class Project(Base):
__tablename__ = 'project'
id = Column(Integer, primary_key=True)
articles = relationship('Article', secondary=project_articles, backref='project', lazy='dynamic')
tags = association_proxy('articles', 'tags')

class Article(Base):
__tablename__ = 'article'
id = Column(Integer, primary_key=True)
projects = relationship('Project', secondary=project_articles, backref='article')
tags = relationship('Tag', secondary=article_tags, backref='article')
date_created = Column(DateTime, default=datetime.now, nullable=False)

class Tag(Base):
__tablename__ = 'tag'
id = Column(Integer, primary_key=True)
articles = relationship('Article', secondary=article_tags, backref='tag')
text = Column(String)

我经常进行查询,返回与在特定日期范围内创建的项目相关的所有文章:

q = db.session.query(Article)
q = q.join(Article.project)
q = q.filter(Project.id == id)
q = q.filter(Article.date_created.between(now-timedelta(hours=1), now))
articles = q.all()

我还想找到与上述文章子集关联的所有标签,但我需要知道每个标 checkout 现了多少次(同一标签可能与多篇文章关联)。我目前使用Python:

tags = [tag for article in articles for tag in article.tags]

但这很慢,我确信这是一个 sqlalchemy 查询可以做到这一点。

注意我可以这样做:

q = db.session.query(Tag)
q = q.join(Tag.article)
q = q.join(Article.project)
q = q.filter(Project.id == 2)
q = q.filter(Article.date_created.between(now-timedelta(hours=1), now))
tags = q.all()

但是这是过滤标签表,所以只是给了我一个唯一的列表,但我需要知道每个标 checkout 现的频率。

谢谢。

最佳答案

事实上,当您收集查询返回的文章的所有 Tags 时,将为每篇文章发出单独的 SQL,这可能会很慢。

选项 1: 解决这个问题的一种方法是在原始查询期间使用以下方法急切地加载所有标签:

  1. joinedload ,在这种情况下,原始查询还将预取标签
  2. subqueryload ,在这种情况下,一旦访问第一个 Article.tag 属性,就会再发出一个查询,该查询将加载使用原始查询加载的所有文章的所有标签。

在这种情况下,您可以使用您的代码,只需向其中添加一个选项即可:

q = db.session.query(Article)
q = q.join(Article.project)
q = q.filter(Project.id == id)
q = q.filter(Article.date_created.between(now-timedelta(hours=1), now))
#q = q.options(joinedload(Article.tags)) # @new: load Tag immediatelly
q = q.options(subqueryload(Article.tags)) # @new: load Tag on first access (in the line where tags are collected)
articles = q.all()

并且您的标签收集代码保持不变:

tags = [tag for article in articles for tag in article.tags]

选项2:另一种方法是有一个单独的查询,就像您在第二个代码片段中实际尝试执行的那样。查询中没有得到重复项的原因是 sqlalchemy 实际上是在 ORM 级别过滤掉重复项。要解决此问题,您可以向查询本身添加一个计数器:

q = db.session.query(Tag, func.count('*').label("cnt")) #@new: added COUNT
q = q.join(Tag.article)
q = q.join(Article.project)
q = q.filter(Project.id == project_id)
q = q.filter(Article.date_created.between(now-timedelta(hours=1), now))
q = q.group_by(Tag) #@new:
tags = q.all()
return tags # @note: the result is a list of tuples: (Tag, cnt)

另一个技巧是告诉 sqlalchemy 仅返回某些列(标签),而不是 ORM 对象(标签),在这种情况下,sqlalchemy 将返回所有行而不返回重复项:

q = db.session.query(Tag.text) # @new:modified
q = q.join(Tag.article)
q = q.join(Article.project)
q = q.filter(Project.id == project_id)
q = q.filter(Article.date_created.between(now-timedelta(hours=1), now))
tags = q.all()
return tags # @note: the result is a list of tuples: (tag_name,)

关于python - SQLAlchemy 查询查找按 parent 和祖 parent 过滤的孙子,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20882016/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com