Добавление дополнительных полей в QuerySet, который охватывает отношение - PullRequest
1 голос
/ 12 декабря 2011

Я пытаюсь сделать что-то вроде этого:

class A(models.Model):
    members = models.ManyToManyField(B)

class B(models.Model):
    pass

# not sure what the right query is here
results = A.objects.all().[members.extra(select={"extra_field": ...})?]

# I want to be able to write this using the result of my query:
for r in result:
    for m in r.members:
        print m.extra_field

Можно ли заполнить это extra_field без создания нового запроса для каждой модели B в элементах?

Ответы [ 3 ]

2 голосов
/ 12 декабря 2011

Пока в Django 1.4 не прибудет предварительная выборка, это будет немного волосатым.Держитесь за свою шляпу.

Во-первых, вы должны иметь возможность запрашивать таблицу, которая связывает две ваши модели.Если вы не хотите явно определять сквозную таблицу, вы можете использовать неуправляемую модель, например, так:

class AB(models.Model):
    a = models.ForeignKey('A')
    b = models.ForeignKey('B')

    class Meta:
        db_table = 'myapp_a_b'
        managed = False

Получив это, вы можете глубоко вдохнуть, держать нос и делать что-то вродеследующее:

# Grab the links between A and B
a_b_relationships = AB.objects.all().values('a_id', 'b_id')

# Make an indexed reference for your B objects
all_b = B.objects.all().extra(select={'extra_field': ...})
b_dict = dict((b.pk, b) for b in all_b)

# Make a dict so that for any given A object we can immediately grab
# a list of its B objects
b_by_a = {}
for rel in a_b_relationships:
    a_id = rel['a_id']
    b = b_dict[rel['b_id']]

    if a_id not in b_by_a:
        b_by_a[a_id] = []

    if b not in b_by_a[a_id]
        b_by_a[a_id].append(b)

results = A.objects.all()

for r in result:
    members = b_by_a.get(r.id, [])

    for m in members:
        print m.extra_field

Это противно, но работает.Имейте в виду, что если таблицы A и B станут большими, вы столкнетесь с проблемами производительности - объекты Django занимают lot памяти и могут очень медленно повторяться.Если вы в конечном итоге фильтруете или разбиваете на части А, вам нужно будет также добавить соответствующие фильтры к запросам AB и B.

Если у кого-то есть более чистый / более эффективный способ сделать это, я бы с удовольствиемзнаю!

1 голос
/ 12 декабря 2011
0 голосов
/ 07 мая 2014

Теперь, когда мы находимся на Django 1.6, это тривиально с:

results = B.objects.prefetch_related('a')
...