3

我有点受阻,它似乎不是很复杂。这是我的模型:

class Team(models.Model):
    name = models.CharField('team name', max_length=200, unique=True)

class QualityStream(models.Model):
    name = models.CharField('quality stream name', max_length=200, unique=True)
    team = models.ManyToManyField(Team)

class Milestone(models.Model):
    name = models.CharField('milestone name', max_length=200)
    quality_stream = models.ForeignKey(QualityStream)
    team = models.ForeignKey(Team)

如您所见,一个团队可以有几个预定义的质量流,以及确实属于一个质量流的几个要实现的里程碑。

这是我的看法:

<p>{{team.name}}</p>

{% for stream in team.qualitystream_set.all %}
    <p>{{stream.name}}</p>
    {% for milestone in team.milestone_set.all %}

        {% if milestone.quality_stream.id == stream.id  %}
           <p>{{milestone.name}}</p>               
        {% endif %}

    {% endfor %}    
{% endfor %}

这个想法是显示团队、与团队相关的质量流以及按质量流分组的每个里程碑:

Team

  Quality Stream 1
     Milestone 1 for Quality Stream 1
     Milestone 2 for Quality Stream 1
  Quality Stream 2
     Milestone 1 for Quality Stream 2
     Milestone 2 for Quality Stream 2

代码运行良好,但循环每个质量流的所有里程碑让我感觉不太舒服。我想一定有更好的方法来实现这一点。有任何想法吗?

4

2 回答 2

2

您正在做的事情没有任何问题,但是通过在视图中执行查询可能会有一些数据库优化,特别是使用 select_related():

https://docs.djangoproject.com/en/1.5/topics/db/optimization/#retrieve-everything-at-once-if-you-know-you-will-need-it

此外,如果您的模型有一堆字段但您只需要一些字段,您可以使用 only() 或 defer()。我已经看到使用 defer 来避免大字段的显着性能提升。only() 是 defer() 的逆:

https://docs.djangoproject.com/en/1.5/ref/models/querysets/#defer

您的模型似乎不太复杂,所以我认为仅使用 select_related() 对您有用。我强烈建议使用Django 调试工具栏来做出优化决策。调试工具栏将向您显示实际的选择语句以及每个语句所花费的时间。在花太多时间优化之前知道是否真的存在问题是很好的。

希望这可以帮助

于 2013-03-16T20:35:17.640 回答
2

每当您认为必须像以前那样执行多个下降循环时,请考虑是否可以从另一端解决问题。

正如@Pathetique 指出的那样,以下链接显示了如何最小化您正在执行的查询数量:

https://docs.djangoproject.com/en/1.5/topics/db/optimization/#retrieve-everything-at-once-if-you-know-you-will-need-it

该链接中的亮点是select_related仅适用于ForeignKeys,并且prefetch_related仅适用于ManyToManyFields

由于您是从“我有一组团队,现在我想显示与这些团队相关的所有数据”的角度来解决这个问题的,因此您无法使用任何可用的优化,因为Team没有ForeignKeysManyToManyFields.

相反,您可以像这样处理问题:“我想显示所有里程碑,按团队分组,然后按质量流分组”。由于您的 Milestone 类可以访问您需要的所有数据,因此它使查询集非常容易构建,只生成一个查询。

def my_view(request):
    queryset = Milestone.objects.select_related(
        'team', 'quality_stream'
    ).order_by(
        'team__name', 'quality_stream__name'
    ) # a single query to fetch all teams + streams + milestones

    return render_to_response('/your/template.html', 
        { 'milestones':queryset },
        context_instance=RequestContext(request)
    )

现在,您的模板将打破您构建它的方式。这就是我之前提到的问题的定义所在。您拥有所有里程碑,但您希望按团队对它们进行分组,然后按质量流进行分组。查询集的排序现在对我们有帮助,因为我们可以遍历所有里程碑,并检查我们是否适合新团队或新质量流。

# your template
{% for milestone in milestones %}
    {% ifchanged %} <p> {{ milestone.team.name }} </p> {% endifchanged %}
    {% ifchanged %} <p> {{ milestone.quality_stream.name }} </p> {% endifchanged %}
    <p> {{ milestone.name }} </p>
{% endfor %}

上面的模板使用了ifchanged模板标签,它似乎就是为此目的而设计的。

于 2013-03-17T00:15:06.387 回答