How to group two same values and get value from other field in django, DRF
Question:
I am struggling with grouping two same field values and displaying their related values in one response.
models.py:
class Book(models.Model):
user = models.ForeignKey(User, on_delete = models.CASCADE, null = True, blank = True)
image = models.ImageField(default = "Nana.jpg", upload_to = 'images/', null = True, blank = True)
title = models.CharField(max_length = 150, unique = True)
author = models.CharField(max_length = 100)
category = models.CharField(max_length = 100)
description = models.TextField(max_length = 5000, null = True, blank = True)
published_date = models.DateField(null = True, blank = True)
language = models.CharField(max_length = 100, null = True, blank = True, default = "Not selected")
read_book_count = models.IntegerField(default = 0)
def __str__(self):
return self.title
Views.py:
class BookAuthors(APIView):
def get(self, request):
author = Book.objects.all()
serializer = AuthorSerializer(author, many = True)
return Response(serializer.data)
serializers.py
class AuthorSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = ['title', 'author']
urls.py
path('library/api/authors/', views.BookAuthors.as_view()),
I want to combine author Homer and his two titles in same place not to be separated.
Answers:
You need to use the query with distinct authors
and change your serializer.
Views.py
class BookAuthors(APIView):
def get(self, request):
author = Book.objects.distinct('author')
serializer = AuthorSerializer(author, many = True)
return Response(serializer.data)
serializers.py
class AuthorSerializer(serializers.ModelSerializer):
titles = serializers.SerializerMethodField()
class Meta:
model = Book
fields = ['author', 'titles']
def get_titles(self, book):
return list(Book.objects.filter(author=book.author).values_list('title', flat=True))
Output will be like this
[
...
{
"author": "author1",
"titles": ["title1", "title2"]
},
...
]
You can solve your problem by using values
method that groups your rows depend on fields you pass to it. So the code becomes something like this:
(Just note that ArrayAgg
can be used only with PostgreSQL
)
views.py
from django.contrib.postgres.aggregates import ArrayAgg
class BookAuthors(APIView):
def get(self, request):
authors = Book.objects
.values('author')
.annotate(titles=ArrayAgg('title'))
serializer = AuthorSerializer(authors, many=True)
return Response(serializer.data)
serializer.py
class AuthorSerializer(serializers.ModelSerializer):
titles = serializers.ListField(child=serializers.CharField())
class Meta:
model = Book
fields = ['titles', 'author']
I am struggling with grouping two same field values and displaying their related values in one response.
models.py:
class Book(models.Model):
user = models.ForeignKey(User, on_delete = models.CASCADE, null = True, blank = True)
image = models.ImageField(default = "Nana.jpg", upload_to = 'images/', null = True, blank = True)
title = models.CharField(max_length = 150, unique = True)
author = models.CharField(max_length = 100)
category = models.CharField(max_length = 100)
description = models.TextField(max_length = 5000, null = True, blank = True)
published_date = models.DateField(null = True, blank = True)
language = models.CharField(max_length = 100, null = True, blank = True, default = "Not selected")
read_book_count = models.IntegerField(default = 0)
def __str__(self):
return self.title
Views.py:
class BookAuthors(APIView):
def get(self, request):
author = Book.objects.all()
serializer = AuthorSerializer(author, many = True)
return Response(serializer.data)
serializers.py
class AuthorSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = ['title', 'author']
urls.py
path('library/api/authors/', views.BookAuthors.as_view()),
I want to combine author Homer and his two titles in same place not to be separated.
You need to use the query with distinct authors
and change your serializer.
Views.py
class BookAuthors(APIView):
def get(self, request):
author = Book.objects.distinct('author')
serializer = AuthorSerializer(author, many = True)
return Response(serializer.data)
serializers.py
class AuthorSerializer(serializers.ModelSerializer):
titles = serializers.SerializerMethodField()
class Meta:
model = Book
fields = ['author', 'titles']
def get_titles(self, book):
return list(Book.objects.filter(author=book.author).values_list('title', flat=True))
Output will be like this
[
...
{
"author": "author1",
"titles": ["title1", "title2"]
},
...
]
You can solve your problem by using values
method that groups your rows depend on fields you pass to it. So the code becomes something like this:
(Just note that ArrayAgg
can be used only with PostgreSQL
)
views.py
from django.contrib.postgres.aggregates import ArrayAgg
class BookAuthors(APIView):
def get(self, request):
authors = Book.objects
.values('author')
.annotate(titles=ArrayAgg('title'))
serializer = AuthorSerializer(authors, many=True)
return Response(serializer.data)
serializer.py
class AuthorSerializer(serializers.ModelSerializer):
titles = serializers.ListField(child=serializers.CharField())
class Meta:
model = Book
fields = ['titles', 'author']