【问题标题】:tastypie: filter many to many tables with multiple, ANDed values美味派:过滤具有多个 ANDed 值的多对多表
【发布时间】:2013-02-28 15:41:23
【问题描述】:

我有两个表(电影和流派),它们使用交叉表(电影流派)以多对多关系连接。

我的 models.py 文件如下所示:

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 )

我想使用tastepie 过滤某些类型的所有电影。例如。显示所有类型为动作、惊悚和科幻的电影。

我的 api.py 看起来像这样:

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,
        }

我的测试数据: 两部电影(带有流派 ID) 矩阵 (1 & 3 ) 银翼杀手 (1 & 2 )

首先我对标题进行查询,如下查询返回1个结果(即矩阵):

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

但是,我得到了三个结果,其 URL 应该使用此查询查询相关类型表(两次 Matrix 和一次 Blade Runner):

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

我希望只取回 Matrix

我也尝试像这样覆盖 apply_filters:

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

任何想法使这项工作?

感谢您的任何想法...

【问题讨论】:

  • 我不确定您为什么在 apply_filters 方法中如此复杂的查询。例如,您可以使用 oList = oList.filter(sTitle__icontains='a', sTitle__icontains='x').distinct() 来代替 loQ = [Q(**{'sTitle__icontains': 'a'}), Q(**{'sTitle__icontains': 'x'})] 之类的东西

标签: django filter tastypie relation m2m


【解决方案1】:

你试过http://localhost:8000/api/v1/movie/?format=json&genre__id=3&genre__id=1

如果我理解正确,那么使用__in 就像说genre__id__in=[1, 3]

【讨论】:

  • 我必须同意。当使用__in 时,它将返回包含该列表中的 id 的任何结果,如给出的第三个apply_filters 示例所示。 @msc 解决方案的替代方案也可以是使用 genre__id__exactgenre__pk
  • genre__id=1 与genre__id__exact=1 相同。
  • 是的,只是提供了替代语法。从技术上讲,我也应该说genre__pk__exact ;)
  • 感谢您的提示,使用genre__id,genre__id__exact 为URL 解决了问题。伟大的!然而,一个问题仍然存在,如果我想用 q 个对象创建过滤器,当与上面示例中的两个“genre__id”对象进行 AND 运算时仍然没有结果......知道为什么吗?
  • 一个可行的方法是将过滤器链接起来:oList = oList.filter( oFilter_1 ).filter( oFilter_2 )... 但这有点臭
猜你喜欢
  • 2012-07-11
  • 2012-10-30
  • 1970-01-01
  • 1970-01-01
  • 2022-06-22
  • 2012-09-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多