创建报告时,Django模板变慢(许多变量,许多模型,许多列表)

时间:2019-01-10 19:27:23

标签: django django-templates

我是一个新手,试图使用Django创建有关团队参与者的报告,而我所做的事情根本上是错误的,并且花了几个小时试图找出问题所在-该报告仍在影响数据库大约4000次以上下面是我正在做的缩写。

任何帮助,指针或其他资源将非常感谢

对于团队模型:

class Team(BenchmarkData):
    year = models.ForeignKey(Period, on_delete=models.CASCADE, null=True)
    sponsor = models.ForeignKey(Person, on_delete=models.CASCADE)
    goal = models.ForeignKey(Goal, on_delete=models.CASCADE, null=True)
        ...other non-relational properties...

    def _participation_queryset(self):
        from .participation import Participation
        pp = Participation.objects.filter(team=self.id)
                return pp

    @cached_property
    def average_points(self):
        list_participation = [participation.calculated_yearly_points_per_hour for participation in self._participation_queryset()] 
        try: return mean(list_participation)

    @cached_property
    ...

对于参与模式:

class Participation(models.Model):
    person = models.ForeignKey(Person, on_delete=models.CASCADE, null=True)
    team = models.ForeignKey(Team, on_delete=models.CASCADE, null=True)
    year = models.ForeignKey(Period, on_delete=models.CASCADE, null=True)

    start_date = models.DateField('Began', null=True)
    end_date = models.DateField('Left', blank=True, null=True)
    active = models.BooleanField('Active?', null=True)

    yearly_points = models.FloatField(default=0, null=True)
    yearly_hours_of_play = models.FloatField(default=0)
        ...other non-relational properties...

    @cached_property
    def calculated_yearly_points_per_hour(self):
        try: return self.yearly_points / self.yearly_hours_of_play
        except ZeroDivisionError: return 0

        ...other cached properties...

对于我的观点,我使用了:

class PlanReport(TemplateView):
    template_name = 'pension/report/index.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)

        self.team = get_object_or_404(Plan, id=self.kwargs['team_id'])
        self.sponsor = get_object_or_404(Company, id=self.kwargs['sponsor_id'])
        self.report = get_object_or_404(Report, id=self.kwargs['plan_id'])

        pp = Participation.objects.filter(plan_id=self.plan)
        s = pickle.dumps(pp.query)
        s2 = pickle.loads(s)
        participation_list = s2.model.objects.all()

        # Add in other context information
        context['team'] = self.team
        context['sponsor'] = self.sponsor
        context['report'] = self.report
        context['participation_list'] = participation_list

        return context

报告模板结构为:

index.html
 - section1.html
 - section2-table-of-group-participants-with-stats-on-each-participant.html
...

该表的模板显示:

...other html...
    {% for participation in participation_list %}
        <tr>
            <td>{{ participation.person }}</td>
            <td>{{ participation.team }}</td>
            <td>{{ participation.year }}</td>
            <td>{{ participation.start_date }}</td>
            <td>{{ participation.end_date }}</td>
            <td>{{ participation.active }}</td>
            <td>{{ participation.yearly_points }}</td>
            <td>{{ participation.yearly_hours_of_play }}</td>
            <td>{{ participation.calculated_yearly_points_per_hour }}</td>
                ...other calculated attributes...
    </tr>
    {% empty %}
    </tbody>
    </table>
    <p>No data imported into the list</p>
    {% endfor %}

感谢到目前为止的答复!

@Daniel Roseman:

谢谢。

正如您提到的,我将所有@cached_properies都恢复为@property(我怀疑它们会减慢速度!)

我删除了所有的酱菜材料-我听说有人试图这样做,但并不太了解它的相关性-所以我想它与缓存实际上并没有多大关系-至少在我的情况下。

我还更改了以下内容:

在团队模型中:

def _participation_queryset(self):
    from .participation import Participation
    return self.participation_set.all()

在create_report视图中:

    participation_list = self.team.participation_set.all().select_related('team')

    ...

    context['participation_list'] = participation_list

1 个答案:

答案 0 :(得分:0)

您的代码有两个主要的低效率之处。

首先,您已经使用_participation_queryset方法定义了自己的方法来吸引团队成员。这不仅是不必要的,而且会破坏 Django的内置缓存;每次调用时都会对其进行评估。删除它并参考self.participation_set.all()

另一个,也许甚至更重要的一点是,您无需执行任何操作即可为您的任何模型预加载任何相关数据。因此,即使您实际上已经有了团队,对{{ participation.team }}的每次调用都会导致数据库命中。当您在视图中获取“参与”查询集时,应使用select_related(应通过对participation_set的相同调用来完成此操作)。

(而且我不明白您在那儿进行的腌菜转储/装载操作。您到底为什么要这样做?还要注意,没有理由将值分配为实例属性。)

所以您的视图如下:

def get_context_data(self, **kwargs):
    context = super().get_context_data(**kwargs)

    team = get_object_or_404(Plan, id=self.kwargs['team_id'])
    sponsor = get_object_or_404(Company, id=self.kwargs['sponsor_id'])
    report = get_object_or_404(Report, id=self.kwargs['plan_id'])

    participation_list = team.participation_set.all().select_related('team')
    ...

最后,我不认为您的cached_properties发挥了您的预期作用,并且可能使事情变得更加低效。 calculated_yearly_points_per_hour之类的东西是两个整数的简单除法,并且计算起来很简单。根本不需要缓存它。删除大部分(如果不是全部)装饰器。