如何在Django中查询泛型关系

时间:2014-06-04 21:27:47

标签: python sql django orm django-rest-framework

我正在制作活动Feed,但我无法弄清楚如何避免N + 1次查询。

基本上,团队或地方都有粉丝/活动,每个用户都是一个粉丝,其活动供稿来自他们所关注的团队/地点。

我模特的片段:

class Follower(models.Model):
    user = models.ForeignKey(User)
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = GenericForeignKey('content_type', 'object_id')

class Activity(models.Model):
    ...
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = GenericForeignKey('content_type', 'object_id')

class Team(models.Model):
    ...
    followers = GenericRelation('Follower')
    activities = GenericRelation('Activity')

class Place(models.Model):
    ...
    followers = GenericRelation('Follower')
    activities = GenericRelation('Activity')

我使用DRF并拥有Activity的基本序列化程序,我认为棘手的部分在视图中:

 class ActivityViewSet(viewsets.ModelViewSet):

     def list(self, request):
         #N+1 query
         activities = [f.content_object.activities.all() for f in request.user.follower_set.all()]

         ...

这样可行,但是有更好的方法来进行查询吗?

1 个答案:

答案 0 :(得分:2)

def list(self, request):
    items = {}
    for f in request.user.follower_set.all():
        items.setdefault(f.content_type_id, []).append(f.object_id)
    activities = Activity.objects.get_empty_queryset() # get_empty_query_set in <1.5
    for k, v in items.iteritems():
        activities |= Activity.objects.filter(content_type=k, object_id__in=v)

这归结为2个查询。它利用了这样一个事实:如果FollowerActivity与同一个对象(团队或地点)相关,则content_typeobject_id是相同的。一个小的python处理和tada,你有2个查询中与当前用户相关的所有活动。