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

Filter exact through tags #840

Open pancakeDevelopment opened 1 year ago

pancakeDevelopment commented 1 year ago

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 nameexact=_q, but it isn't working. Any ideas how to solve this issue?

rtpg commented 1 year ago

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:

developcreativo commented 1 year ago
  • 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...
developcreativo commented 1 year ago
 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

developcreativo commented 1 year ago

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

ethagnawl commented 1 year ago

@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')                                                                                                                                             
)    
rtpg commented 3 months ago

We might want to document how to do this kind of search, how to get objects that have exactly a certain set of tags. We could put this into the FAQs inside the documentation