简体   繁体   中英

get all unique prefetch_related objects in Django

in models.py:

from django.db import models
...
class Product(models.Model):
   ...
   recommended = models.ManyToManyField('self', blank=True)
   ...

if i have a queryset of Product how can i get all unique recommended objects?
example: product «A» has 3 recommended products: «B», «C» and «D», product «B» has 2 recommended products: «C» and «E», in queryset «products» we have «A» and «B» products, in this example:

# get_products() returns QuerySet of «A» and «B» products
products = get_products().prefetch_related('recommended')
recommended = [item for p in products for item in p.recommended.all()]

we will get list of [«B», «C», «D», «C», «E»], but how to get only [«B», «C», «D», «E»]?

PS of course we can filter objects in «for» cycle, but maybe there's more effective and fair way? ...

Update #1 (answer to Mark Galloway):

products = self.request.basket.get_products().prefetch_related(
        Prefetch('recommended', queryset=models.Product.objects.distinct()))
recommended_list = [item for p in products for item in p.recommended.all()]

returns:

[<Product: Vestibulum ante ipsum primis in>, <Product: Vivamus quis turpis>, <Product: Pellentesque habitant>, <Product: Vivamus quis turpis>]

where <Product: Vivamus quis turpis> repeated

PS does anybody knows?

You can define a more specific query for prefetch_releated by using a Prefetch object.

prefetch = Prefetch('recommended', queryset=Product.objects.distinct()))
products = get_products().prefetch_related(prefetch)
recommended_list = list(set([item for p in products for item in p.recommended.all()]))

Assuming your model is as follows (from your description and output, I am assuming you must have symmetrical=False ):

class Product(models.Model):
    recommended = models.ManyToManyField('self', blank=True, symmetrical=False, related_name='recommended_by')

Then I think the following does what you are after:

Product.objects.filter(recommended_by__in=get_products()).distinct()
>>> <QuerySet [<Product: B>, <Product: C>, <Product: D>, <Product: E>]>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM