我有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 %}
小小的侧面思考。
我一直在考虑将这个项目的一部分开源,因为我从社区得到了很多帮助。它可以帮助未来的编码者在同一个地方,并帮助发布更详细的未来问题。有什么想法吗?特别是关于用正确的方式去做。
如果有人想知道我目前所做的是将计算结果保存为字段,并在每次编辑交易时更新这些 "自动字段"。我还运行了一个脚本来更新所有现有的交易。
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()