django:select_lated with entry_set

时间:2009-06-29 06:34:23

标签: django django-models django-select-related

是否应使用select_related缓存entry_set?即使我使用select_related后,我的数据库仍然会收到电话。相关部分

class Alias(models.Model):
    achievements = models.ManyToManyField('Achievement', through='Achiever')

    def points(self) :
        points = 0
        for a in self.achiever_set.all() :
            points += a.achievement.points * a.count
        return points

class Achievement(models.Model):
    name = models.CharField(max_length=100)
    points = models.IntegerField(default=1)

class Achiever(models.Model):
    achievement = models.ForeignKey(Achievement)
    alias = models.ForeignKey(Alias)
    count = models.IntegerField(default=1)

aliases = Alias.objects.all().select_related()
for alias in aliases :
    print "points : %s" % alias.points()
    for a in alias.achiever_set.all()[:5] :
        print "%s x %d" % (a.achievement.name, a.count)

我在开始时看到一个很大的联接查询,然后个人调用每个成就。点数和名称查找。

这是一个错误,还是我做错了什么?

3 个答案:

答案 0 :(得分:4)

Select_related()不适用于manytomanyfields。目前,这是未计划的,但可能是未来的功能。见http://code.djangoproject.com/ticket/6432

在这种情况下,如果您想进行单个查询,则有两个选项 1)制作自己的SQL,可能不会很漂亮或很快。 2)您还可以使用foreignkey查询模型。在这种情况下,您可以使用select_related。您将无法访问modelname_set,但通过某种格式化,您可以在单个查询中审核所需的数据。没有一个选项是理想的,但你可以让它以相反的速度工作。

答案 1 :(得分:4)

使用Django 1.4,您可以使用prefetch_related,它将适用于ManyToMany关系:

https://docs.djangoproject.com/en/dev/ref/models/querysets/#prefetch-related

答案 2 :(得分:0)

在Django 1.3中您可以使用Queryset.values()并执行以下操作:

Alias.objects[.filter().exclude() etc.].values('achievements__name', 'achievement__points')

只有drwaback是你获得QuerySetList而不是QuerySet。但是这可以通过将所有必要的字段传递给值()来简单地克服 - 你必须改变你的看法;)

这可以为您节省少量查询...

详细信息可以在django docs中找到: http://docs.djangoproject.com/en/dev/ref/models/querysets/#django.db.models.query.QuerySet.values