Я создаю приложение для криптовалюты, я заполняю некоторые таблицы криптографическими данными, чтобы получить некоторые из этих данных, мне нужно вычислить значения API по значениям базы данных. Я сделал это, создав функции и выполнив вызов API в файле models.py, но это сильно замедлило работу моего приложения. Я делаю что-то неправильно? Есть ли лучший способ закодировать это?
models.py ниже. Сильно замедлился с момента добавления 4 свойств
class Transaction(models.Model):
currency = models.CharField(max_length=20)
amount = models.IntegerField()
total_price = models.DecimalField(max_digits=8, decimal_places=2)
date_purchased = models.DateTimeField()
note = models.TextField(default = "")
owner = models.ForeignKey(User, on_delete=models.CASCADE)
amount_per_coin = models.DecimalField(max_digits=8, decimal_places=2, editable=False)
def save(self, *args, **kwargs):
self.amount_per_coin = self.total_price / self.amount
super(Transaction, self).save(*args, **kwargs)
def __str__(self):
return str(self.pk)+','+self.currency + ', '+str(self.amount)
def get_absolute_url(self):
return reverse('transaction-detail', kwargs = {'pk': self.pk})
@property
def coin_value(self):
try:
current_price = requests.get("https://min-api.cryptocompare.com/data/price?fsym = "+self.currency+"&tsyms=EUR")
price = json.loads(current_price.content)
return price["EUR"]
except:
return 0
@property
def total_value(self):
value = self.coin_value * self.amount
return round(value, 2)
@property
def profit_loss(self):
value = float(self.total_value) - float(self.total_price)
return round(value, 2)
@property
def profit_loss_percent(self):
value = ((float(self.total_value) - float(self.total_price))/self.total_value)*100
return round(value, 1)
таблица, которую я добавляю ниже
{% for transaction in transactions %}
<tr>
<td>{{transaction.currency}}</td>
<td>{{transaction.amount}}</td>
<td>{{transaction.amount_per_coin}}</td>
<td>{{transaction.total_price}}</td>
<td>{{transaction.coin_value}}</td>
<td>{{transaction.total_value}}</td>
<td>{{transaction.date_purchased|date:"j N Y"}}</td>
<td>{{transaction.profit_loss}}</td>
<td>{{transaction.profit_loss_percent}} %</td>
<td><a href = "{% url 'transaction-detail' transaction.id %}">View</a></td>
</tr>
{% endfor %}






Сетевые подключения к другой службе всегда будут относительно медленными. Итак, что вы хотите сделать, так это найти способы избежать слишком большого количества таких запросов.
Распространенным методом является кэширование результатов на некоторое время. Даже короткий кэш на несколько секунд может очень помочь, если вы обрабатываете множество транзакций, в которых используется небольшое количество валют. Прямо сейчас вы делаете новый запрос для каждого свойства, к которому вы обращаетесь, поэтому рендеринг вашей таблицы вызывает четыре запроса показана строка транзакции.
У Django уже есть поддержка кэширования данных; следующее будет использовать кеш, настроенный в CACHES = {..., 'currencies': {...},}, если он существует, но в противном случае использует конфигурацию 'default'. Настройка выделенной конфигурации кеша позволяет вам устанавливать такие вещи, как тайм-аут только для данных валюты.
Если у вас есть ключ Cryptocompare API, установите его в CRYPTOCOMPARE_API_KEY в вашем settings.py файле:
import requests
from django.conf import settings
from django.core.cache import caches, InvalidCacheBackendError
APIURL = 'https://min-api.cryptocompare.com/data/price'
class CurrencyPrices:
def __init__(self):
self.session = requests.Session() # re-use connections
api_key = getattr(settings, 'CRYPTOCOMPARE_API_KEY', None)
if api_key is not None:
self.session.headers['Authorization'] = f'Apikey {api_key}'
try:
self.cache = caches['currencies']
self.key_prefix = ''
except InvalidCacheBackendError:
self.cache = caches['default']
self.key_prefix = 'currency_cache_'
def get_currency_price(self, currency):
key = f'{self.key_prefix}{currency}'
value = self.cache.get(key)
if value is None:
params = {"fsym": currency, "tsyms": "EUR"}
response = self.session.get(APIURL, params=params)
value = response.json()['EUR']
self.cache.set(key, value)
return value
_currency_prices = CurrencyPrices() # single instance per process
get_currency_price = _currency_prices.get_currency_price
затем импортируйте get_currency_price и используйте его, чтобы получить свои значения:
@property
def coin_value(self):
return get_currency_price(self.currency)
Вот пример конфигурации кеша, который кэширует ответы в локальной памяти на 10 секунд:
CACHES = {
'currencies': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
'LOCATION': 'currencies',
'TIMEOUT': 10,
}
}
Проверьте, что такое могут потребоваться другие настройки.