django many -to -many field :предварительная выборка только первичных ключей

Я пытаюсь оптимизировать запросы к базе данных для приложения Django. Вот упрощенный пример:

class Label(models.Model):
    name = models.CharField(max_length=200)
    #... many other fields...

class Thing(models.Model):
    name = models.CharField(max_length=200)
    labels = models.ManyToManyField(Label)

У меня есть функция, которая извлекает все Labelи Thingи помещает их в структуру данных JSON, в которой Thingссылаются на Labelс помощью их idс (первичные ключи ). Что-то вроде этого:

{
    'labels': [
        { 'id': 123, 'name': 'label foo' },
       ...
    ],
    'things': [
        { 'id': 45, 'name': 'thing bar', 'labels': [ 123,... ] },
       ...
    ]
}

Каков наиболее эффективный способ получения такой структуры данных с помощью Django? Предположим, у меня есть LLabelс и TThingс, а среднее Thingимеет xLabelс.

Способ 1.:

data = {}
data['labels'] = [model_to_dict(label) for label in Label.objects.all()]
data['things'] = [model_to_dict(thing) for thing in Thing.objects.all()]

Получается (1 + 1 + T)запросов к базе данных, поскольку model_to_dict(thing)необходимо получить Labelдля каждого Thingотдельно.

Способ 2.:

data = {}
data['labels'] = [model_to_dict(label) for label in Label.objects.all()]
data['things'] = [model_to_dict(thing) for thing in
                    Thing.objects.prefetch_related('labels').all()]

Это делает (1 + 1 + 1 )только запросов к базе данных, поскольку для извлеченных Thingтеперь предварительно выбираются Labelв одном дополнительном запросе.

Это все еще неудовлетворительно.prefetch_related('labels')будет получать много копий одного и того же Label, тогда как мне нужны только их id. Есть ли способ предварительно выбрать idиз Labelтолько? Я пробовал prefetch_related('labels__id'), но это не сработало. Я также обеспокоен тем, что, поскольку T большое (сотни ), prefetch_related('labels')приводит к SQL-запросу с большим предложением IN. L намного меньше (< 10 ), так что я мог бы сделать это вместо этого:

Метод 3:

data = {}
data['labels'] = [model_to_dict(label) for label in
                    Label.objects.prefetch_related('thing_set').all()]
things = list(Thing.objects.all())
# plug in label ids by hand, and also fetch things that have zero labels
# somehow

Это приводит к меньшему предложению IN, но все еще неудовлетворительно, потому что prefetch_related('thing_set')извлекает дубликаты Things, если Thingимеет несколько Labels.

Резюме:

Labelи Thingсоединены ManyToManyField. Я все равно получаю всеLabelи Thing. Итак, как мне также эффективно получить их отношения many -to -many?

8
задан cberzan 23 April 2012 в 01:23
поделиться