Mikey Lockwood
Mikey Lockwood

Reputation: 1261

Getting a django queryset from a backward foreign key relationship with one distinct field

Using Django 1.8

I'm trying to get a queryset through the backward foreign key relationship where there is only one distinct value of one the fields in the source models.

class Franchise(models.Model):
    ...

class Title(models.Model):
    franchise = models.ForeignKey(Franchise, related_name='titles')
    genre = models.CharField(max_length=20)
    ...

So in this example I would like to get a queryset of Franchise objects of which all Titles have the same genre. I can add methods to the Franchise model and generate a list of franchise id's obtain a queryset, but this is very slow.

class Franchise(models.Model):
    ...

    def get_title_genres(self):
        self.titles.values_list('genre', flat=True).distinct()

    def is_single_genre(self):
        return len(self.get_title_genres()) == 1


franchise_ids = [
   franchise.id
   for franchise in Franchise.objects.all()
   if franchise.is_single_genre()
]

queryset = Franchise.objects.filter(id__in=franchise_ids)

Is there a more efficient way I can do this?

Upvotes: 1

Views: 148

Answers (1)

Alasdair
Alasdair

Reputation: 308899

Unless you need a queryset, you don't need to the second queryset with id__in=franchise_ids.

franchises = [
    franchise for franchise in Franchise.objects.all()
    if franchise.is_single_genre()
]

You could use prefetch_related to fetch all of the related titles with the queryset, however you won't be able to reuse the get_title_genres method, because the values_list(...).distinct() would trigger a new SQL query.

franchises = [
    franchise for franchise in Franchise.objects.prefetch_related('titles')
    if len(set(t.genre for t in franchise.titles)) == 1
]

Upvotes: 1

Related Questions