Невозможно получить связанные данные из поля ManyToManyField

Я пытаюсь получить связанные объекты из двух нижеприведенных моделей.

Следующие модели django с отношениями ManyToManyField.

Книга

class Book(models.Model):
authors = models.ManyToManyField(
    to=Author, verbose_name="Authors", related_name="books_author"
)
bookshelves = models.ManyToManyField(
    to=Bookshelf, verbose_name="Bookshelf", related_name="books_shelves"
)
copyright = models.NullBooleanField()
download_count = models.PositiveIntegerField(blank=True, null=True)
book_id = models.PositiveIntegerField(unique=True, null=True)
languages = models.ManyToManyField(
    to=Language, verbose_name=_("Languages"), related_name="books_languages"
)

Автор

class Author(models.Model):
birth_year = models.SmallIntegerField(blank=True, null=True)
death_year = models.SmallIntegerField(blank=True, null=True)
name = models.CharField(max_length=128)

def __str__(self):
    return self.name

class Meta:
    verbose_name = _("Author")
    verbose_name_plural = _("Author")

Мне нужно найти все Auhtors и связанные с ними книги. Я перепробовал множество различных способов, но ни один из них мне не помог.

Первый способ : использование prefetch_related

class AuthorListAPIView(APIErrorsMixin, generics.ListAPIView):

serializer_class = AuthorSerializer
queryset = Author.objects.exclude(name__isnull=True)

def get_queryset(self):
    auths = queryset.prefetch_related(Prefetch("books_author"))

Второй способ с использованием родственного_имени 'books_auhtor'

class AuthorListAPIView(APIErrorsMixin, generics.ListAPIView):

serializer_class = AuthorSerializer
queryset = Author.objects.exclude(name__isnull=True)

def get_queryset(self):
    auths = queryset.books_author.all()

Ни один из вышеперечисленных способов мне не помог. Я хочу подготовить список авторов и связанных с ними книг.

Например:-

[{'Author1':['Book1','Book2'],... }]

Префетчинг не является необходимым, но может быть использован для повышения эффективности, вы можете работать с:

class AuthorListAPIView(APIErrorsMixin, generics.ListAPIView):
    serializer_class = AuthorWithBooksSerializer
    queryset = Author.objects.exclude(name=None).prefetch_related('books_author')

В AuthorWithBooksSerializer затем можно добавить данные книги, например:

from rest_framework import serializers


class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = ('book_id', 'copyright')


class AuthorWithBooksSerializer(serializers.ModelSerializer):
    books = BookSerializer(source='books_author', many=True)

    class Meta:
        model = Author
        fields = ('name', 'books')

Здесь books будет использовать BookSerializer и таким образом кодировать список словарей.

Хотя вы можете использовать имя автора в качестве ключа объекта, я сильно не советую этого делать: это делает объект менее доступным, поскольку ключи больше не фиксированы, и если они содержат пробелы, это также может привести к большим проблемам с получением значения(й), связанного с данным именем атрибута.

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