DRF как получить группировку элементов по категориям

Я понимаю, что мой вопрос часто повторяется, но я застрял на этом. Я хочу сделать простой api с DRF. У меня есть две модели:

models.py

class Rubrics(models.Model):
    id = models.AutoField(primary_key=True)
    rubric = models.CharField(max_length=255, blank=True, null=True)

class Books(models.Model):
    id = models.AutoField(primary_key=True)
    title = models.CharField(max_length=255, blank=True, null=True)
    author = models.CharField(max_length=255, blank=True, null=True)
    date = models.CharField(max_length=255, blank=True, null=True)
    rubrics = models.ForeignKey('Rubrics', on_delete=models.DO_NOTHING, related_name='books', blank=True, null=True)

Я хотел бы просмотреть сериализованный результат следующим образом:

[
    rubric1: [
        {
         title: "title1",
         author:"author1"
        }, 
        book_obj2,
        so on
    ],
    rubric2: [
        book_obj4,
        book_obj5
    ]
]

my views.py:

class BooksByRubricView(APIView):
    """List of books by rubrics"""

    def get(self, request):
        last_date = Books.objects.latest("date").date
        books_last = Books.objects.filter(date=last_date)
        serializer = RubricsSerializer(books_last, many=True)
        return Response(serializer.data)

Я пробую много примеров в этой теме,

sorry this garbage
class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Books
        #fields = ("title",)
        exclude = ()

class RubricsSerializer(serializers.ModelSerializer):
    rubrics = BookSerializer(read_only=True)
    class Meta:
        model = Rubrics
        fields = ("rubrics",)
        #exclude = ()
"""
class RubricSerializer(serializers.ModelSerializer):
    #rubrics = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
    #books = RecursiveSerializer(many=True)
    #print(books)
    rubrics = RubricSerializer(read_only=True)
    #books = BooksListSerializer(many=True)
    class Meta:
        model = Books
        fields  = ("title", "rubrics",)
        #fields = ['rubric', 'rubrics']
        #fields = ['books', 'rubrics']
"""

но возможно я не понимаю принципов обратных связей и сериализации в DRF. Пожалуйста, подскажите мне WAIDW. Спасибо.

В модели rubrics отсутствует поле Rubrics, доступны следующие поля:

Book имеют одну рубрику (внешний ключ rubrics), а рубрики имеют несколько книг (books_set). Я бы также предложил изменить имя FK с rubrics на rubric, так как он может быть только один.

Попробуйте это и работайте дальше:

class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Books
        #fields = ("title",)
        exclude = ()

class RubricsSerializer(serializers.ModelSerializer):
    class Meta:
        model = Rubrics
        fields = ("books_set",)
        #exclude = ()

Сначала я попытался получить результат, который вы хотели, используя ваше представление, но ничего не получилось! Поэтому я создал другое представление:

from .serializers import *
from rest_framework import generics
from .models import *


class BooksByRubricView(generics.ListAPIView):
    serializer_class = RubricsSerializer
    queryset = Rubric.objects.all()
    # You should try!

Конечно, мне также пришлось создать путь (только для тестов! Не обращайте внимания!):

from django.urls import path
from .views import BooksByRubricView

urlpatterns = [
    path('books/', BooksByRubricView.as_view(), name='books')
]

В ваших моделях:

from django.db import models


class Rubric(models.Model):
    id = models.AutoField(primary_key=True)  # Do not use plural in the models name!
    rubric_name = models.CharField(max_length=255, blank=True, null=True)

    class Meta:
        ordering = ['id']  # Create a ordering!

    def __str__(self):
        return self.rubric_name


class Book(models.Model):
    rubric = models.ForeignKey(Rubric, related_name='rubrics', on_delete=models.CASCADE)
    id = models.AutoField(primary_key=True)
    title = models.CharField(max_length=255, blank=True, null=True)
    author = models.CharField(max_length=255, blank=True, null=True)
    date = models.CharField(max_length=255, blank=True, null=True)

    class Meta:
        ordering = ['id']  # Create a ordering!

В вашем файле serializers.py:

from rest_framework import serializers
from .models import *


class BookSerializer(serializers.ModelSerializer):

    class Meta:
        model = Book
        fields = (
            "title",
            "author",
            "date"

        )


class RubricsSerializer(serializers.ModelSerializer):

    rubrics = BookSerializer(many=True, read_only=True)

    class Meta:
        model = Rubric
        fields = (
            "id",  # Put an Id if you want!
            "rubrics",
        )

Возможно, проблема была только в вашем представлении! Поэтому я просто сделал все это, чтобы получить результат, который вы хотите, но локально; изображения результата: enter image description here

Вернуться на верх