python - 从查询集中获取所有多对多对象的有效方法
问题描述
我有类似于以下的模型:
class Tag(models.Model):
text = models.CharField(max_length=30)
class Post(models.Model):
title = models.CharField(max_length=30)
tags = models.ManyToManyField(Tag)
APost
可以有很多Tags
并且Tags
可以与很多关联Posts
。
我需要的是获取所有帖子的列表以及与每个帖子关联的所有标签。Pandas DataFrame
然后我从该数据创建一个。这是我目前的做法:
qs = Post.objects.all().prefetch_related('tags')
tag_df = pd.DataFrame(columns=["post_id", "tags"])
for q in qs:
tag_df = tag_df.append(
{
"post_id": q.pk,
"tags": list(q.tags.all().values_list("text", flat=True)),
},
ignore_index=True,
)
post_df = pd.DataFrame(qs.values("id", "title"))
final_df = post_df.merge(tag_df, left_on="id", right_on="post_id")
就我需要的数据而言,结果是正确的。问题是它的效率非常低,即使我使用的是运行的查询数量prefetch_related
。对于循环的每次迭代,似乎都有一个查询正在访问数据库。
有没有更好、更有效的方法来做到这一点(可能没有循环)?最后我需要的是一个包含所有帖子的数据框以及一个包含每个帖子标签列表的列。
解决方案
通过使用.values_list(..)
,您将在每次迭代时进行额外的查询。所以这不是很有效。您可以简单地使用已经预取的Tag
对象,并获取.text
属性:
qs = Post.objects.prefetch_related('tags')
tag_df = pd.DataFrame(columns=['post_id', 'tags'])
for q in qs:
tag_df = tag_df.append(
{
'post_id': q.pk,
'tags': [t.text for t in q.tags.all()],
},
ignore_index=True,
)
post_df = pd.DataFrame(qs.values('id', 'title'))
final_df = post_df.merge(tag_df, left_on='id', right_on='post_id')
然而,首先制作一个字典列表,然后将它们加载到数据框中一次可能会更有效:
qs = Post.objects.prefetch_related('tags')
data = [
{'id': q.pk, 'title': q.title, 'tags': [t.text for t in q.tags.all()]}
for q in qs
]
final_df= pd.DataFrame(data, columns=['id', 'title', 'tags'])
请注意,使用.values(..)
or.values_list(..)
不是一个好主意。只有在某些情况下,例如在某个值上创建 GROUP BY,这是一个好主意。通常最好使用模型对象,因为它们增加了额外的逻辑层。
推荐阅读
- authorization - Postman 上的授权类型 Bearer Token
- parse-platform - 有没有办法限制查询中对象返回的键?
- javascript - 查找隐藏的父元素jQuery
- java - Java 正则表达式匹配范围内的数字
- c# - 使用 Prism 时如何允许 WPF 为 Window 控件解析 ContentTemplate?
- javascript - 如何使用角度动画始终将其向一个方向移动?
- visual-studio - 从 Visual Studio 发布到 Azure 时,“项目中不存在目标‘AddScheduledJob’”
- windows - Windows 10 主页上的 Docker
- apache-camel - features:uninstall -v 或 features:uninstall --verbose 未显示 Karaf 2.4.0.redhat-630310 中正在执行的操作
- javascript - 带有 DataTables 的 Javascript JSON 数据