Django / Tastypie中忽略注释

时间:2012-09-17 13:46:08

标签: django annotations tastypie

在我的Tastypie资源中,我正在注释我的查询集,但我没有看到注释流向JSON Tastypie生成并传回。代码很简单:

class CompetitionResource(ModelResource):
    total_tickets = fields.IntegerField(readonly=True)

    class Meta:
        queryset = Competition.objects.all().annotate(total_tickets=Count('ticket__ticketownership__user__id', distinct=True))

我在我的查询集中生成和注释的那个Count根本没有显示在最终的JSON中。最终的JSON有一个total_users字段(因为我在ModelResource中声明了一个),但它是null。我是否遗漏了任何明显的东西以确保这样的注释得以通过?如果没有,那么解决这个问题的方法是什么?

一种方法是在我的Model中创建一个属性,然后将ModelResource中的total_users字段绑定到该属性。但这可能会导致我从数据库中抽取的每个竞赛的Count查询,这并不好。我想在一个注释类型查询中执行此操作。

3 个答案:

答案 0 :(得分:5)

好的,我明白了。您可以简单地使用可添加到ModelResource的自定义dehydrate_ [字段名称]方法。对于每个ModelResource字段,Tastypie检查你是否指定了一个dehydrate_ [field name]方法,如果你这样做了,那么当它将一个对象处理成一个bundle(然后以JSON或XML或其他形式输出)时,它会调用该方法。对于该特定对象,此dehydrate_ [field name]方法获取Tastypie为此之前创建的包。好处是这个bundle在bundle.obj下有原始对象。该对象仍将具有您在get_object_list中提供的原始注释(如上面的答案所示)。所以你可以使用以下代码。

class CompetitionResource(ModelResource):
    total_tickets = fields.IntegerField(readonly=True)

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

    def get_object_list(self, request):
        return super(CompetitionResource, self).get_object_list(request).annotate(total_tickets=Count('ticket__ticketownership__user__id', distinct=True))

    def dehydrate_total_tickets(self, bundle):
        return bundle.obj.total_tickets

从自定义dehydrate_ [field name]方法返回的任何内容都将正确存储为该字段在该对象的包中的最终值,然后正确处理为输出。

答案 1 :(得分:0)

它没有出现在文档中,但是查看源代码有一个 attribute 参数,该参数可以传递给字段声明,该声明可以用于将其绑定到模型实例。

  

(可选)接受attribute,该字符串应为   在执行期间,可以使用实例属性或可调用对象   dehydrate或在hydrate期间将数据推送到对象上。   默认值为None,表示将手动访问数据。

因此,在您的示例中,以下方法可以解决问题。

class CompetitionResource(ModelResource):
    total_tickets = fields.IntegerField(readonly=True, attribute='total_tickets')

    class Meta:
        queryset = Competition.objects.all().annotate(total_tickets=Count('ticket__ticketownership__user__id', distinct=True))

脱水解决方案适用于用值填充发送的对象,但不允许您轻松利用Tastypie的某些其他功能,例如内置过滤(我相信排序)。可以将字段定义与属性参数一起使用。

答案 2 :(得分:-1)

我认为您的问题可能与queryset的Tastypie文档中提供的警告有关:

  

如果在其中放置任何可调用对象,它们将仅被评估一次(当实例化Meta类时)。这尤其会影响与日期/时间相关的事物。请参阅:ref:cookbook以了解解决方案。

查看食谱中的relevant section,我认为你应该尝试这样的事情:

class CompetitionResource(ModelResource):
    total_users = fields.IntegerField(readonly=True)

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

    def get_object_list(self, request):
        return super(CompetitionResource, self).get_object_list(request).annotate(total_tickets=Count('ticket__ticketownership__user__id', distinct=True))