half-life
@half-life

Django Rest Framework как реализовать такой Serializer?

Всем добра :3 Пытаюсь разобратся с DRF и возникли такие вопросы.

Есть две модели:
models.py

@python_2_unicode_compatible
class AuthorModel(models.Model):
    first_name = models.CharField(max_length=50,
                                  verbose_name=_('First Name'), )
    last_name = models.CharField(max_length=50,
                                 verbose_name=_('Last Name'), )

    class Meta:
        ordering = ('pk',)
        unique_together = ('first_name', 'last_name')
        verbose_name = _('Author')
        verbose_name_plural = _('Authors')

    def __str__(self):
        return '{} {}'.format(self.first_name, self.last_name)

    def get_absolute_url(self):
        return reverse('author:author_detail', args=(self.pk,))

    def get_name(self):
        return '{} {}'.format(self.first_name, self.last_name)

    def get_book_count(self):
        return self.books.count()

    def get_books_url(self):
        return reverse('author:author_book_list', args=(self.pk,))


@python_2_unicode_compatible
class BookModel(models.Model):
    isbn = models.CharField(max_length=25,
                            validators=[isbn_validator],
                            verbose_name=_('ISBN'),
                            db_index=True,
                            unique=True)
    title = models.CharField(max_length=35,
                             verbose_name=_('Title'), )
    author = models.ForeignKey(AuthorModel,
                               related_name='books',
                               verbose_name=_('Author'), )
    description = models.TextField(verbose_name=_('Description'), )

    class Meta:
        ordering = ('pk',)
        verbose_name = _('Book')
        verbose_name_plural = _('Books')

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        return reverse('book:book_detail', args=(self.isbn,))

    def get_name(self):
        return self.title


и сериализотор:
serializer.py

class AuthorSerializer(serializers.ModelSerializer):
    name = serializers.CharField(source='get_name', read_only=True)
    url = serializers.CharField(source='get_absolute_url', read_only=True)
    book_count = serializers.CharField(source='get_book_count', read_only=True)
    books_url = serializers.CharField(source='get_books_url', read_only=True)

    class Meta:
        model = AuthorModel
        exclude = ('first_name', 'last_name')


при обращений к урлу '/api/v1.0/authors/' приходит ответ:
[
    {
        "id": 1,
        "name": "Mark Twain",
        "url": "/api/v1.0/authors/1/",
        "book_count": "4",
        "books_url": "/api/v1.0/authors/1/books/"
    },
    {
        "id": 2,
        "name": "Isaac Asimov",
        "url": "/api/v1.0/authors/2/",
        "book_count": "5",
        "books_url": "/api/v1.0/authors/2/books/"
    }
]

Но как подправить сериализотор что бы при обращении к урлу вида '/api/v1.0/authors/2' мне в ответе возвращало
все книги данного автора в формате `title`:'book_url`

Что то типа такого:
[
    {
        "id": 2,
        "name": "Isaac Asimov",
        "url": "/api/v1.0/authors/2/",
        "books": [
             {'title':'The Naked Sun', 'url':'api/v1.0/books/9780449242438/'},
             {'title':'I, Robot', 'url':'api/v1.0/books/9780246121004/'}
        ]
    }
]
  • Вопрос задан
  • 2464 просмотра
Решения вопроса 1
class BookSerializer(serializers.ModelSerilaizer):
    class Meta:
       model = Book
       fields = ('id', 'title', 'url')

class AuthorSerializer(serializers.ModelSerializer):
    name = serializers.CharField(source='get_name', read_only=True)
    url = serializers.CharField(source='get_absolute_url', read_only=True)
    book_count = serializers.CharField(source='get_book_count', read_only=True)
    books_url = serializers.CharField(source='get_books_url', read_only=True)
    books = BookSerializer(many=True, read_only=True)

    class Meta:
        model = AuthorModel
        exclude = ('first_name', 'last_name')

Ну и чтобы только в детальном view отображалось, разделите на два сериалайзера(AuthorListSerializer, AuthorRetrieveSerializer) и во view переопределите get_serializer_class
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
half-life
@half-life Автор вопроса
В итоге, благодаря ответу Абдулла Мурсалов, получилось вот так:

serializers.py
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from rest_framework import serializers

from src.apps.book.models import AuthorModel, BookModel


class BookAuthorSerializer(serializers.ModelSerializer):
    url = serializers.CharField(source='get_absolute_url', read_only=True)
    name = serializers.CharField(source='get_name', read_only=True)

    class Meta:
        model = AuthorModel
        exclude = ('id', 'first_name', 'last_name')


class BookSerializer(serializers.ModelSerializer):
    url = serializers.CharField(source='get_absolute_url', read_only=True)
    author = BookAuthorSerializer()

    class Meta:
        model = BookModel
        fields = '__all__'


class AuthorBookSerializer(serializers.ModelSerializer):
    url = serializers.CharField(source='get_absolute_url', read_only=True)

    class Meta:
        model = BookModel
        exclude = ('isbn', 'author')


class AuthorListSerializer(serializers.ModelSerializer):
    name = serializers.CharField(source='get_name', read_only=True)
    url = serializers.CharField(source='get_absolute_url', read_only=True)
    book_count = serializers.CharField(source='get_book_count', read_only=True)

    class Meta:
        model = AuthorModel
        exclude = ('first_name', 'last_name')


class AuthorRetrieveSerializer(AuthorListSerializer):
    books = AuthorBookSerializer(many=True, read_only=True)

    class Meta:
        model = AuthorModel
        exclude = ('book_count', 'first_name', 'last_name')

views.py
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from rest_framework import viewsets
from rest_framework_extensions.mixins import DetailSerializerMixin

from src.apps.book.models import AuthorModel, BookModel
from src.apps.book.permissions import IsAccountAdminOrReadOnly
from src.apps.book.serializers import AuthorListSerializer, AuthorRetrieveSerializer, BookSerializer


class AuthorViewSet(DetailSerializerMixin, viewsets.ModelViewSet):
    model = AuthorModel
    queryset = AuthorModel.objects.prefetch_related('books').all()
    serializer_class = AuthorListSerializer
    serializer_detail_class = AuthorRetrieveSerializer
    permission_classes = [
        IsAccountAdminOrReadOnly
    ]
    lookup_field = 'id'


class BookViewSet(viewsets.ModelViewSet):
    model = BookModel
    queryset = BookModel.objects.select_related('author').all()
    serializer_class = BookSerializer
    permission_classes = [
        IsAccountAdminOrReadOnly
    ]
    lookup_field = 'isbn'


Если кто-то знает как это зделать покрасивше, буду рад услышать.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы