如何“通过”改进涉及两个相关模型的慢速 django 视图中间体?

发布于 2024-11-19 15:35:23 字数 1579 浏览 4 评论 0原文

我正在尝试创建一个视图,该视图输出“通过”第三个中间模型关联两个模型的二维表。它在相对较小的查询集上运行良好,但对于较大的查询集却变得越来越慢。有没有更好的方法来实现视图以加快速度?

为了简单起见,我给出了模型和视图的类似版本,但如果需要,我可以发布实际的模型/视图(如果它们可能导致速度变慢)。如果我有一些小错误,请原谅我,实际的视图/模型是有效的。

谢谢。

所需输出:

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)

I'm trying to create a view that outputs a 2D table relating two models "through" a third intermediate model. It runs fine on relatively small querysets but becomes increasingly slow for larger ones. Is there a better way of implementing the view to speed it up?

I've given an analogous version of my models and view for simplicity but if needed I can post the actual models/view if they could be a cause for a slowdown. Please forgive me if I've included minor errors, the actual view/models work.

Thank you.

Desired output:

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       

Analogous models:

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)

Analogous view:

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)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

小草泠泠 2024-11-26 15:35:24

重要的是要根据分析和 django-debug-toolbar 等工具的输出来回答为什么您的视图速度很慢。在不知道速度减慢的地方的情况下,很难告诉您如何解决它。

在这种情况下,由于我们正在处理多对多关系,我认为速度减慢是由于大量查询造成的。为了解决这个问题,您需要记住数据库中代表了多少个(但您似乎理解这一点)。简而言之,个人和团体之间没有直接关系,相反,会员资格既包含个人又包含团体。

这意味着您不能使用 select_lated 来减少查询数量。正确的方法是查询 Membership 表而不是 Person 表。正确的方法将取决于您具体情况。如果您真正想要的是会员数据,您可能只需使用 Membership.objects.all().select_lated() (或某些变体)即可。如果您正在寻找人员数据,请执行以下操作:

 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]

这会将数百或数千个查询减少为 2 个查询。其代价是Python代码的效率稍低。

请记住,我只是假设大量查询是您的问题,您可能还有其他我看不到的主要问题;例如需要索引、CPU密集型Python、非常大的表等。

It's important to answer why you're view is slow based on output from tools like profiling and django-debug-toolbar. It's hard to tell you how to fix it without knowing where the slowdown is.

In this case since we're dealing with a manytomany relationship I assume in that the slowdown is due to a huge number of queries. In order to solve that you need to remember how manytomany's are represented in the database (but you seem to understand that). In brief there is no direct relationship between person and group and instead a membership has both a person and a group.

That means that you can't use select_related to cut the number of queries down. The correct approach is going to come down to querying the Membership table instead of the Person table. The correct approach is going to depend on the particulars of your situation. If what you're really after is membership data you may be able to just simply go Membership.objects.all().select_related() (or some variation). If you're after people data do something like:

 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]

This will cut what could be hundreds or thousands of queries down to 2 queries. The cost of which is that the python code is slightly less efficient.

Bear in mind I'm simply assuming that a large number of queries is your problem, you could have other major issues that I can't see; such as needing an index, cpu intensive python, very large tables, etc.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文