37👍
The queryset returned from get_queryset provides the list of things that will go through the serializer, which controls how the objects will be represented. Try adding an additional field in your Book serializer, like:
author_count = serializers.IntegerField(
source='author_set.count',
read_only=True
)
Edit: As others have stated, this is not the most efficient way to add counts for cases where many results are returned, as it will hit the database for each instance. See the answer by @José for a more efficient solution.
97👍
The accepted solution will hit the database as many times as results are returned. For each result, a count
query to the database will be made.
The question is about adding annotations to the serializer, which is way more effective than doing a count
query for each item in the response.
A solution for that:
models.py
class Author(models.Model):
name = models.CharField(...)
other_stuff = models...
...
class Book(models.Model):
author = models.ForeignKey(Author)
title = models.CharField(...)
publication_year = models...
...
serializers.py
class BookSerializer(serializers.ModelSerializer):
authors = serializers.IntegerField()
class Meta:
model = Book
fields = ('id', 'title', 'authors')
views.py
class BookViewSet(viewsets.ModelViewSet):
queryset = Book.objects.annotate(authors=Count('author'))
serializer_class = BookSerializer
...
That will make the counting at database level, avoiding to hit database to retrieve authors count for each one of the returned Book
items.
- [Django]-Django Rest Framework partial update
- [Django]-Django Admin – Disable the 'Add' action for a specific model
- [Django]-What is the difference render() and redirect() in Django?
8👍
Fiver’s solution will hit the db for every instance in the queryset so if you have a large queryset, his solution will create a lot of queries.
I would override the to_representation of your Book serializer, it reuses the result from the annotation. It will look something like:
class BookSerializer(serializers.ModelSerializer):
def to_representation(self, instance):
return {'id': instance.pk, 'num_authors': instance.authors__count}
class Meta:
model = Book
- [Django]-Customize/remove Django select box blank option
- [Django]-Django contrib admin default admin and password
- [Django]-Navigation in django
0👍
So, if you make an annotation like
Model.objects.annotate(
some_new_col=Case(
When(some_field=some_value, then=Value(something)),
# etc...
default=Value(something_default),
output_field=SomeTypeOfField(),
)
).filter()#etccc
and the interpreter throws in an error that something
is not a model field for the related serializer
, there is a workaround. It’s not nice but if you add a method some_new_col
, it recognizes the value from the query above.
The following will do just fine.
def some_new_col(self):
pass;
- [Django]-Where should utility functions live in Django?
- [Django]-How to chcek if a variable is "False" in Django templates?
- [Django]-Django render_to_string missing information
0👍
Im doing it in elegant way in DRF, creating custom model manager
## models.py
from . import custom_managers
class MyModel(models.Model):
field=...
#
objects=models.Manager() # default model manager MyModel.objects.all()
annotate_objects=custom_managers.MyModelSummary()
## custom_managers.py
class MyModelSummary(models.Manager):
def get_queryset(self):
queryset = (super().get_queryset()
.values('date__month','date__year')
.annotate(total=models.Count('price'))
.annotate(sum=models.Sum('price'))
.order_by('date__year','date__month')
.values('date__month',
'date__year',
'total',
'sum')
)
return queryset
## summary_serializers.py
class MyModelSummarySerializer(serializers.ModelSerializer):
month=serializers.IntegerField(source='date__month')
year=serializers.IntegerField(source='date__year')
total=serializers.IntegerField()
sum=serializers.IntegerField()
class Meta:
model = MyModel
fields =['month','year','total','sum']
## summery_views.py
class MyModelSummaryListView(ReadOnlyModelViewSet):
queryset=MyModel.annotate_objects.all()
serializer_class=MyModelSummarySerializer
- [Django]-Any thoughts on A/B testing in Django based project?
- [Django]-Sending images using Http Post
- [Django]-Is the Lift framework as "easy" as Ruby on Rails or Django?