Search code examples
pythondjangodjango-taggitdjango-tagging

Getting all the tags associated with the parent object using django-taggit


I have models Restaurant & Review. Review has TaggableManager() I have no problem in making tags work for Reviews. But I also want to know all the tags that are associated with the Restaurant object.

I can write my own function that iterates through all reviews of the restaurant to get all the tags associated with the Restaurant. But I am looking for cleaner and easy way to get the tags that accomplishes it in a single DB query.


Solution

  • I don't think its possible in a single query but this solution will take five database queries:

    # 1 query: Get restaurant
    restaurant = Restaurant.objects.get(pk=pk)
    
    # 2 query: Get content type of restaurant model
    restaurant_ct = ContentType.objects.get_for_model(restaurant)
    
    # 3 query: Get all reviews ids for a restaurant
    reviews_ids = Review.objects.filter(content_type__id=restaurant_ct.id, object_id=restaurant.id).values_list('id', flat=True)
    
    # 4 query: Get content type of review model
    review_ct = ContentType.objects.get(app_label='review', model='review')
    
    # 5 query: Get all tags
    tags = TaggedItem.objects.filter(object_id__in=reviews_ids, content_type__id=review_ct.id)
    

    But do note that the __in lookup on review ids might become costly on TaggedItem. But you wanted minimum database queries.

    You can reduce one more query by fetching both content types of restaurant and review model in a single query but its not an elegant way:

    ctypes = ContentType.objects.filter(
        app_label__in=['review', 'restaurant'],
        model__in=['review', 'restaurant']
    )
    assert len(ctypes) is 2
    if ctypes[0].model == 'restaurant':
        restaurant_ct = ctypes[0]
        review_ct = ctypes[1]
    else:
        review_ct = ctypes[0]
        restaurant_ct = ctypes[1]