Django减少页面SQL查询(代码优化)

问题描述 投票:0回答:1

我有2个页面越来越慢,其中一个页面在涉及到10多个对象左右的时候完全无法使用。用了django-debug-toolbar包后,我知道问题出在哪里了。

ListView page: 23971.48 ms (182 queries including 180 similar and 178 duplicates )

我对做优化的数据库查询相当陌生,到目前为止,所有的东西都能正常使用。然而,就像我之前说的,如果我有超过10个对象(在这种情况下是文档交易),事情就会开始崩溃。我相信一个大的解决方案是计算这些统计数据,然后将它们保存为字段。这是正确的方法吗,完全不是,还是只是从头开始?

模型.py (你可以看出有很多函数,调用了更多的函数)

class Trade(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE, blank=True)
    ...

    # P/L Value = Sum of all buys * ( Entry Cost Per Unit (CPU) - Exit Cost Per Unit (CPU) )
    def get_profit_loss_value_or_None(self):
        if self.get_exit_cpu() > 0:
            if self.type == 'Long':
                result = self.get_entries().aggregate(
                get_profit_loss_value=Sum('amount', output_field=models.FloatField()
                                               ) * (self.get_exit_cpu() - self.get_entry_cpu()))['get_profit_loss_value']
                return 0 if result is None else result
            elif self.type == 'Short':
                result = self.get_entries().aggregate(
                get_profit_loss_value=Sum('amount', output_field=models.FloatField()
                                               ) * -1 * (self.get_exit_cpu() - self.get_entry_cpu()))['get_profit_loss_value']
                return 0 if result is None else result
        else:
            return 0

    #Fight unexpected None errors https://stackoverflow.com/questions/60576545/nonetype-and-float-error-how-to-avoid-nonetype/60576597?noredirect=1#comment107169241_60576597
    def get_profit_loss_value(self):
        ret = self.get_profit_loss_value_or_None()
        return 0 if ret is None else ret


    # profit_loss_value_fees = profit_loss_value - fees
    def get_profit_loss_value_fees(self):
        result = self.get_profit_loss_value() - self.get_fees()
        return result

视图.py

class TradeListView(LoginRequiredMixin, ListView):
    model = Trade

    def get_queryset(self):
        return Trade.objects.filter(user=self.request.user).order_by('created')

交易列表.html

<!-- Content Row -->

<div class="row">
    {% for trade in object_list reversed %}
    <div class="col-xs-12 col-sm-6 col-lg-4">
        <div class="card mb-3 shadow-sm">
            {% if trade.image %}
            <a href="{{ trade.image.url }}" target="_blank"><img src="{{ trade.image.url }}" class="img-fluid card-img-top" alt="Responsive image"></a>
            {% else %}
            <a target="_blank"><img src="https://tradejournal.s3.amazonaws.com/media/no-image-available-icon.jpg" class="img-fluid card-img-top" alt="Responsive image"></a>
            {% endif %}

            <div class="card-body">
                <h4>
                    <a href="{% url 'trade-detail' trade.id %}" class="card-title card-link">
                        {% if trade.status == "cl" %}
                            {% if trade.get_profit_loss_value_fees > 0 %}
                            <font color="green">${{ trade.get_profit_loss_value_fees|floatformat:2 }}</font>
                            {% elif trade.get_profit_loss_value_fees == 0 %}
                            <font color="#5a5c69">${{ trade.get_profit_loss_value_fees|floatformat:2 }}</font>
                            {% elif trade.get_profit_loss_value_fees < 0 %}
                            <font color="red">${{ trade.get_profit_loss_value_fees|floatformat:2 }}</font>
                            {% endif %}
                        {% else %}
                        <font color="orange">{{  trade.get_status_display }}</font>
                        {% endif %}
                    </a>
                </h4>
                <p>
                    <a href="{% url 'trade-detail' trade.id %}" class="card-text card-link">
                        {{ trade.asset }} | {{ trade.symbol | upper }} | {{ trade.type }}
                    </a>
                </p>
                <p class="card-text">
                    <small>
                        <a href=" {% url 'trade-detail' trade.id %} " class="card-link text-muted"><i class="fas fa-binoculars"></i> View</a>
                        {% if user.is_authenticated and trade.user == user %}
                        <a href=" {% url 'trade-update' trade.id %} " class="card-link text-muted"><i class="fas fa-edit"></i> Edit</a>
                        <a href=" {% url 'trade-delete' trade.id %} " class="card-link text-muted"><i class="fas fa-trash"></i> Delete</a>
                        {% endif %}
                    </small>
                </p>   
            </div>

        </div>
    </div>
    {% empty %}
    <p class="lead">No trades yet</p>
    {% endfor %}

</div>
{% endblock content %}

小小的侧面思考。

我一直在考虑将这个项目的一部分开源,因为我从社区得到了很多帮助。它可以帮助未来的编码者在同一个地方,并帮助发布更详细的未来问题。有什么想法吗?特别是关于用正确的方式去做。

sql django postgresql optimization django-queryset
1个回答
0
投票

如果有人想知道我目前所做的是将计算结果保存为字段,并在每次编辑交易时更新这些 "自动字段"。我还运行了一个脚本来更新所有现有的交易。

models.py (贸易类内部)

#AUTOMATED FIELDS
WIN = 'win'
LOSS = 'loss'
SCRATCH = 'scratch'

RESULT_CHOICES = [
    (WIN, 'win'),
    (LOSS, 'loss'),
    (SCRATCH, 'scratch'),
]
max_amount = models.FloatField(null=True)
fees = models.FloatField(null=True)
entry_cpu = models.FloatField(null=True)
exit_cpu = models.FloatField(null=True)
position_size = models.FloatField(null=True)
profit_loss_percent = models.FloatField(null=True)
profit_loss_value = models.FloatField(null=True)
profit_loss_value_fees = models.FloatField(null=True)
trade_result = models.CharField(max_length=7, choices=RESULT_CHOICES, null=True)

def save(self):
    self.max_amount = self.get_max_amount()
    self.fees = self.get_fees()
    self.entry_cpu = self.get_entry_cpu()
    self.exit_cpu = self.get_exit_cpu()
    self.position_size = self.get_position_size()
    self.profit_loss_percent = self.get_profit_loss_percent()
    self.profit_loss_value = self.get_profit_loss_value()
    self.profit_loss_value_fees = self.get_profit_loss_value_fees()
    self.trade_result = self.get_trade_result()
    if not self.id:
        self.created = timezone.now()
    self.modified = timezone.now()
    return super(Trade, self).save()
© www.soinside.com 2019 - 2024. All rights reserved.