Django Шаблон: Динамическая переменная шаблона внутри другой переменной
Надеюсь, это имеет смысл... Я создаю страницу списка криптоактивов (легко); однако, в цикле {% for %} я хотел бы включить переменную внутри переменной. Если показать код, это будет иметь больше смысла:
Tempalte.html
{% for crypto_asset in objects__list_cryptoAssets %}
<tr role="row" class="body-row">
<td role="cell">{{ api_external_prices.bitcoin.usd }}</td>
</tr>
{% endfor %}
Итак, цикл {% for %} захватывает все криптоактивы, а затем я могу использовать шаблон Django {{ asset_class.slug }} для захвата всех slug... ничего исключительного здесь нет. Эта переменная {{ api_external_prices.bitcoin.usd }} захватывает внешние долларовые цены на биткойн, {{ api_external_prices.bitcoin.eur }} цены в евро и так далее... здесь тоже нет ничего исключительного
Вот где возникает вопрос: идея состоит в том, чтобы иметь что-то вроде {{ api_external_prices.{{ asset_class.slug }}.usd }}... таким образом, каждая криптовалюта будет иметь свою собственную цену FX, полученную правильно. Возможно ли иметь переменную внутри переменной?
Есть несколько способов, которыми вы можете это реализовать:
Фильтры шаблона
Вы можете создать шаблонный фильтр api_external_prices
, который принимает asset_class
и тип криптовалюты в качестве параметров и возвращает значение.
Синтаксис будет выглядеть следующим образом, где api_external_prices
- имя фильтра шаблонов:
{{ asset_class|api_external_prices:"usd" }}
Для получения дополнительной информации об этой функции смотрите здесь: https://docs.djangoproject.com/en/4.0/howto/custom-template-tags/#writing-custom-template-filters
Методы
Другим подходом было бы иметь api_external_prices
в качестве метода на вашем объекте asset_class
, который возвращает объект, имеющий свойство usd
. api_external_prices
здесь может быть просто оберткой, вызывающей центральный модуль/функцию, но это значительно упростит использование в шаблонах.
{{ asset_class.api_external_prices.usd }}
Первый подход похож на то, о чем вы спрашиваете, но лично я предпочел бы использовать второй подход, потому что он избавляет вас от внедрения фильтра шаблонов.
Надеюсь, это поможет вам понять, как реализовать метод 2 из вашего ответа выше.
Views.py
@login_required(login_url='xxx', redirect_field_name = '')
@require_http_methods(["GET", "POST"])
def view_cryptoAsset_list(request, *args, **kwargs):
template_name = 'xxx'
if request.user.is_authenticated and request.user.allow_private_access and request.user.is_superuser:
if request.method == 'GET':
context = {}
objects__list_cryptoAssets = CryptoAsset.objects.all()
objects__list_foreignExchange = ForeignExchange.objects.all()
context = get_crypto_asset_list(objects__list_cryptoAssets, context)
context = get_real_time_prices(objects__list_cryptoAssets, objects__list_foreignExchange, context)
return render(request, template_name, context)
else:
return HttpResponseRedirect(reverse('page__error_404'))
else:
return HttpResponseRedirect(reverse('page__home'))
Utils.py
def get_crypto_asset_list(objects__list_cryptoAssets, context):
if objects__list_cryptoAssets.count() > 0:
extra_context = { 'xxx': xxx,
'xxx': xxx,
'xxx': xxx,
'xxx': xxx}
else:
extra_context = { 'xxx': xxx,
'xxx': xxx,
'xxx': xxx}
context.update(extra_context)
return context
def get_real_time_prices(objects__list_cryptoAssets, objects__list_foreignExchange, context):
raw_crypto = objects__list_cryptoAssets.values('slug_name')
dict_crypto = []
for value in raw_crypto.values():
raw_slugs = value.get('slug_name')
dict_crypto.append(raw_slugs)
stringCrypto = ",".join(dict_crypto)
raw_foreign_exchange = objects__list_foreignExchange.values('slug')
dict_fx = []
for value in raw_foreign_exchange.values():
raw_slugs = value.get('slug')
dict_fx.append(raw_slugs)
stringFX = ",".join(dict_fx)
url = "xxx"
response = urllib.request.urlopen(url)
api_external_prices = json.loads(response.read())
extra_context = {'api_external_prices': api_external_prices}
context.update(extra_context)
return context
В соответствии с просьбой я добавил весь код сюда.
Models.py
from django.db import models
from django.utils.text import slugify
class CryptoAsset(models.Model):
is_active = models.BooleanField(default=True)
name = models.CharField(max_length=128, blank=False)
slug_name = models.SlugField(max_length=128, null=True, blank=True)
ticker = models.CharField(max_length=8, blank=False, unique=True)
slug_ticker = models.SlugField(max_length=16, null=True, blank=True)
image = models.URLField(max_length=512, blank=False)
scan_blockchain = models.URLField(max_length=512, blank=False)
date_created = models.DateTimeField(auto_now_add=True)
date_modified = models.DateTimeField(auto_now=True)
def save(self, *args, **kwargs):
self.slug_name = slugify(self.name)
self.slug_ticker = slugify(self.ticker)
self.ticker = self.ticker.upper()
super(CryptoAsset, self).save(*args, **kwargs)
class Meta:
ordering = ['slug_name', 'slug_ticker']
class ForeignExchange(models.Model):
is_active = models.BooleanField(default=True)
name = models.CharField(max_length=128, blank=False)
ticker = models.CharField(max_length=8, blank=False, unique=True)
slug = models.SlugField(max_length=128, null=True, blank=True)
def save(self, *args, **kwargs):
self.ticker = self.ticker.upper()
self.slug = slugify(self.ticker)
super(ForeignExchange, self).save(*args, **kwargs)
class Meta:
ordering = ['slug']
Views.py
@login_required(login_url='xxx', redirect_field_name = '')
@require_http_methods(["GET", "POST"])
def view_cryptoAsset_list(request, *args, **kwargs):
template_name = 'xxx'
if request.user.is_authenticated and request.user.allow_private_access and request.user.is_superuser:
if request.method == 'GET':
context = {}
objects__list_cryptoAssets = CryptoAsset.objects.all()
objects__list_foreignExchange = ForeignExchange.objects.all()
context = get_crypto_asset_list(objects__list_cryptoAssets, context)
context = get_real_time_prices(objects__list_cryptoAssets, objects__list_foreignExchange, context)
return render(request, template_name, context)
else:
return HttpResponseRedirect(reverse('page__error_404'))
else:
return HttpResponseRedirect(reverse('page__home'))
Utils.py
def get_crypto_asset_list(objects__list_cryptoAssets, context):
if objects__list_cryptoAssets.count() > 0:
extra_context = { 'total_crypto_assets': objects__list_cryptoAssets.count(),
'objects__list_cryptoAssets': objects__list_cryptoAssets,
'json_textGlobal': static_textGlobal,
'json_textLanguage': static_textLanguage}
else:
extra_context = { 'total_crypto_assets': 0,
'json_textGlobal': static_textGlobal,
'json_textLanguage': static_textLanguage}
context.update(extra_context)
return context
def get_real_time_prices(objects__list_cryptoAssets, objects__list_foreignExchange, context):
raw_crypto = objects__list_cryptoAssets.values('slug_name')
print(raw_crypto)
dict_crypto = []
for value in raw_crypto.values():
raw_slugs = value.get('slug_name')
dict_crypto.append(raw_slugs)
print(dict_crypto)
stringCrypto = ",".join(dict_crypto)
print(stringCrypto)
raw_foreign_exchange = objects__list_foreignExchange.values('slug')
print(raw_foreign_exchange)
dict_fx = []
for value in raw_foreign_exchange.values():
raw_slugs = value.get('slug')
dict_fx.append(raw_slugs)
print(dict_fx)
stringFX = ",".join(dict_fx)
print(stringFX)
url = "https://api.xxxxxxx.com/api/price?ids="+ stringCrypto +"&vs_currencies="+ stringFX +""
response = urllib.request.urlopen(url)
api_external_prices = json.loads(response.read())
print(api_external_prices)
extra_context = {'api_external_prices': api_external_prices}
context.update(extra_context)
return context
Итак, из Utils.py upated, если мы поставим несколько prints() для bitcoin & ethereum и usd & eur, они генерируют следующее...
>>> print(raw_crypto) :: <QuerySet [{'slug_name': 'bitcoin'}, {'slug_name': 'ethereum'}]>
>>> print(dict_crypto) :: ['bitcoin', 'ethereum']
>>> print(stringCrypto) :: bitcoin,ethereum
>>> print(raw_foreign_exchange) :: <QuerySet [{'slug': 'eur'}, {'slug': 'usd'}]>
>>> print(dict_fx) :: ['eur', 'usd']
>>> print(stringFX) :: eur,usd
>>> print(api_external_prices) :: {'ethereum': {'eur': 1399.75, 'usd': 1472.54}, 'bitcoin': {'eur': 26240, 'usd': 27604}}
Tempalte.html
{% for crypto_asset in objects__list_cryptoAssets %}
<tr role="row" class="body-row">
<td role="cell">{{ api_external_prices.bitcoin.usd }}</td>
</tr>
{% endfor %}
В шаблоне, если я сделаю {{ api_external_prices.bitcoin.usd }} я получу USD цену биткоина в долларах; однако, внутри цикла мне нужно, чтобы часть биткоина была динамической... поможет ли все это?