jazzband/django-taggit

Filter exact through tags

pancakeDevelopment opened this issue · 6 comments

I'm trying to do this:

_q =  ["tag1","tag2]

Message.objects.filter(Q(tags__name__in=_q)).distinct().order_by('timestamp')

Now I want a result, where every message has exact those two tags - not just one of them. I've tried it with __name__exact=_q, but it isn't working. Any ideas how to solve this issue?

rtpg commented

I haven't tried this but I believe that doing Message.objects.filter(tags__name="tag1").filter(tags__name="tag2") should give you what you want.

That should return your messages that include tag1.... that are then filtered down by messages including tag2 (so the end result has those including both).

If you want to find those with exactly those two tags (i.e. no other tags), then you will want to filter those down, then there's a bit more work involved.

has_both_tags = Message.objects.filter(tags__name="tag1").filter(tags__name="tag2")

# get all the tag objects that you are not interested in (using the through model)
all_other_tags = Message.tags.through.objects.exclude(name__in=["tag1", "tag2")
# filter out messages that have any of those other tags
only_both_tags = has_both_tags.exclude(tags__in=all_other_tags)

I haven't tested this but the through model should be helpful for you. Core idea, mathematically is:

  • get the set of messages with both tags
  • get all the tags that you do not care about
  • get the set of messages with any tags you don't care about
  • exclude that latter set from this set
  • btenga el conjunto de mensajes con cual

feed = Feed.hashtags.through.objects.filter(tag__name__in=["demo"])
`

class TaggitManager:
    hashtags = TaggableManager(through=UUIDTaggedItem)

    class Meta:
        abstract = True

class UUIDTaggedItem(GenericUUIDTaggedItemBase, TaggedItemBase):
    pass


class Feed(UUIDModel, TimeStampedModel, mongo_models.Model, TaggitManager):
         #more field`
Internal Server Error: /api/v1/feed/feed-hashtag-list/
Traceback (most recent call last):
  File "/usr/local/lib/python3.10/dist-packages/django/db/backends/utils.py", line 89, in _execute
    return self.cursor.execute(sql, params)
psycopg2.errors.UndefinedTable: relation "feed_feed" does not exist
LINE 1: ...is_announcement", "feed_feed"."count_shared" FROM "feed_feed...
                                                             ^


The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/usr/local/lib/python3.10/dist-packages/asgiref/sync.py", line 486, in thread_handler
    raise exc_info[1]
  File "/usr/local/lib/python3.10/dist-packages/django/core/handlers/exception.py", line 42, in inner
    response = await get_response(request)
  File "/usr/local/lib/python3.10/dist-packages/django/core/handlers/base.py", line 253, in _get_response_async
    response = await wrapped_callback(
  File "/usr/local/lib/python3.10/dist-packages/asgiref/sync.py", line 448, in __call__
    ret = await asyncio.wait_for(future, timeout=None)
  File "/usr/lib/python3.10/asyncio/tasks.py", line 408, in wait_for
    return await fut
  File "/usr/local/lib/python3.10/dist-packages/asgiref/current_thread_executor.py", line 22, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/usr/local/lib/python3.10/dist-packages/asgiref/sync.py", line 490, in thread_handler
    return func(*args, **kwargs)
  File "/usr/lib/python3.10/contextlib.py", line 79, in inner
    return func(*args, **kwds)
  File "/usr/lib/python3.10/contextlib.py", line 79, in inner
    return func(*args, **kwds)
  File "/usr/local/lib/python3.10/dist-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
    return view_func(*args, **kwargs)
  File "/usr/local/lib/python3.10/dist-packages/rest_framework/viewsets.py", line 125, in view
    return self.dispatch(request, *args, **kwargs)
  File "/usr/local/lib/python3.10/dist-packages/rest_framework/views.py", line 509, in dispatch
    response = self.handle_exception(exc)
  File "/usr/local/lib/python3.10/dist-packages/rest_framework/views.py", line 469, in handle_exception
    self.raise_uncaught_exception(exc)
  File "/usr/local/lib/python3.10/dist-packages/rest_framework/views.py", line 480, in raise_uncaught_exception
    raise exc
  File "/usr/local/lib/python3.10/dist-packages/rest_framework/views.py", line 506, in dispatch
    response = handler(request, *args, **kwargs)
  File "/var/www/sportyeah/apps/feed/api/v1/views/feed.py", line 351, in feed_hashtag_list
    return super().list(request, *args, **kwargs)
  File "/usr/local/lib/python3.10/dist-packages/rest_framework/mixins.py", line 38, in list
    queryset = self.filter_queryset(self.get_queryset())
  File "/var/www/sportyeah/apps/feed/api/v1/views/feed.py", line 198, in get_queryset
    print(feed)
  File "/usr/local/lib/python3.10/dist-packages/django/db/models/query.py", line 373, in __repr__
    return "<%s %r>" % (self.__class__.__name__, data)
  File "/usr/local/lib/python3.10/dist-packages/django/db/models/base.py", line 606, in __repr__
    return "<%s: %s>" % (self.__class__.__name__, self)
  File "/usr/local/lib/python3.10/dist-packages/taggit/models.py", line 97, in __str__
    "object": self.content_object,
  File "/usr/local/lib/python3.10/dist-packages/django/contrib/contenttypes/fields.py", line 250, in __get__
    rel_obj = ct.get_object_for_this_type(pk=pk_val)
  File "/usr/local/lib/python3.10/dist-packages/django/contrib/contenttypes/models.py", line 179, in get_object_for_this_type
    return self.model_class()._base_manager.using(self._state.db).get(**kwargs)
  File "/usr/local/lib/python3.10/dist-packages/django/db/models/query.py", line 646, in get
    num = len(clone)
  File "/usr/local/lib/python3.10/dist-packages/django/db/models/query.py", line 376, in __len__
    self._fetch_all()
  File "/usr/local/lib/python3.10/dist-packages/django/db/models/query.py", line 1866, in _fetch_all
    self._result_cache = list(self._iterable_class(self))
  File "/usr/local/lib/python3.10/dist-packages/django/db/models/query.py", line 87, in __iter__
    results = compiler.execute_sql(
  File "/usr/local/lib/python3.10/dist-packages/django/db/models/sql/compiler.py", line 1395, in execute_sql
    cursor.execute(sql, params)
  File "/usr/local/lib/python3.10/dist-packages/django/db/backends/utils.py", line 103, in execute
    return super().execute(sql, params)
  File "/usr/local/lib/python3.10/dist-packages/django/db/backends/utils.py", line 67, in execute
    return self._execute_with_wrappers(
  File "/usr/local/lib/python3.10/dist-packages/django/db/backends/utils.py", line 80, in _execute_with_wrappers
    return executor(sql, params, many, context)
  File "/usr/local/lib/python3.10/dist-packages/django/db/backends/utils.py", line 84, in _execute
    with self.db.wrap_database_errors:
  File "/usr/local/lib/python3.10/dist-packages/django/db/utils.py", line 91, in __exit__
    raise dj_exc_value.with_traceback(traceback) from exc_value
  File "/usr/local/lib/python3.10/dist-packages/django/db/backends/utils.py", line 89, in _execute
    return self.cursor.execute(sql, params)
django.db.utils.ProgrammingError: relation "feed_feed" does not exist
LINE 1: ...is_announcement", "feed_feed"."count_shared" FROM "feed_feed...
 feed = Feed.objects.filter(tags__name="demo")

django.core.exceptions.FieldError: Cannot resolve keyword 'tags' into field

or

feed = Feed.objects.filter(hashtags__name="demo")

django.core.exceptions.FieldError: Cannot resolve keyword 'hashtags' into field

@rtpg Any way to tell my model to filter me by hashtags since none of the ways I have tried has been satisfactory.

@rtpg I can confirm that your chained filter example works as expected. Thank you for that!

I'm curious to know if you have a suggested way of building up a dynamic filter chain, though. I'm trying to compose a list of Q filters combined with the & operator and it's not working. What's really interesting is that using & to compose filter chains does work.

# works
xs = Band.objects.filter(                                                                                                                                                   
    custom_tags__name='punk'                                                                                                                                                 
) & Band.objects.filter(                                                                                                                                             
    custom_tags__name='indie'                                                                                                                                                
)                                                                                                                                                                            

# does not work                                                                                                                                                                             
xxs = Band.objects.filter(                                                                                                                                                  
    Q(custom_tags__name='punk') &                                                                                                                                            
    Q(custom_tags__name='indie')                                                                                                                                             
)