Alex Yu
Alex Yu

Reputation: 25

How to get with query nested comments?

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?

Upvotes: 1

Views: 301

Answers (1)

PTomasz
PTomasz

Reputation: 1718

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']

Upvotes: 1

Related Questions