from classytags.arguments import Argument from classytags.core import Options from classytags.helpers import AsTag from django import template from django.contrib.contenttypes.models import ContentType from django.core.exceptions import FieldError from django.db.models import Count from taggit_templatetags2 import settings from taggit_templatetags2.compat import get_model T_MAX = getattr(settings, 'TAGCLOUD_MAX', 6.0) T_MIN = getattr(settings, 'TAGCLOUD_MIN', 1.0) register = template.Library() def get_queryset(forvar, taggeditem_model, tag_model): through_opts = taggeditem_model._meta count_field = ( "%s_%s_items" % ( through_opts.app_label, through_opts.object_name)).lower() if forvar is None: # get all tags queryset = tag_model.objects.all() else: # extract app label and model name beginning, applabel, model = None, None, None try: beginning, applabel, model = forvar.rsplit('.', 2) except ValueError: try: applabel, model = forvar.rsplit('.', 1) except ValueError: applabel = forvar applabel = applabel.lower() # filter tagged items if model is None: # Get tags for a whole app queryset = taggeditem_model.objects.filter( content_type__app_label=applabel) tag_ids = queryset.values_list('tag_id', flat=True) queryset = tag_model.objects.filter(id__in=tag_ids) else: # Get tags for a model model = model.lower() if ":" in model: model, manager_attr = model.split(":", 1) else: manager_attr = "tags" model_class = get_model(applabel, model) if not model_class: raise Exception( 'Not found such a model "%s" in the application "%s"' % (model, applabel)) manager = getattr(model_class, manager_attr) queryset = manager.all() through_opts = manager.through._meta count_field = ("%s_%s_items" % (through_opts.app_label, through_opts.object_name)).lower() if count_field is None: # Retain compatibility with older versions of Django taggit # a version check (for example taggit.VERSION <= (0,8,0)) does NOT # work because of the version (0,8,0) of the current dev version of # django-taggit try: return queryset.annotate( num_times=Count(settings.TAG_FIELD_RELATED_NAME)) except FieldError: return queryset.annotate( num_times=Count('taggit_taggeditem_items')) else: return queryset.annotate(num_times=Count(count_field)) def get_weight_fun(t_min, t_max, f_min, f_max): def weight_fun(f_i, t_min=t_min, t_max=t_max, f_min=f_min, f_max=f_max): # Prevent a division by zero here, found to occur under some # pathological but nevertheless actually occurring circumstances. if f_max == f_min: mult_fac = 1.0 else: mult_fac = float(t_max - t_min) / float(f_max - f_min) return t_max - (f_max - f_i) * mult_fac return weight_fun @register.tag class GetTagForObject(AsTag): name = 'get_tags_for_object' options = Options( Argument('source_object', resolve=True, required=True), 'as', Argument('varname', resolve=False, required=False), ) def get_value(self, context, source_object, varname=''): """ Args: source_object - Return: queryset tags """ tag_model = settings.TAG_MODEL app_label = source_object._meta.app_label try: model = source_object._meta.model_name except AttributeError: model = source_object._meta.module_name.lower() content_type = ContentType.objects.get(app_label=app_label, model=model) try: tags = tag_model.objects.filter( taggit_taggeditem_items__object_id=source_object, taggit_taggeditem_items__content_type=content_type) except: tags = tag_model.objects.filter( taggit_taggeditem_items__object_id=source_object.pk, taggit_taggeditem_items__content_type=content_type) if varname: context[varname] return '' else: return tags class TaggitBaseTag(AsTag): options = Options( 'as', Argument('varname', resolve=False, required=False), 'for', Argument('forvar', required=False), 'limit', Argument('limit', required=False, default=5, resolve=True), ) @register.tag class GetTagList(TaggitBaseTag): name = 'get_taglist' def get_value(self, context, varname, forvar, limit=settings.LIMIT, order_by=settings.TAG_LIST_ORDER_BY): # TODO: remove default value for limit, report a bug in the application # django-classy-tags, the default value does not work queryset = get_queryset( forvar, settings.TAGGED_ITEM_MODEL, settings.TAG_MODEL) queryset = queryset.order_by(order_by) context[varname] = queryset if limit: queryset = queryset[:limit] return '' @register.tag class GetTagCloud(TaggitBaseTag): name = 'get_tagcloud' def get_value(self, context, varname, forvar, limit=settings.LIMIT, order_by=settings.TAG_CLOUD_ORDER_BY): queryset = get_queryset( forvar, settings.TAGGED_ITEM_MODEL, settings.TAG_MODEL) num_times = queryset.values_list('num_times', flat=True) if(len(num_times) == 0): context[varname] = queryset return '' weight_fun = get_weight_fun( T_MIN, T_MAX, min(num_times), max(num_times)) queryset = queryset.order_by(order_by) if limit: queryset = queryset[:limit] for tag in queryset: tag.weight = weight_fun(tag.num_times) context[varname] = queryset return '' @register.inclusion_tag('taggit_templatetags2/tagcloud_include.html') def include_tagcloud(forvar=None): return {'forvar': forvar} @register.inclusion_tag('taggit_templatetags2/taglist_include.html') def include_taglist(forvar=None): return {'forvar': forvar} @register.inclusion_tag('taggit_templatetags2/tagcanvas_include.html') def include_tagcanvas(element_id, width, height, url_name='tagcanvas-list', forvar=None, limit=3): """ Args: element_id - str - html id width - int - pixels width height - int - pixels height url_name - if url_name=='' then no links. Default: tagcanvas-list """ if url_name == 'default': url_name = 'tagcanvas-list' return { 'forvar': forvar, 'element_id': element_id, 'width': width, 'height': height, 'url_name': url_name, 'limit': limit}