Home > Software engineering >  How to get with query nested comments?
How to get with query nested comments?

Time:04-26

I am new to django. I'm trying to deal with queries on nested comments. There is a blog project with adding articles and adding comments to articles. For each comment, you can recursively add a comment, and so on.

├── blog_api
│   ├── asgi.py
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├──── blog_api/api
|    ├── admin.py
|    ├── apps.py
|    ├── __init__.py
|    ├── migrations
|    │   └── __init__.py
|    ├── models.py
|    ├── permissions.py
|    ├── serializers.py
|    ├── tests.py
|    ├── urls.py
|    └── views.py
└── manage.py

I described the following models

api/models.py

from django.db import models

class Article(models.Model):
    date_pub = models.DateTimeField(auto_now_add=True)
    title = models.CharField (max_length = 60,  blank=True, default='')
    text = models.TextField(blank=True, default='')
    owner = models.ForeignKey('auth.User', related_name='posts', on_delete=models.CASCADE)

    class Meta:
        ordering = ['date_pub']


class Comment(models.Model):
    date_pub = models.DateTimeField(auto_now_add=True)
    text = models.TextField(blank=False)
    owner = models.ForeignKey('auth.User', related_name='comments', on_delete=models.CASCADE)
    article = models.ForeignKey('Article', related_name='comments', on_delete=models.CASCADE)
    parent = models.ForeignKey('self', related_name='reply_set', null=True, on_delete=models.PROTECT)

    class Meta:
        ordering = ['date_pub']

api/serializers.py

from rest_framework import serializers
from api.models import Article
from api.models import Comment

from django.contrib.auth.models import User

class ArticleSerializer(serializers.ModelSerializer):
    owner = serializers.ReadOnlyField(source='owner.username')
    comments = serializers.PrimaryKeyRelatedField(many=True, read_only=True)

    class Meta:
        model = Article
        fields = ['id', 'title', 'text', 'owner', 'comments']


class UserSerializer(serializers.ModelSerializer):
    posts = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
    comments = serializers.PrimaryKeyRelatedField(many=True, read_only=True)

    class Meta:
        model = User
        fields = ['id', 'username', 'posts', 'comments']


class RecursiveSerializer(serializers.Serializer):
    def to_representation(self, value):
        serializer = self.parent.parent.__class__(value, context=self.context)
        return serializer.data


class CommentSerializer(serializers.ModelSerializer):
    owner = serializers.ReadOnlyField(source='owner.username')
    reply_set = RecursiveSerializer(many=True, read_only=True)

    class Meta:
        model = Comment
        fields = ['id', 'text', 'owner', 'article', 'parent', 'reply_set']

The GET query returns the following comment structure:

HTTP 200 OK
Allow: GET, POST, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

[
    {
        "id": 1,
        "text": "First comment",
        "owner": "alex",
        "article": 1,
        "parent": null,
        "reply_set": [
            {
                "id": 2,
                "text": "Comment to comment",
                "owner": "alex",
                "article": 1,
                "parent": 1,
                "reply_set": []
            }
        ]
    },
    {
        "id": 2,
        "text": "Comment to comment",
        "owner": "alex",
        "article": 1,
        "parent": 1,
        "reply_set": []
    },
    {
        "id": 3,
        "text": "Second article comment",
        "owner": "alex",
        "article": 2,
        "parent": null,
        "reply_set": [
            {
                "id": 4,
                "text": "Comment to second article comment",
                "owner": "alex",
                "article": 1,
                "parent": 3,
                "reply_set": [
                    {
                        "id": 5,
                        "text": "some comment",
                        "owner": "alex",
                        "article": 1,
                        "parent": 4,
                        "reply_set": [
                            {
                                "id": 6,
                                "text": "some more comment",
                                "owner": "alex",
                                "article": 1,
                                "parent": 5,
                                "reply_set": []
                            }
                        ]
                    }
                ]
            }
        ]
    },
    {
        "id": 4,
        "text": "Comment to second article comment",
        "owner": "alex",
        "article": 1,
        "parent": 3,
        "reply_set": [
            {
                "id": 5,
                "text": "some comment",
                "owner": "alex",
                "article": 1,
                "parent": 4,
                "reply_set": [
                    {
                        "id": 6,
                        "text": "some more comment",
                        "owner": "alex",
                        "article": 1,
                        "parent": 5,
                        "reply_set": []
                    }
                ]
            }
        ]
    },
    {
        "id": 5,
        "text": "some comment",
        "owner": "alex",
        "article": 1,
        "parent": 4,
        "reply_set": [
            {
                "id": 6,
                "text": "some more comment",
                "owner": "alex",
                "article": 1,
                "parent": 5,
                "reply_set": []
            }
        ]
    },
    {
        "id": 6,
        "text": "some more comment",
        "owner": "alex",
        "article": 1,
        "parent": 5,
        "reply_set": []
    }
]

I have no idea for solving the following problems:

How to get all comments for this comment, which is at the third nesting level?

How can a tree structure be recreated from the comments API response?

Sending API request localhost:8000/comments/1 I receive the comment with id="1" and all nested comments to the third level. How to make request getting the third level nesting comment and all others? What should be written in views and urls?

CodePudding user response:

Could you check if this code works for you?

class FinalLevelRepliesSerializer(serializers.ModelSerializer):
    owner = serializers.ReadOnlyField(source='owner.username')

    class Meta:
        model = Comment
        fields = ['id', 'text', 'owner', 'article', 'parent']

class FirstLevelRepliesSerializer(serializers.ModelSerializer):
    owner = serializers.ReadOnlyField(source='owner.username')
    reply_set = FinalLevelRepliesSerializer(many=True, read_only=True)
    class Meta:
        model = Comment
        fields = ['id', 'text', 'owner', 'article', 'parent', 'reply_set']

class CommentSerializer(serializers.ModelSerializer):
    owner = serializers.ReadOnlyField(source='owner.username')
    reply_set = FirstLevelRepliesSerializer(many=True, read_only=True)

    class Meta:
        model = Comment
        fields = ['id', 'text', 'owner', 'article', 'parent', 'reply_set']
  • Related