Django's QuerySet has two methods, annotate and aggregate. The documentation says that:
Unlike aggregate(), annotate() is not a terminal clause. The output of the annotate() clause is a QuerySet. https://docs.djangoproject.com/en/4.1/topics/db/aggregation/#generating-aggregates-for-each-item-in-a-queryset
Is there any other difference between them? If not, then why does aggregate exist?


That's the main difference, but aggregates also work on a grander scale than annotations. Annotations are inherently related to individual items in a queryset. If you run an
Countannotation on a something like a many-to-many field, you'll get a separate count for each member of the queryset (as an added attribute). If you were to do the same with an aggregation, however, it would attempt to count every relationship on every member of the queryset, even duplicates, and return that as just one value.