Soy nuevo en Django y estoy creando un blog y una función de comentarios.
from django.db import models from django.contrib.auth import get_user_model class Blog(models.Model): user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE) title = models.CharField(max_length=200) content = models.TextField(max_length=200) class Comment(models.Model): user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE) blog = models.ForeignKey(Blog, on_delete=models.CASCADE) parent = models.ForeignKey('self', on_delete=models.CASCADE, null=True, blank=True, related_name="children") content = models.CharField(max_length=200)Estos son mis datos de prueba actuales
Comment.objects.all().values() <QuerySet [ {'id': 1, 'user_id': 1, 'blog_id': 1, 'parent_id': None, 'content': '1'}, {'id': 2, 'user_id': 1, 'blog_id': 1, 'parent_id': None, 'content': '2'}, {'id': 3, 'user_id': 1, 'blog_id': 1, 'parent_id': 1, 'content': '1-1'}, {'id': 4, 'user_id': 1, 'blog_id': 1, 'parent_id': 1, 'content': '1-2'} ]>Pero ahora quiero encontrar una estructura de árbol de este tipo, ¿qué debo hacer?
[ {'id': 1, 'user_id': 1, 'blog_id': 1, 'parent_id': None, 'content': '1', 'children': [ {'id': 3, 'user_id': 1, 'blog_id': 1, 'parent_id': 1, 'content': '1-1'}, {'id': 4, 'user_id': 1, 'blog_id': 1, 'parent_id': 1, 'content': '1-2'} ]}, {'id': 2, 'user_id': 1, 'blog_id': 1, 'parent_id': None, 'content': '2', 'children': [] }, ]No puede obtener un diccionario anidado con values . Podrías escribir esto:
Comment.objects.all().values('id', 'user_id', 'blog_id', 'parent_id', 'content', 'children')Pero el resultado no será el esperado, la lista contendrá un dict para cada combinación padre-hijo, por ejemplo:
[ {'id': 1, 'user_id': 1, 'blog_id': 1, 'parent_id': None, 'content': '1', children: 2}, {'id': 1, 'user_id': 1, 'blog_id': 1, 'parent_id': None, 'content': '1', children: 3}, {'id': 2, 'user_id': 1, 'blog_id': 1, 'parent_id': 1, 'content': '2', children: None}, {'id': 3, 'user_id': 1, 'blog_id': 1, 'parent_id': 1, 'content': '2', children: None}, ]Puede tratar directamente con el conjunto de consultas, por ejemplo:
for comment in Comment.objects.all().prefetch_related('children'): for child in comment.children.all(): print(child.id)O puede usar una comprensión de lista anidada (el resultado será el que esperaba):
print([{'id': comment.id, 'user_id': comment.user.id, 'blog_id': comment.blog.id, 'parent_id': comment.parent.id if comment.parent != None else None, 'content': comment.content, 'children': [{'id': child.id, 'user_id': child.user.id, 'blog_id': child.blog.id, 'parent_id': child.parent.id, 'content': child.content} for child in comment.children.all()]} for comment in Comment.objects.all()])Yo uso la recursividad para consultar
def get_children(c): return { 'id': c.id, 'user_id': c.user_id, 'blog_id': c.blog_id, 'parent_id': c.parent_id, 'content': c.content, 'children': list(map(get_children, c.children.all())), } def get_comment_tree(): return list(map(get_children, Comment.objects.filter(parent=None).prefetch_related('children')))json de salida
[{ "id": 1, "user_id": 1, "blog_id": 1, "parent_id": null, "content": "1", "children": [{ "id": 3, "user_id": 1, "blog_id": 1, "parent_id": 1, "content": "1-1", "children": [{ "id": 5, "user_id": 1, "blog_id": 1, "parent_id": 3, "content": "1-1-1", "children": [] }] }, { "id": 4, "user_id": 1, "blog_id": 1, "parent_id": 1, "content": "1-2", "children": [] }] }, { "id": 2, "user_id": 1, "blog_id": 1, "parent_id": null, "content": "2", "children": [] }]