Package: queryset-annotations
django_queryset_annotationsThedjango_queryset_annotationslibrary provides a way to add annotations to Django querysets. Annotations are additional fields that are calculated on the fly and added to the queryset results. This can be particularly useful when you want to add computed fields to your models without having to modify the underlying database schema.InstallationYou can installdjango_queryset_annotationsvia pip:pipinstallqueryset-annotationsUsageTo use thedjango_queryset_annotationslibrary, you first need to create an annotation class. An annotation class is a subclass of theBaseAnnotationclass. TheBaseAnnotationclass provides a number of methods that you can use to define the annotation, such as thename,output_field, andget_expression()methods.ExampleConsider the following models:fromdjango.dbimportmodelsclassBook(models.Model):title=models.CharField(max_length=100)author=models.ForeignKey("Author",on_delete=models.CASCADE,related_name="books")classAuthor(models.Model):name=models.CharField(max_length=100)age=models.IntegerField()You can create an annotation class to count the number of books for each author:fromdjango.dbimportmodelsfromqueryset_annotations.baseimportBaseAnnotationclassBookCountAnnotation(BaseAnnotation):name="book_count"output_field=models.IntegerField()defget_expression(self):returnmodels.Count("books",distinct=True)Then, create a proxy model for theAuthormodel:fromqueryset_annotations.proxy.modelimportBaseProxyModelclassAuthorProxyModel(BaseProxyModel):book_count=BookCountAnnotation()classMeta:model=AuthorYou can now use this proxy model in your serializers and viewsets:fromrest_frameworkimportserializersfromrest_framework.viewsetsimportModelViewSetclassAuthorSerializer(serializers.ModelSerializer):classMeta:model=AuthorProxyModelfields="__all__"classBookSerializer(serializers.ModelSerializer):classMeta:model=Bookfields="__all__"classAuthorViewSet(ModelViewSet):queryset=AuthorProxyModel.objects.all()serializer_class=AuthorSerializerclassBookViewSet(ModelViewSet):queryset=Book.objects.all()serializer_class=BookSerializerWith this setup, when you retrieve an author from the API, you will also get the count of books they have written.Advanced UsageThedjango_queryset_annotationslibrary also provides aBaseContextManagerand anAnnotatedQuerysetMixinfor more advanced use cases. TheBaseContextManagercan be used to manage the context of the annotation, and theAnnotatedQuerysetMixincan be used to automatically annotate the queryset in a viewset.Here is an example of how to use these features:fromdjango.dbimportmodelsfromrest_frameworkimportserializersfromrest_framework.viewsetsimportModelViewSetfromannotation.modelsimportAuthor,Bookfromqueryset_annotations.baseimportBaseAnnotation,BaseContextManagerfromqueryset_annotations.drf.viewsimportAnnotatedQuerysetMixinfromqueryset_annotations.proxy.modelimportBaseProxyModelclassBookCountAnnotation(BaseAnnotation):name="book_count"output_field=models.IntegerField()defget_expression(self,*,context_manager:BaseContextManager=None):returnmodels.Count("books",distinct=True)classAuthorProxyModel(BaseProxyModel):book_count=BookCountAnnotation()classMeta:model=AuthorclassAuthorSerializer(serializers.ModelSerializer):user=serializers.HiddenField(default=serializers.CurrentUserDefault())classMeta:model=AuthorProxyModelfields="__all__"classBookSerializer(serializers.ModelSerializer):classMeta:model=Bookfields="__all__"classAuthorViewSet(AnnotatedQuerysetMixin,ModelViewSet):annotation_context_class=BaseContextManagerannotated_model=AuthorProxyModelserializer_class=AuthorSerializerdefget_queryset(self):context_manager=self.annotation_context_class(self.get_serializer_context())returnself.queryset.get_annotated_queryset(context_manager=context_manager)classBookViewSet(ModelViewSet):queryset=Book.objects.all()serializer_class=BookSerializerIn this example, theAuthorViewSetuses theAnnotatedQuerysetMixinand aBaseContextManagerto automatically annotate the queryset with the book count.ConclusionThedjango_queryset_annotationslibrary provides a powerful and flexible way to add computed fields to your Django models. Whether you need to add simple counts or more complex calculations, this library can help you keep your code clean and maintainable.