(对不起我的英文)
我正在学习Python和Django。现在,我的挑战是开发线程通用评论系统。有两种模式,帖子和评论。
-Post可以评论。
-Comment可以评论。 (环形/螺纹)
- 系统中不应该是n + 1查询问题。 (无论有多少评论,都不应该增加查询次数)
我目前的模特是这样的:
class Post(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
child = generic.GenericRelation(
'Comment',
content_type_field='parent_content_type',
object_id_field='parent_object_id'
)
class Comment(models.Model):
content = models.TextField()
child = generic.GenericRelation(
'self',
content_type_field='parent_content_type',
object_id_field='parent_object_id'
)
parent_content_type = models.ForeignKey(ContentType)
parent_object_id = models.PositiveIntegerField()
parent = generic.GenericForeignKey(
"parent_content_type", "parent_object_id")
我的模特是对的吗?如何在没有n + 1查询问题的情况下获得帖子的所有评论(带层次结构)?
注意:我知道mttp和其他模块,但我想学习这个系统。
编辑:我运行“Post.objects.all().prefetch_related("child").get(pk=1)
”命令,这给了我帖子及其子评论。但是当我想获得child命令的child命令时,一个新的查询正在运行。我可以将命令更改为...prefetch_related("child__child__child...")...
,然后仍然为每个深层的子父关系运行一个新查询。有没有人有解决这个问题的想法?
答案 0 :(得分:2)
如果您想通过单个查询获得对帖子的所有评论,那么将每个评论链接到相关帖子会很好。您可以使用单独的链接指示父评论。
基本上:
class Post(models.Model):
...
comments = models.ManyToManyField('Comment')
# link to all comments, even children of comments
class Comment(models.Model):
...
child_comments = models.ManyToManyField('Comment')
# You may find it easier to organise these into a tree
# if you use a parent_comment ForeignKey. That way the
# top level comments have no parent and can be easily spotted.
Post.objects.all().select_related('comments').get(pk=1)
这里的多对多需要a little extra work来创建关联,因为它使用了一个中间表。如果您想要一个纯one to many,那么您需要ForeignKey
上的Comment
,但是您只能使用prefetch_related
而不是select_related
,然后才会涉及PostitiveIntegerField
额外的数据库命中。
这也更好,因为你没有无类型的外键引用(你的{{1}})。
然后,您需要将注释排列到树结构中,但这不在您的问题范围内。