django: select_related с entry_set - PullRequest
4 голосов
/ 29 июня 2009

Должен ли entry_set кэшироваться с select_related? Моя БД все еще получает звонки даже после того, как я использую 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 ]

4 голосов
/ 29 апреля 2012

С Django 1.4 вы можете использовать prefetch_related, который будет работать для отношений ManyToMany:

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

4 голосов
/ 29 июня 2009

Select_related () не работает со многими полями. На данный момент это то, что не планируется, но может стать будущей функцией. Смотри http://code.djangoproject.com/ticket/6432

В этом случае, если вы хотите сделать один запрос, у вас есть два варианта 1) Сделайте свой собственный SQL, вероятно, не будет красивым или быстрым. 2) Вы также можете запросить модель с помощью внешнего ключа. В этом случае вы сможете использовать select_related. Вы по-прежнему не сможете получить доступ к modelname_set, но с некоторым форматированием вы сможете проверять необходимые данные в одном запросе. Ни один из вариантов не идеален, но вы также можете заставить его работать на приличной скорости.

0 голосов
/ 27 апреля 2011

В Django 1.3 Вы можете использовать Queryset.values ​​() и сделать что-то вроде:

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

Только drwaback состоит в том, что вы получаете QuerySetList вместо QuerySet. Но это можно просто преодолеть, передав все необходимые поля в значения () - Вы должны изменить свое восприятие;)

Это может сэкономить вам несколько десятков запросов ...

Подробности можно найти здесь, в документации Django: http://docs.djangoproject.com/en/dev/ref/models/querysets/#django.db.models.query.QuerySet.values

...