docs: def similar_objects(self, num=None, **filters):
          """
          Find similar objects using related tags.
          """
          tags = self.tags
          if not tags:
              return []
  
          content_type = ContentType.objects.get_for_model(self.__class__)
          filters['content_type'] = content_type
  
          # can't filter, see
          # - https://github.com/alex/django-taggit/issues/32
          # - https://django-taggit.readthedocs.io/en/latest/api.html#TaggableManager.similar_objects
          #
          # Otherwise this would be possible:
          # return tags.similar_objects(**filters)
  
          lookup_kwargs = tags._lookup_kwargs()
          lookup_keys = sorted(lookup_kwargs)
          subq = tags.all()
          qs = (tags.through.objects
                .values(*lookup_kwargs.keys())
                .annotate(n=models.Count('pk'))
                .exclude(**lookup_kwargs)
                .filter(tag__in=list(subq))
                .order_by('-n'))
  
          # from https://github.com/alex/django-taggit/issues/32#issuecomment-1002491
          if filters is not None:
              qs = qs.filter(**filters)
  
          if num is not None:
              qs = qs[:num]
  
          # Normal taggit code continues
  
          # TODO: This all feels like a bit of a hack.
          items = {}
          if len(lookup_keys) == 1:
              # Can we do this without a second query by using a select_related()
              # somehow?
              f = tags.through._meta.get_field_by_name(lookup_keys[0])[0]
              objs = f.rel.to._default_manager.filter(**{
                  "%s__in" % f.rel.field_name: [r["content_object"] for r in qs]
              })
              for obj in objs:
                  items[(getattr(obj, f.rel.field_name),)] = obj
          else:
              preload = {}
              for result in qs:
                  preload.setdefault(result['content_type'], set())
                  preload[result["content_type"]].add(result["object_id"])
  
              for ct, obj_ids in preload.items():
                  ct = ContentType.objects.get_for_id(ct)
                  for obj in ct.model_class()._default_manager.filter(pk__in=obj_ids):
                      items[(ct.pk, obj.pk)] = obj
  
          results = []
          for result in qs:
              obj = items[
                  tuple(result[k] for k in lookup_keys)
              ]
              obj.similar_tags = result["n"]
              results.append(obj)
          return results