from django.db import models # Some convenience functions. def _get_table(model): return model._meta.db_table def _get_column(model, attr): return "%s.%s" % (_get_table(model), model._meta.get_field(attr).column) def _get_related_column(model, attr): related = model._meta.get_field(attr).rel return "%s.%s" % (_get_table(related.to), related.field_name) def _related_count_sql(related, attr): return """SELECT COUNT(*) FROM %s WHERE %s = %s """ % (_get_table(related), _get_column(related, attr), _get_related_column(related, attr)) # This is what it's all about. def _count_related(self, query, count_attr=None, related_attr=None): """ Count the rows matching `query` related to this model by their foreign key attribute `related_attr`, and store the result in `count_attr`. If `count_attr` is None, use the name of the module given in `query` suffixed with '__count'. If `related_attr` is None, find the first foreign key field in the model queried by `query` relating to this model. If `query` is a model class, use the all() method on its default manager as the query. """ if isinstance(query, models.base.ModelBase): query = query._default_manager.all() if count_attr is None: count_attr = query.model._meta.module_name + '__count' if related_attr is None: for field in query.model._meta.fields: if isinstance(field, models.related.RelatedField): if field.rel.to is self.model: related_attr = field.name select_count = _related_count_sql(query.model, related_attr) joins, wheres, params = query._filters.get_sql(query.model._meta) if wheres: select_count += ' AND %s' % wheres[0] return self.extra(select={count_attr: select_count}, params=params) # Here's where your code comes in. class YourManager(models.Manager): count_related = _count_related # Add this to your managers.