У меня есть две модели, связанные один-ко-многим:
class Person(models.Model):
name = models.CharField(max_length=255);
surname = models.CharField(max_length=255);
age = models.IntegerField();
class Dog(models.Model):
name = models.CharField(max_length=255);
owner = models.ForeignKey('Person');
Я хочу вывести список людей и ниже каждого человека список собак, которые у него есть. Вот как я могу это сделать:
в поле зрения:
persons = Person.objects.all()[0:100];
в шаблоне:
{% for p in persons %}
{{ p.name }} has dogs:<br />
{% for d in persons.dog_set.all %}
- {{ d.name }}<br />
{% endfor %}
{% endfor %}
Но если я сделаю это так, Django выполнит 101 SQL-запрос, что очень неэффективно.
Я пытался создать собственный менеджер, который будет получать всех людей, затем всех собак и связывать их в python, но тогда я не могу использовать paginator (мой другой вопрос: Django: Paginator + raw SQL запрос ) и выглядит довольно некрасиво.
Есть ли более изящный способ сделать это?
UPDATE
Решение на основе записи в блоге @Daniel Roseman
all_objects = Person.objects.select_related().all();
paginator = Paginator(all_objects, 100);
try:
page = int(request.GET.get('page', '1'))
except ValueError:
page = 1
try:
current_page = paginator.page(page)
except (EmptyPage, InvalidPage):
current_page = paginator.page(paginator.num_pages)
person_list = dict([(obj.id, obj) for obj in current_page.object_list])
id_list = [obj.id for obj in current_page.object_list]
objects = Dog.objects.filter(owner__id__in=id_list)
relation_dict = {}
for obj in objects:
relation_dict.setdefault(obj.owner_id, []).append(obj)
for id, related_items in relation_dict.items():
person_list[id].dogs = related_items