Jason
Jason

Reputation: 11363

Django - get results of query based on many to many relationship

Given the following models and an array of strings via a URI GET, how can I efficiently execute a filter operation and return all Trail matches?

class Trail(models.Model):
    '''
    Main model for this application.  Contains all information for a particular trail
    '''
    trail_name = models.CharField(max_length=150)
    active = models.BooleanField(default=True)
    date_uploaded = models.DateTimeField(default=now())
    owner = models.ForeignKey(Account, default=1)

class Surface(models.Model):
    '''
    A many to many join table to map a surface type to many trails.  A trail can have many
    surface types.
    '''
    type = models.CharField(max_length=50, db_column='surface_type', unique=True)
    trails = models.ManyToManyField(Trail)

    class Meta:
        ordering = ('type', )

Naively, I can just get all Trail models and iterate through them to get the matches, but would like a more efficient way.

I've attempted to do this:

from django.models.db import Q

#List of strings as a result of a URL querystring like
#?keys=Dirt&keys=Gravel&keys=Paved
keys = request.GET.getlist('keys')

queries = [Q(type = surface) for surface in keys]
query = queries.pop()

for item in queries:
     query |= item

results = Trail.objects.filter(surface=type)

but this returns an ValueError: invalid literal for int() with base 10: exception.

Upvotes: 0

Views: 884

Answers (1)

Daniel Roseman
Daniel Roseman

Reputation: 600041

There's no need to use Q here at all. What you presumably have is a list of strings corresponding to the type field of Surface objects, and you want to get the Trails that are related to those Surfaces. You can use __in to query for multiple surface types, and you can also use the double-underscore relationship to cross the relationship between Surface and Trail. So:

Trail.objects.filter(surface__type__in=request.GET.getlist('keys'))

Upvotes: 2

Related Questions