Как улучшить медленное представление django, вовлекая две связанные модели «через» промежуточный? - PullRequest
1 голос
/ 11 июля 2011

Я пытаюсь создать представление, которое выводит 2D-таблицу, относящуюся к двум моделям "через" третью промежуточную модель. Он отлично работает на относительно небольших наборах запросов, но становится все медленнее для больших. Есть ли лучший способ реализовать представление, чтобы ускорить его?

Я дал аналогичную версию своих моделей и просмотр для простоты, но при необходимости я могу опубликовать фактические модели / представление, если они могут быть причиной замедления. Пожалуйста, простите, если я включил незначительные ошибки, фактический вид / модели работают.

Спасибо.

Желаемый вывод:

artist                 The Foo Bars       FUBAR     Bas Bix
Joe Blow                 5/10/1975                 12/7/2010
Fred Noname             12/12/2012      10/2/2010   
Smith John               2/2/2002       

Аналоговые модели:

class Person(models.Model):
    name = models.CharField(max_length=128)

class Group(models.Model):
    name = models.CharField(max_length=128)
    members = models.ManyToManyField(Person, through='Membership', related_name="group")

class Membership(models.Model):
    person = models.ForeignKey(Person, related_name="membership")
    group = models.ForeignKey(Group, related_name="membership")

    date_joined = models.DateField()
    invite_reason = models.CharField(max_length=64)

Аналогичный вид:

people = Person.objects.all().select_related()
groups = Group.objects.all().select_related()
group_names = [group.name for group in groups]
table = [["artist"] + group_names]
for person in people:
    row = [person.name]
    for group in groups:
        membership = person.membership.all() & group.membership.all()
        if membership:
            membership = membership[0]
            row.append(membership.date_joined)
        else:
            row.append("")
    table.append(row)

1 Ответ

1 голос
/ 11 июля 2011

Важно ответить, почему вы просматриваете медленно, основываясь на результатах таких инструментов, как профилирование и django-debug-toolbar. Трудно сказать вам, как это исправить, не зная, где замедление.

В этом случае, поскольку мы имеем дело со многими отношениями, я предполагаю, что замедление происходит из-за огромного количества запросов. Чтобы решить эту проблему, вам нужно вспомнить, сколько человек представлено в базе данных (но, похоже, вы это понимаете). Короче говоря, нет прямой связи между человеком и группой, и вместо этого в членстве есть и человек, и группа.

Это означает, что вы не можете использовать select_related, чтобы сократить количество запросов. Правильный подход сводится к запросу таблицы членства вместо таблицы Person. Правильный подход будет зависеть от особенностей вашей ситуации. Если то, что вы действительно ищете, это данные о членстве, вы можете просто набрать Membership.objects.all().select_related() (или какой-то другой вариант). Если вы ищете людей, сделайте что-то вроде:

 memberships = Membership.objects.all()
 membership_dict = {}
 for m in membership:
      try:
          membership_dict[m.person].append(m)
      except KeyError:
          membership_dict[m.person] = [m,]
 people = Person.objects.all()
 for p in people:
      p.groups = membership_dict[p]

Это сократит сотни или тысячи запросов до двух запросов. Стоимость которого заключается в том, что код Python немного менее эффективен.

Имейте в виду, я просто предполагаю, что большое количество запросов является вашей проблемой, у вас могут быть другие серьезные проблемы, которые я не вижу; например, наличие индекса, интенсивный процессор Python, очень большие таблицы и т. д.

...