使用 Prefetch Django

问题描述

我有 2 个模型:发布和评论。像这样:

class Post(models.Model):
    content = models.TextField()

class Comment(models.Model)
    content = models.TextField()
    owner = models.ForeignKey(User,null=False,on_delete=models.CASCADE)
    post_parent = models.ForeignKey(
        Post,on_delete=models.CASCADE,db_column='post_parent',related_name='comments',)
    comment_ref = models.ForeignKey(
        'self',null=True,related_name='children_comment'
    )

假设评论可以有 1 个级别的子评论。使用帖子的 ID,我想获得 5 条最新评论(不是子评论),每条评论都预取了 3 条最新的子评论。 搜索后我目前的实现是:

sub_comments = Comment.objects.filter(
                  comment_ref=OuterRef('pk'),post_parent=post_id
               ).order_by('-timestamp').values_list('id',flat=True)[:3]
queryset = Comment.objects.filter(
               comment_ref=None,post_parent=post_id
           ).select_related('owner').prefetch_related(
                    Prefetch('children_comment',queryset=Comment.objects.filter(
                    id__in=Subquery(sub_comments)
                ),to_attr="cmt"))

那行不通。它不限制预取子评论的数量。请帮帮我 :D

解决方法

您将需要 Comment 表中的日期字段,以便您可以显示最新评论和子评论。

我将在这里介绍另一种模型,以便为我个人查询和编写测试更容易。 模型.py

class Post(models.Model):
    content = models.TextField()


class Comment(models.Model)
    content = models.TextField()
    owner = models.ForeignKey(User,null=False,on_delete=models.CASCADE)
    post_parent = models.ForeignKey(
        Post,on_delete=models.CASCADE,db_column='post_parent',related_name='comments',)
    date_posted = models.DateTimeField()


class ChildComment(models.Model):
    parent_comment = models.ForeignKey(
        Comment,null=True,related_name="child_comments"
    )

视图.py

post = Post.objects.get(id=<some_id>)
comments = Comment.objects.filter(
    post_parent_id=post.id
).prefetch_related(
    'child_comments'
).order_by(
    '-date_posted'
)[:5]

recent_comments = {}
for comment in comments:
    recent_comments[comment] = [
        comment.child_comments.all().order_by(
            '-parent_comment__date_posted'
        )[:3]
    ]

recent_comments 传递给模板 context,然后在模板文件中使用它,例如:

{% for recent_comment,child_comments in recent_comments.items %}
    {{ recent_comment.content }}
    {% for child_comment in child_comments  %}
        {{ child_comment.content }}
    {% endfor %}
{% endfor %}
,

您需要一个 DateTimeField 来获取 order_by 中的最新评论和子评论,但此查询应该可以工作。如果您要返回数千条评论,这可能不太理想,但一次只有 5 条,这会很快。

comments = Comment.objects.filter(
    post_parent_id=post.id
)[:5]
root_comment_ids = [comment.id for comment in comments]

child_comments = Comment.objects.filter(
    comment_ref_id__in=root_comment_ids
)[:3]

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...