我有点被一些似乎并不复杂的东西所阻挡。这是我的模特:
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
代码运行良好,但通过循环遍历每个Quality流的所有里程碑,我感觉不太舒服。我想必须有更好的方法来实现这一目标。有什么想法吗?
答案 0 :(得分:2)
您正在做的事情没有错,但可以通过在视图中执行查询来进行一些数据库优化,尤其是使用select_related():
此外,如果您的模型有一堆字段,但您只需要一些字段,则只能使用()或defer()。我已经看到使用延迟来避免大字段的显着性能提升。 only()只是defer()的反转:
https://docs.djangoproject.com/en/1.5/ref/models/querysets/#defer
你的模型看起来不太复杂,所以我认为使用select_related()会对你有用。我强烈建议您使用Django debug toolbar进行优化决策。调试工具栏将显示实际的select语句以及每个语句所花费的时间。在花费太多时间进行优化之前,了解是否确实存在问题,这很有用。
希望这有帮助
答案 1 :(得分:2)
每当你认为你必须像你一样做多个下行循环时,想一想你是否可以从另一端解决问题。
正如@Pathetique所指出的,以下链接显示了如何最大限度地减少您正在执行的查询数量:
该链接中的重点是select_related
仅适用于ForeignKeys
,而prefetch_related
仅适用于ManyToManyFields
。
由于您从“我有一组团队,现在我想要显示与这些团队相关的所有数据”的角度来处理这个问题,因此您无法使用自{{{}以来可用的任何优化。 1}}没有Team
或ForeignKeys
。
相反,您可以像这样处理问题“我希望显示所有里程碑,按团队分组,然后按质量流分组”。由于您的Milestone类可以访问您需要的所有数据,因此它使查询集非常容易构造,只生成一个查询。
ManyToManyFields
现在,您的模板将打破您构建它的方式。这就是我之前提到的问题的定义所在。您拥有所有里程碑,但是您希望按团队分组,然后按质量流分组。我们的查询集的排序现在可以帮助我们,因为我们可以遍历所有里程碑,并检查我们是否需要新的团队或新的质量流。
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)
)
上述模板使用ifchanged模板标记,这似乎是为此目的而设计的。