common_slug=book.common_slug).exclude(pk=book.pk)[:limit])
limit -= len(related)
if limit:
- tagged = Book.tagged.with_any(book.tags).exclude(pk=book.pk)
- book_tag = book.book_tag()
- for rel_book in tagged:
- if book_tag in rel_book.tags.all():
- continue
- related += [rel_book]
- limit -= 1
- if not limit:
- break
-
+ related += Book.tagged.related_to(book,
+ Book.objects.exclude(common_slug=book.common_slug),
+ ignore_by_tag=book.book_tag())[:limit]
return {
'books': related,
}
super(ModelTaggedItemManager, self).__init__()
self.intermediary_table_model = tag_model.objects.intermediary_table_model
- def related_to(self, obj, queryset=None, num=None):
+ def related_to(self, obj, queryset=None, num=None, ignore_by_tag=None):
if queryset is None:
- return self.intermediary_table_model.objects.get_related(obj, self.model, num=num)
+ return self.intermediary_table_model.objects.get_related(
+ obj, self.model, num=num, ignore_by_tag=ignore_by_tag)
else:
- return self.intermediary_table_model.objects.get_related(obj, queryset, num=num)
+ return self.intermediary_table_model.objects.get_related(
+ obj, queryset, num=num, ignore_by_tag=ignore_by_tag)
def with_all(self, tags, queryset=None):
if queryset is None:
else:
return model._default_manager.none()
- def get_related(self, obj, queryset_or_model, num=None):
+ def get_related(self, obj, queryset_or_model, num=None, ignore_by_tag=None):
"""
Retrieve a list of instances of the specified model which share
tags with the model instance ``obj``, ordered by the number of
If ``num`` is given, a maximum of ``num`` instances will be
returned.
+
+ If ``ignore_by_tag`` is given, object tagged with it will be ignored.
"""
queryset, model = get_queryset_and_model(queryset_or_model)
model_table = qn(model._meta.db_table)
# instances for the same model.
query += """
AND related_tagged_item.object_id != %(tagged_item)s.object_id"""
+ if ignore_by_tag is not None:
+ query += """
+ AND NOT EXISTS (
+ SELECT * FROM %(tagged_item)s
+ WHERE %(tagged_item)s.object_id = %(model_pk)s
+ AND %(tagged_item)s.content_type_id = %(content_type_id)s
+ AND %(ignore_id)s = %(tagged_item)s.tag_id
+ )
+ """
query += """
GROUP BY %(model_pk)s
ORDER BY %(count)s DESC
'content_type_id': content_type.pk,
'related_content_type_id': related_content_type.pk,
'limit_offset': num is not None and connection.ops.limit_offset_sql(num) or '',
+ 'ignore_id': ignore_by_tag.id if ignore_by_tag else None,
}
cursor = connection.cursor()