2013-02-28 1 views
1

J'ai deux tables (Movie et Genre) qui sont connectées avec une relation many to many en utilisant un crosstable (MovieGenre).tastypie: filtre beaucoup à plusieurs tables avec plusieurs, valeurs ANDed

Mon fichier models.py ressemble à ceci:

class Genre(models.Model): 

    sName = models.CharField(max_length=176) 
    [ .. ] 

class Movie(models.Model): 

    sTitle = models.CharField(max_length=176) 
    genre = models.ManyToManyField(Genre) 
    [ .. ] 

class MovieGenre(models.Model): 

    idMovie = models.ForeignKey(Movie) 
    idGenre = models.ForeignKey(Genre) 

Je veux utiliser tastypie pour filtrer tous les films de certains genres. Par exemple. montre moi tous les films de genre Action, Thriller et SciFi.

Mon api.py ressemble à ceci:

class GenreResource(ModelResource): 
    class Meta: 
     queryset = Genre.objects.all() 
     resource_name = 'genre' 
     always_return_data = True 
     include_resource_uri = False 
     excludes = ['dtCreated', 'dtModified' ] 
     authorization= Authorization() 
     authentication = SessionAuthentication() 
     filtering = { 
      "id" : ALL, 
     } 


class MovieResource(ModelResource): 
    genre = fields.ManyToManyField('app.api.GenreResource', 'genre', full=True) 
    class Meta: 
     queryset = Movie.objects.all() 
     resource_name = 'movie' 
     authorization= Authorization() 
     authentication = SessionAuthentication() 
     always_return_data = True 
     include_resource_uri = False 
     excludes = ['dtCreated', 'dtModified' ] 
     filtering = { 
      "sTitle" : ALL, 
      "genre" : ALL_WITH_RELATIONS, 
     } 

Mes données de test: Deux films (avec ids genre) Matrix (1 & 3) Blade Runner (1 & 2)

D'abord je fais une requête sur le titre, comme attendu ci-dessous la requête renvoie 1 résultat (à savoir Matrix):

http://localhost:8000/api/v1/movie/?format=json&sTitle__icontains=a&sTitle__icontains=x 

Cependant, je reçois trois résultats avec l'URL qui devrait interroger la table de genre liées (deux fois la matrice et une fois Blade Runner) avec cette requête:

http://localhost:8000/api/v1/movie/?format=json&genre__id__in=3&genre__id__in=1 

j'attendre de revenir que la matrice

J'ai également essayé de substituer apply_filters comme ceci:

def apply_filters(self, request, applicable_filters): 
    oList = super(ModelResource, self).apply_filters(request, applicable_filters) 
    loQ = [Q(**{'sTitle__icontains': 'a'}), Q(**{'sTitle__icontains': 'x'})] 
    # works as intended: one result 
    loQ = [Q(**{'genre__id__in': '3'}) ] 
    # results in one result (Matrix) 

    loQ = [Q(**{'genre__id__in': '1'}), Q(**{'genre__id__in': '3'}) ] 
    # results in no results! 

    loQ = [Q(**{'genre__id__in': [ 1, 3]}) ] 
    # results in two results Matrix and Blade Runner which is OK since obviously ORed 
    oFilter = reduce(operator.and_, loQ) 
    oList = oList.filter(oFilter).distinct() 
    return oList 

Une idée pour que cela fonctionne?

Merci pour toute idée ...

+0

Je ne sais pas pourquoi vous avez tellement compliqué les requêtes dans votre méthode 'apply_filters'. Par exemple, au lieu de quelque chose comme: 'loQ = [Q (** {'Title__icontains ':' a '}), Q (** {'Title__icontains': 'x'})]' vous pouvez faire la même chose avec this 'oList = oList.filter (sTitle__icontains = 'a', sTitle__icontains = 'x'). distinct()' – Ngenator

Répondre

3

Avez-vous essayé http://localhost:8000/api/v1/movie/?format=json&genre__id=3&genre__id=1

Si je comprends bien, en utilisant __in cette façon serait comme dire genre__id__in=[1, 3].

+0

Je suis d'accord. En utilisant '__in', il retournera tout résultat qui contient un identifiant dans cette liste, comme démontré dans le troisième exemple' apply_filters' donné. Alternatives à la solution de @ msc pourrait également être d'utiliser 'genre__id__exact' ou' genre__pk'. – Ngenator

+0

genre__id = 1 est la même chose avec genre__id__exact = 1. – UnLiMiTeD

+0

Oui, c'était juste une syntaxe alternative. Techniquement j'aurais dû dire 'genre__pk__exact' aussi;) – Ngenator

Questions connexes