def top_items(self, item_type, num=5):
"""
Returns a list of the top ``num`` objects of a particular
type, based on the number of Snippets associated with them;
for example, with ``item_type=tag``, returns a list of Tags
based on how many Snippets they've been used for.
Acceptable values for ``item_type`` are:
* 'author' -- will return the users who have submitted the
most Snippets.
* 'language' -- will return the most-used languages.
* 'tag' -- will return the most-used tags.
"""
# Need all of these up-front so the mapping dictionary can be built
# correctly.
from django.contrib.auth.models import User
from models import Language, Tag, Snippet
# ``_meta`` strikes again.
object_mapping = {
'author': {'model': User,
'primary_table': User._meta.db_table,
'secondary_table': Snippet._meta.db_table },
'tag': { 'model': Tag,
'primary_table': Tag._meta.db_table,
'secondary_table': Snippet._meta.get_field('tags').m2m_db_table() },
'language': {'model': Language,
'primary_table': Language._meta.db_table,
'secondary_table': Snippet._meta.db_table },
}
params = object_mapping[item_type]
query = """SELECT p.id AS object_id, COUNT(*) AS score
FROM %s p INNER JOIN %s s
WHERE p.id = s.%s
GROUP BY object_id
ORDER BY score DESC""" % (params['primary_table'], params['secondary_table'], item_type + '_id')
from django.db import connection
cursor = connection.cursor()
cursor.execute(query, [])
object_ids = [row[0] for row in cursor.fetchall()[:num]]
# Use ``in_bulk`` here instead of an ``id__in`` lookup, because ``id__in``
# would clobber the ordering.
object_dict = params['model']._default_manager.in_bulk(object_ids)
return [object_dict[object_id] for object_id in object_ids]
Comments
See also: http://www.djangosnippets.org/snippets/236/
#