Я создаю приложение Django с рекурсивной структурой комментариев.
Проблема: Рекурсивный характер структуры данных моих комментариев означает, что я изо всех сил пытаюсь написать запрос, чтобы аннотировать каждый пост числом ответов, а затем перебирать эти сообщения / ответы в моем шаблоне. .
Модель комментариев, которую я построил, различает ответы на сообщения (которые являются комментариями верхнего уровня) и комментарии (которые являются ответами на другие комментарии).
(Post)
3 Total Comments
-----------------
one (post reply)
└── two (comment reply)
└── three (comment reply)
(more)
Я представил следующий комментарий:
class Comment(TimeStamp):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
content = models.TextField(max_length=2000)
post = models.ForeignKey("Post", on_delete=models.CASCADE, related_name="comments")
# Top level comments are those that aren't replies to other comments
reply = models.ForeignKey(
"self", on_delete=models.PROTECT, null=True, blank=True, related_name="replies"
)
Это работает очень хорошо, пи c связано
Что работает
Я могу предварительно выбрать все ответы на комментарии для сообщения следующим образом:
comment_query = Comment.objects.annotate(num_replies=Count("replies"))
post = Post.objects.prefetch_related(Prefetch("comments", comment_query)).get(id="1")
, который правильно отображает количество ответов для каждого комментарий:
>>> post.comments.values_list('num_replies')
<QuerySet [(1,), (1,), (0,)]>
Что не работает
Этот запрос аннотирует только верхний уровень post.comments
>>> post.comments.first().replies.all()
<QuerySet [<Comment: two>]>
>>> post.comments.first().replies.first().num_replies
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-132-8151a7d13021> in <module>
----> 1 post.comments.first().replies.first().num_replies
AttributeError: 'Comment' object has no attribute 'num_replies'
Для правильной визуализации по шаблону мне нужно перебирать comment.replies
для каждого ответа верхнего уровня. Поэтому во всех вложенных ответах на комментарии отсутствует исходная аннотация num_replies
.
В моей логике шаблона / представления c Я отображаю деревья комментариев примерно со следующими логиками c:
{% for comment in post.comments.all %}
{% if not comment.reply %}
{% include "posts/comment_tree.html" %}
{% endif %}
{% endfor %}
Где post/comments_tree.html
содержит:
{{ post.content }}
{% for reply in comment.replies.all %}
{% include "posts/comment_tree.html" with comment=reply %}
{% endfor %}
Что я уже пробовал
Я могу обойти эту проблему в некоторой степени, выполнив следующие действия, которые аннотируют первый уровень ответов :
comment_query = Comment.objects.prefetch_related(
Prefetch("replies", Comment.objects.annotate(num_replies=Count("replies")))
).annotate(num_replies=Count("replies"))
Это успешно аннотирует второй комментарий, который является вложенным ответом
>>> post.comments.first().replies.first().num_replies
1
Но он не будет работать для дальнейших вложенных комментариев (т. Е. Третьего)
>>> post.comments.first().replies.first().replies.first().num_replies
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-127-7d5b9798b7b1> in <module>
----> 1 post.comments.first().replies.first().replies.first().num_replies
AttributeError: 'Comment' object has no attribute 'num_replies'
Очевидно, что этот подход полностью ошибочен, так как я буду вынужден добавить вложенный оператор Prefetch для общего количества вложенных комментариев, которые я хочу поддержать. В идеале мне бы хотелось решение, которое позволило бы мне аннотировать вложенную (самореференциальную) структуру данных.
TLDR: возможен ли этот тип запроса даже в ORM Django, или мне придется достичь SQL?