绕过Tastypie忽略ManyToMany查询的查询集

时间:2013-04-05 15:26:02

标签: django-queryset django-orm tastypie

我无法让Tastypie在ManyToMany查询中正常运行。

以下是我的模型的简化版本。

class Buttons(models.Model):
    name = models.CharField(max_length=255)
    deleted = models.IntegerField()
    date_entered = models.DateTimeField(auto_now_add=True)
    date_modified = models.DateTimeField(auto_now=True)
    jacket = models.ManyToManyField('Jackets', through='JacketsButtons', related_name='buttons_jackets', blank=True)

    class Meta:
        app_label = 'habby'
        db_table = u'buttons'

#joining table
class JacketsButtons(models.Model):
    date_modified = models.DateTimeField(auto_now=True)
    deleted = models.IntegerField()
    jacket_id = models.ForeignKey('Jackets')
    button_id = models.ForeignKey('Buttons')
    class Meta:
        app_label = 'habby'
        db_table = u'jacket_buttons'

class Jackets(models.Model):
    name = models.CharField(max_length=450, blank=True)
    deleted = models.IntegerField()
    date_entered = models.DateTimeField(auto_now_add=True)
    date_modified = models.DateTimeField(auto_now=True)

    class Meta:
        app_label = 'habby'
        db_table = u'jackets'

这些是资源模型:

class ButtonsResource(ModelResource):
    jacket = fields.ToManyField('habby.JacketsResource', "jacket", null=True, readonly=True)
    class Meta:
        queryset = Buttons.objects.filter(jacketsbuttons__deleted=0)
        resource_name = 'buttons'
        always_return_data = True
        filtering = {
                "id": ALL,
                "name": ALL,
                "deleted" : ALL,
                "date_entered" : ALL,
                "date_modified" : ALL,
                "jacket" : ALL_WITH_RELATIONS
        }

class JacketsResource(ModelResource):
    class Meta:
        queryset = Jackets.objects.filter(deleted=0)
        resource_name = 'jackets'
        always_return_data = True
        filtering = {
                "id": ALL,
                "name": ALL,
                "deleted" : ALL,
                "date_entered" : ALL,
                "date_modified" : ALL,
        }

现在,我要做的是过滤按钮,通过连接表上的一个参数和夹克表上的一个参数,它在django中完美运行:

Buttons.objects.filter(
        jacket__id="1",
        jacketsbuttons__deleted=0)

但我无法弄清楚如何在TastyPie中做同等效。

我试过这个:

GET /api/v1/buttons/?jacket__id=1&jacketsbuttons__deleted=0

但TastyPie忽略了jacketsbuttons__deleted参数,因为它在Resource.build_filters()中被删除,因为它在self.fields中找不到。

然后我尝试了上面显示的设置,在那里我将条件指定为元类中查询集的一部分,这让我想到了这个问题的主题。

查询资源并指定jacket__id时,它会完全忽略查询集,因此会忽略连接表过滤器。

...
class Meta:
            queryset = Buttons.objects.filter(jacketsbuttons__deleted=0)
...

GET /api/v1/buttons/?jacket__id=1

但是当我将jacket__id参数替换为另一个原生按钮参数,或者甚至省去所有参数时它都能正常工作,正确使用了连接表过滤器。

GET /api/v1/buttons/?name=round_button

我还尝试了TastyPie Cookbook中建议的“按请求更改查询集”,但是当我尝试通过jacket__id进行查询时,它也被忽略了:

class Meta:
        queryset = Buttons.objects.all()

    def get_object_list(self, request):
        return super(ButtonsResource, self).get_object_list(request).filter(jacketsbuttons__deleted=0)

那么,为什么会被忽略? 我怎么强迫它被使用?

此外,是否有其他人知道如何更好地实现这一目标?

提前致谢。

Jayd

1 个答案:

答案 0 :(得分:1)

之前我有过类似的情况,然后我做的是修改apply_filter函数到这样的事情:

def apply_filters(self, request, applicable_filters):
    """
    accept extra query in request
    """
    query_foo = request.GET.get('foo', None)
    query_bar = request.GET.get('bar', None)
    semi_filtered = super(RouteResource, self).apply_filters(request, applicable_filters)
    if query_foo:
        filtered_objects = semi_filtered.filter(..something with query_foo..)
        return filtered_objects
    else:
        return semi_filtered

您可以随时查看tastypie的资源代码,了解此功能的工作原理。希望它有所帮助。