jazzband / django-taggit

Simple tagging for django
https://django-taggit.readthedocs.io
BSD 3-Clause "New" or "Revised" License
3.33k stars 622 forks source link

Tags on objects with hashids #631

Open ephes opened 5 years ago

ephes commented 5 years ago

Hi *,

first of all: thanks for this awesome package :).

I use django-taggit on models which have a hash_id primary key. At first I thought that this would be enough:

class GenericHashidTaggedItemBase(CommonGenericTaggedItemBase):
    object_id = HashidField(verbose_name=_("Object id"), db_index=True)

    class Meta:
        abstract = True

class ItemTagLink(GenericHashidTaggedItemBase, TaggedItemBase):
    class Meta:
        verbose_name = _("Tag")
        verbose_name_plural = _("Tags")

But it turned out that now item.tags.all() was empty on models which were retrieved through querysets with .prefetch_related("tags"). This seemed very odd to me. After some digging in djangos prefetch_related functions, I found out that this line caused the problem. Since obj._get_pk_val() returns an Hashid-object and attrgetter("_prefetch_related_val") returns the integer key the cache keys do not match anymore and an empty queryset gets stored. My current workaround is to use my own _TaggableManager which overwrites get_prefetch_queryset, but this doesn't seem to be very elegant. Maybe there's another way to do it?

Thanks and have a nice day, jochen

oryon-dominik commented 5 years ago
class _HashidTaggableManager(_TaggableManager):
    def get_prefetch_queryset(self, instances, queryset=None):
        result = list(super().get_prefetch_queryset(instances, queryset=queryset))
        result[2] = lambda obj: obj._get_pk_val().id
        return tuple(result)
rtpg commented 3 years ago

Thanks for the report, this is clearly a nasty little bug