New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
KeyError on similar_objects #80
Comments
any thoughts on this issue? |
I've hit the same issue. |
I believe that this is a Django bug. Look at ticket #19149. The quickest way to fix this is to move the TaggableManager on to the subclass. |
I also have hit the same issue. I found a dirty workaround by limiting the number of objects returned by similar_objects(). In taggit/managers.py, in similar_objects(), slicing the queryset after qs.order_by('-n) seems to solve the issue. |
I am experiencing the same error with |
@The-Fonz Are you using SQLite? I'm having the same issue using sqlite (even with the workaround) but there is no issue with postgres. |
@gelbander Yes I am, thanks for the tip, will try postgres! |
I switched to postgres but still had the KeyError, fixed it by changing line 260 in |
i am having the same issue with @django-taggit 0.22.1@ using Wagtail CMS |
Still having the same issue with django-taggit 0.24.0 and wagtail 2.5.1 almost 8 years later... The workaround that The-Fonz suggested still works, but it's pretty annoying to implement as I have to copy/paste a rather large method just to change one line of it and every time there is a change to the related files I have to diff the original code to update it. If anyone's interested, here's my current working drop in replacement for ClusterTaggableManager implementing The-Fonz's workaround: # taggablemanager.py
from __future__ import unicode_literals
from modelcluster.contrib.taggit import _ClusterTaggableManager, ClusterTaggableManager
from django.contrib.contenttypes.models import ContentType
from django.db import models
from django.utils import six
from taggit.utils import require_instance_manager
# All this crap is mostly boilerplate and copy and pasted code just to fix one line from taggit/managers.py
class _FixedClusterTaggableManager(_ClusterTaggableManager):
@require_instance_manager
def similar_objects(self):
lookup_kwargs = self._lookup_kwargs()
lookup_keys = sorted(lookup_kwargs)
qs = self.through.objects.values(*six.iterkeys(lookup_kwargs))
qs = qs.annotate(n=models.Count("pk"))
qs = qs.exclude(**lookup_kwargs)
qs = qs.filter(tag__in=self.all())
qs = qs.order_by("-n")
# 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 = self.through._meta.get_field(lookup_keys[0])
remote_field = f.remote_field
rel_model = remote_field.model
objs = rel_model._default_manager.filter(
**{
"%s__in"
% remote_field.field_name: [r["content_object"] for r in qs]
}
)
for obj in objs:
# THE FOLLOWING 2 LINES IS THE ACTUAL FIX:
# items[(getattr(obj, remote_field.field_name),)] = obj
items[(obj.id,)] = 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
class FixedClusterTaggableManager(ClusterTaggableManager):
def __get__(self, instance, model):
# override TaggableManager's requirement for instance to have a primary key
# before we can access its tags
manager = _FixedClusterTaggableManager(
through=self.through, model=model, instance=instance, prefetch_cache_name=self.name
)
return manager Assuming this file is in the same directory as the models.py where you want to use a ClusterTaggableManager you can import it like so without changing anything else: # from modelcluster.contrib.taggit import ClusterTaggableManager
from .taggablemanager import FixedClusterTaggableManager as ClusterTaggableManager |
It seems that this bug isn't fixed in version 1.2.0. |
Here is a workaround for those not wanting to eject and override the package: In this scenario we use taggit to tag multiple objects (tools and toolboxes) so the "tt.object_id = ct.id and tt.content_type_id in (select dct.id from django_content_type dct where dct.app_label = 'core' and dct.model = 'tool')" line is to ensure we find the correct object id, in this case it is just for tools. This admittedly is not the best solution but better than nothing. The function only needs the instance of the object you want to find similar items for, in our case a tool queried from Tool.objects.get(pk=id). It returns a list of similar tools ordered by the most matches then by most recently added.
|
Many wagtail users have reported this issue over the years. @jdufresne, as you seem to be the last active maintainer of this project, what needs to happen to put this and #508 and #424 to rest, and how can I help to make that happen? |
thanks @czr137 |
The steps to the trace above are as follows:
The text was updated successfully, but these errors were encountered: