Hello there! I have the following data structure:
class ProductType(Model):
name = ...
class Feature(Model):
product_type = ManyToManyField(ProductType, related_name="features")
class Tag(Model):
feature = ForeignKey(Feature, related_name="tags")
class Product(Model):
tags = ManyToManyField(Tag, related_name="products")
product_type = ForeignKey(ProductType, related_name="products")
So a product has a product type and some tags. A tag belongs to a feature, and a feature can be on many product types. It’s not ideal but that’s what I must work with.
>>> simple_tags_qs = Tag.objects.all()
>>> simple_tags_qs.count()
254
>>> simple_product_types_qs = ProductType.objects.all()
>>> simple_product_types_qs.first().features.first().tags.count()
11
If I want a queryset of Tags with distinct ProductType, filtered by if there are products for that Tag / ProductType, I can do the following:
>>> has_products = (
Product.objects.filter(
tags=OuterRef("pk"),
product_type=OuterRef("feature__product_type"),
)
)
>>> distinct_product_tags_qs = (
Tag.objects
.order_by()
.distinct("pk", "feature__product_type")
.filter(Exists(has_products))
)
>>> distinct_product_tags_qs.count()
1005
But now I want a queryset of ProductTypes with prefetched distinct Tags keeping the above filter.
>>> product_types_with_disctinct_tags_qs = (
ProductType.objects
.prefetch_related(
Prefetch(
"features__tags",
queryset=distinct_product_tags_qs,
)
)
)
However, doing this, I get duplicates of each Tag for each Feature for each ProductType.
>>> product_types_with_disctinct_tags_qs.first().features.first().tags.count()
24 // should be at most initial tag count, 11, or less if there are no products
So I guess my question is: Using Prefetch, how can I join the filtered Tag queryset with the ProductType queryset so that each distinct Tag lands in the correct ProductType tags?