def generic_annotate(qs_model, generic_qs_model, aggregator, gfk_field=None, alias='score'): """ Find blog entries with the most comments: qs = generic_annotate(Entry.objects.public(), Comment.objects.public(), Count('comments__id')) for entry in qs: print entry.title, entry.score Find the highest rated foods: generic_annotate(Food, Rating, Avg('ratings__rating'), alias='avg') for food in qs: print food.name, '- average rating:', food.avg .. note:: In both of the above examples it is assumed that a GenericRelation exists on Entry to Comment (named "comments") and also on Food to Rating (named "ratings"). If a GenericRelation does *not* exist, the query will still return correct results but the code path will be different as it will use the fallback method. .. warning:: If the underlying column type differs between the qs_model's primary key and the generic_qs_model's foreign key column, it will use the fallback method, which can correctly CASTself. :param qs_model: A model or a queryset of objects you want to perform annotation on, e.g. blog entries :param generic_qs_model: A model or queryset containing a GFK, e.g. comments :param aggregator: an aggregation, from django.db.models, e.g. Count('id') or Avg('rating') :param gfk_field: explicitly specify the field w/the gfk :param alias: attribute name to use for annotation """ prepared_query = prepare_query(qs_model, generic_qs_model, aggregator, gfk_field) if prepared_query is not False: return prepared_query.annotate(**{alias: aggregator}) else: # need to fall back since CAST will be missing return fallback_generic_annotate(qs_model, generic_qs_model, aggregator, gfk_field, alias)
def generic_annotate(qs_model, generic_qs_model, aggregator, gfk_field=None, alias="score"): """ Find blog entries with the most comments: qs = generic_annotate(Entry.objects.public(), Comment.objects.public(), Count('comments__id')) for entry in qs: print entry.title, entry.score Find the highest rated foods: generic_annotate(Food, Rating, Avg('ratings__rating'), alias='avg') for food in qs: print food.name, '- average rating:', food.avg .. note:: In both of the above examples it is assumed that a GenericRelation exists on Entry to Comment (named "comments") and also on Food to Rating (named "ratings"). If a GenericRelation does *not* exist, the query will still return correct results but the code path will be different as it will use the fallback method. .. warning:: If the underlying column type differs between the qs_model's primary key and the generic_qs_model's foreign key column, it will use the fallback method, which can correctly CASTself. :param qs_model: A model or a queryset of objects you want to perform annotation on, e.g. blog entries :param generic_qs_model: A model or queryset containing a GFK, e.g. comments :param aggregator: an aggregation, from django.db.models, e.g. Count('id') or Avg('rating') :param gfk_field: explicitly specify the field w/the gfk :param alias: attribute name to use for annotation """ prepared_query = prepare_query(qs_model, generic_qs_model, aggregator, gfk_field) if prepared_query is not False: return prepared_query.annotate(**{alias: aggregator}) else: # need to fall back since CAST will be missing return fallback_generic_annotate(qs_model, generic_qs_model, aggregator, gfk_field, alias)
def generic_aggregate(self, *args, **kwargs): return fallback_generic_annotate(*args, **kwargs)