gpt4 book ai didi

python - Django 使用相关查询集的第一个元素进行注释

转载 作者:太空宇宙 更新时间:2023-11-03 12:07:40 24 4
gpt4 key购买 nike

问题

我正在为一个简单的论坛创建一个数据库模型。用户应该能够创建主题、添加帖子并在帖子中张贴图片。

在一个 View 中,我想显示所有线程并且:

  • 获取主题中第一个帖子的字段以显示帖子/创建日期等的一部分(包括可选图片)
  • 获取线程中最后一个帖子的时间
  • 计算线程中的帖子数
  • 统计线程中的图像

我相信如果不对 n 线程执行 n 查询,这实际上是不可能的,所以真正的问题是如何重新设计数据库以实现这一点。

class Thread(models.Model):
sticky = models.BooleanField()
...

class Post(models.Model):
thread = models.ForeignKey('Thread')
image = models.OneToOneField('Image', null=True, blank=True, default=None)
date = models.DateTimeField()
...

class Image(models.Model):
image = models.ImageField(...)
...

我的部分解决方案

此时我知道如何计算帖子和图片,但我不知道如何同时获取第一篇帖子。我想在链接到第一个 PostThread 模型中添加额外的字段。

我的查询迫使我单独下载第一篇文章:

Thread.objects.annotate(
replies=Count('post'),
images=Count('post__image'),
last_reply=Max('post_date')
)

最佳答案

您可以使用子查询 对最近相关对象的单个字段进行注释:

comments = Comment.objects.filter(
post=OuterRef('pk')
).order_by('-timestamp').values('timestamp')
Post.objects.annotate(
last_comment_time=Subquery(comments[:1])
)

您可以通过这种方式在多个字段上进行注释,但这会损害性能(每个相关子查询单独运行,并且针对每一行,这比 N+1 查询好,但比单个连接差)。

您可以在单个字段上构建一个 JSON 对象,然后在以下位置对其进行注释:

comments = Comment.objects.filter(
post=OuterRef('pk')
).annotate(
data=models.expressions.Func(
models.Value('author'), models.F('author'),
models.Value('timestamp'), models.F('timestamp'),
function='jsonb_build_object',
output_field=JSONField()
),
).order_by('-timestamp').values('data')

(甚至可以将整个对象获取为 JSON,然后在 Django 中将其重新填充,但这有点老套)。


另一种解决方案可能是单独获取最近的评论,然后将它们与帖子合并:

comments = Comment.objects.filter(
...
).distinct('post').order_by('post', '-timestamp')
posts = Post.objects.filter(...).order_by('pk')

for post, comment in zip(posts, comments):
pass

您需要确保帖子和评论在此处的顺序相同:这些查询是。如果每个帖子都没有评论,这也会失败。

一个解决方法是将评论放入一个由帖子 ID 键入的字典中,然后为每个帖子获取匹配的评论。

comments = {
comment.post_id: comment
for comment in Comment.objects.distinct('post').order_by('post', '-timestamp')
}
for post in Post.objects.filter(...):
top_comment = comments.get(post.pk)
# whatever

关于python - Django 使用相关查询集的第一个元素进行注释,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23629431/

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